Make dynamic/re-usable method - javascript

I need to use sendMessage in other method.
Like:
SendMessage('abc#expample.com','abc#exapmle.com','subject','body').
I am new to nodejs. Just need some syntax help.
I have tried
SendMessage.makeBody('','','','');
But its giving me error.
TypeError: sendMessage.makeBody is not a function
function sendMessage(auth) {
const raw = makeBody(
'abc#example.com',
'abc#example.com',
'something',
'something');
gmail.users.messages.send({
auth: auth,
userId: 'me',
resource: {
raw: raw
}
}, function(err, response) {
if (err) {
logger.info('The API returned an error: ' + err);
return;
}
logger.info(response);
});
}
module.exports = {
sendMessage
};

function sendMessage(data) {
gmail.users.messages.send({
auth: data.auth,
userId: 'me',
resource: {
raw: data.raw
}
}, function(err, response) {
if (err) {
logger.info('The API returned an error: ' + err);
return;
}
logger.info(response);
});
}
let raw = makeBody('abc#example.com','abc#example.com','something','something');
let data = {raw: raw, auth: auth}
// pass raw and auth both in a object and use it into sendMessage funtion.
sendMessage(data)
module.exports = {
sendMessage
};

Related

How to send file received through api to google drive nodejs

I am new to Nodejs and trying to send file received through multer to google drive. However I am setting
var media = {
mimeType: req.file.mimetype,
body:req.file
};
Which is giving me error as
const index = require('../index.js');
const { google } = require('googleapis');
let drive = google.drive('v3');
const receive = multer();
router.post("/insertNewProduct", auth, receive.single('productUrl'), async (req, res) => {
try {
const data = req.body;
var folderId = '1v3tdYH_GLtCOOxhQ8HXDdRAb-2Jh455_';
let fs = require('fs')
var fileMetadata = {
'name': new Date().toISOString()+req.file.filename,
parents: [folderId]
};
var media = {
mimeType: req.file.mimetype,
body:req.file
};
drive.files.create({
auth: index.jwtClient,
resource: fileMetadata,
publishAuto: true,
media: media,
fields: 'id'
},
async function (err, file) {
if (err) {
// Handle error
console.error(err);
}
else {
console.log('********File create success. File Id: ', file.data.id);
res.status(201).send({
message: "Record Create Successfully",
data: newRows
});
}
}
);
}
}
} catch (e) {
console.log("Inside catch: " + e);
res.status(404).send({
message: e,
data: {}
});
}
});
As I understand the error, how I set the body:req.file is wrong.
Here's how req.file look like.
How can I pass req.file to
var media = {
mimeType: req.file.mimetype,
body:req.file
};
I tried body:req.file.buffer but it didn't work.

Async Function working in Express but not NestJs

I initially created a little express server to run a report and file write function.
var ssrs = require('mssql-ssrs');
var fs = require('fs');
const express = require('express')
const app = express()
const port = 3001
app.get('/', (req, res) => {
reportCreation();
res.send('File Created');
})
app.get('/api', (req, res) => {
reportCreation();
res.json({'File Created': true});
})
app.listen(port, () => {
console.log(`Report Api listening at http://localhost:${port}`)
})
The function reportCreation() is an async function which gets a report from a SSRS. This works fine
async function reportCreation() {
var serverUrl = 'http://reportServerName/ReportServer/ReportExecution2005.asmx';
ssrs.setServerUrl(serverUrl);
var reportPath = '/ApplicationPortalReports/TestReportNew';
var fileType = 'word';
var parameters = { ApplicationId: 3, TrainingCardId: 267, PortalPersonId: 52 }
var auth = {
username: 'USERNAME',
password: 'PASSWORD',
domain: 'dmz'
};
try {
var report = await ssrs.reportExecution.getReportByUrl(reportPath, fileType, parameters, auth)
} catch (error) {
console.log(error);
}
console.log(report);
try {
fs.writeFile('ReportApiTest.doc', report, (err) => {
if (!err) console.log('Data written');
});
} catch (error) {
console.log(error);
}
I have been working a lot with NestJs recently and wanted to use the same function but within a NestJs service.
#Injectable()
export class AppService {
async getReport(): Promise<string> {
const serverUrl = 'http://reportServerName/ReportServer/ReportExecution2005.asmx';
ssrs.setServerUrl(serverUrl);
const reportPath = '/ApplicationPortalReports/TestReportNew';
const fileType = 'word';
// var parameters = {appId: 3, ReportInstanceId: 1 }
const parameters = {ApplicationId: 3, TrainingCardId: 267, PortalPersonId: 52 };
const auth = {
username: 'USERNAME',
password: 'PASSWORD',
domain: 'dmz'
};
try {
var report = await ssrs.reportExecution.getReportByUrl(reportPath, fileType, parameters, auth)
} catch (error) {
console.log(error);
}
console.log(report);
// excel = xlsx
// word = doc
// pdf = pdf
try {
fs.writeFile('ReportApiTest.doc', report, (err) => {
if (!err) { console.log('Data written');
return 'File Written Succesfully'}
});
} catch (error) {
console.log(error);
return 'File Write Error'
}
}
}
As you can see the files are almost identical, but when I run it through NestJs I get an error which looks like a problem with the line
var report = await ssrs.reportExecution.getReportByUrl(reportPath, fileType, parameters, auth)
not awaiting. Why does this work with Express and not NestJS? Below is the error from NestJs
buffer.js:219
throw new ERR_INVALID_ARG_TYPE(
^
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string, Buffer, ArrayBuffer,
Array, or Array-like Object. Received type undefined
at Function.from (buffer.js:219:9)
at new Buffer (buffer.js:179:17)
at Object.createType3Message (C:\Projects\SSRS-report-api\ssrs-report-api\node_modules\httpntlm\ntlm.js:172:19)
at sendType3Message (C:\Projects\SSRS-report-api\ssrs-report-api\node_modules\httpntlm\httpntlm.js:77:23)
at Immediate._onImmediate (C:\Projects\SSRS-report-api\ssrs-report-api\node_modules\httpntlm\httpntlm.js:101:4)
within the mssql-ssrs node package the getReportByURL looks like this
async function getReportByUrl(reportPath, fileType, params, auth) {
try {
var config = {
binary: true, // very important
username: auth.userName,
password: auth.password,
workstation: auth.workstation,
domain: auth.domain,
url: soap.getServerUrl()
+ "?" + (testReportPath(reportPath).replace(/\s/g, '+'))
+ "&rs:Command=Render&rs:Format=" + reportFormat(fileType)
+ formatParamsToUrl(params)
};
} catch (err) { report.errorHandler(err) }
return new Promise((resolve, reject) => {
config.url = encodeURI(config.url);
httpntlm.post(config, function (err, res) {
if (res.statusCode === 500) { reject(res) }
if (err || res.statusCode !== 200) { reject(err) }
else { resolve(res.body) }
})
})
}
Here is the app.controller.ts
#Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
#Get()
getHello(): Promise<string> {
return this.appService.getReport();
}
}
This is not an answer for the question. But after I see your code, I can see an error you will face in future if await ssrs.reportExecution.getReportByUrl(reportPath, fileType, parameters, auth) failed. Actually you see above error because of this.
The way you used the try catch is really bad.
Here's the way I code it.
#Injectable()
export class AppService {
async getReport(): Promise<string> {
const serverUrl = 'http://reportServerName/ReportServer/ReportExecution2005.asmx';
ssrs.setServerUrl(serverUrl);
const reportPath = '/ApplicationPortalReports/TestReportNew';
const fileType = 'word';
// var parameters = {appId: 3, ReportInstanceId: 1 }
const parameters = {ApplicationId: 3, TrainingCardId: 267, PortalPersonId: 52 };
const auth = {
username: 'USERNAME',
password: 'PASSWORD',
domain: 'dmz'
};
const report = await ssrs.reportExecution.getReportByUrl(reportPath, fileType, parameters, auth)
return new Promise(function(resolve, reject) {
fs.writeFile('ReportApiTest.doc', report, , function(err) {
if (err) reject(err);
resolve("File Created");
});
});
}
And in my controller
#POST
async writeFile() {
try {
const res = await this.appService.getReport();
return res;
} catch(err) {
// handle your error
}
}
I had fudged the code in the node_module changing the userName variable to username and had not done the same in the NestJS version. I forgot I had done that so now it is working.

Handling errors in Express.js in service / controller layers

I am writing an application in Express.js with a separate controller layer and a service layer. Here is my current code:
user.service.js
exports.registerUser = async function (email, password) {
const hash = await bcrypt.hash(password, 10);
const countUser = await User.countDocuments({email: email});
if(countUser > 0) {
throw ({ status: 409, code: 'USER_ALREADY_EXISTS', message: 'This e-mail address is already taken.' });
}
const user = new User({
email: email,
password: hash
});
return await user.save();
};
exports.loginUser = async function (email, password) {
const user = await User.findOne({ email: email });
const countUser = await User.countDocuments({email: email});
if(countUser === 0) {
throw ({ status: 404, code: 'USER_NOT_EXISTS', message: 'E-mail address does not exist.' });
}
const validPassword = await bcrypt.compare(password, user.password);
if (validPassword) {
const token = jwt.sign({ email: user.email, userId: user._id }, process.env.JWT_KEY, { expiresIn: "10s" });
return {
token: token,
expiresIn: 3600,
userId: user._id
}
} else {
throw ({ status: 401, code: 'LOGIN_INVALID', message: 'Invalid authentication credentials.' });
}
};
user.controller.js
exports.userRegister = async function (req, res, next) {
try {
const user = await UserService.registerUser(req.body.email, req.body.password);
res.status(201).json({ data: user });
} catch (e) {
if(!e.status) {
res.status(500).json( { error: { code: 'UNKNOWN_ERROR', message: 'An unknown error occurred.' } });
} else {
res.status(e.status).json( { error: { code: e.code, message: e.message } });
}
}
}
exports.userLogin = async function (req, res, next) {
try {
const user = await UserService.loginUser(req.body.email, req.body.password);
res.status(200).json({ data: user });
} catch (e) {
if(!e.status) {
res.status(500).json( { error: { code: 'UNKNOWN_ERROR', message: 'An unknown error occurred.' } });
} else {
res.status(e.status).json( { error: { code: e.code, message: e.message } });
}
}
}
The code works, but requires some corrections. I have a problem with error handling. I want to handle only some errors. If another error has occurred, the 500 Internal Server Error will be returned.
1) Can I use "throw" object from the service layer? Is this a good practice?
2) How to avoid duplication of this code in each controller:
if(!e.status) {
res.status(500).json( { error: { code: 'UNKNOWN_ERROR', message: 'An unknown error occurred.' } });
} else {
res.status(e.status).json( { error: { code: e.code, message: e.message } });
}
3) Does the code require other corrections? I'm just learning Node.js and I want to write the rest of the application well.
Yes, you can throw errors from service layer, it is good practice to catch errors with try/catch block in controller
I handle this with a custom error middleware, just use a next function in a catch block.
catch (e) {
next(e)
}
Example of error middleware (for more info check docs, fill free to move a middleware to file)
app.use(function (err, req, res, next) {
// err is error from next(e) function
// you can do all error processing here, logging, parsing error messages, etc...
res.status(500).send('Something broke!')
})
From my point of view it looks good. If you looking for some best practice and tools, try eslint (with AirBnb config for example) for linting, dotenv for a environment variables management, also check Node.js Best Practice
i want to give you an example:
this code in your controller
findCar(idCar)
} catch (error) {
switch (error.message) {
case ErrorConstants.ELEMENT_NOT_FOUND('LISTING'): {
return {
response: {
message: ErrorMessages.ELEMENT_NOT_FOUND_MESSAGE('LISTING'),
},
statusCode,
}
}
default: {
return {
response: {
message: ErrorMessages.UNKNOWN_ERROR_MESSAGE,
},
statusCode,
}
}
}
}
and this code in your service
findCar: async listingId => {
try {
if (some condition) {
throw new Error(ErrorConstants.ELEMENT_NOT_FOUND('LISTING'))
}
return { ... }
} catch (error) {
console.error(error.message)
throw new Error(ErrorConstants.UNKNOWN_ERROR)
}
},
controller is going to catch the service's errors

Passing callback as function argument

I have a hard time with callback and couldn't figure out if this is actually the right way to pass a callback function as an argument. Please help me out. Below is my code snippet
Service module
jwt.signToken({userName: success.data.username, userId: success.data.userId}, secret, expiresIn, (error, token) => {
if(error) {
console.log('::::::::::Error generating token::::::::');
console.log(error);
next(returnError({message: 'Internal Server Error', status: 500}));
} else {
sendSuccessResponse({data: {token: token, user: {userName: success.data.username, userId: success.data.userId},status: 200}}, response);
}
});
Auth module
const signToken = (payload, secret, expireIn, callback) => {
jwt.sign(payload, secret, {expiresIn: expireIn}, (error, token) => callback(error, token));
};
Thanks in advance
I'm able to successfully execute the code..Reiterating look at the code how I'm handling the callback in service layer
jwt.signToken({userName: success.data.username, userId: success.data.userId}, secret, expiresIn, function(error, token) {
if(error) {
next(returnError({message: 'Internal Server Error', status: 500}));
} else {
sendSuccessResponse({
data: {
token: `${token}`,
user: {
userName: success.data.username,
userId: success.data.userId
}
},
status: 200
},response);
}
});
And my jwt module is
const signToken = (payload, secret, expireIn, callback) => {
jwt.sign(payload, secret, {expiresIn: expireIn}, (error, token) => callback(error, token));
};
This can be a simple demonstration of passing callback implementation (done in one module) to another function (in another module) as a parameter.

Promise returns undefined json in Express post request

I have a promise within a selectRecipientData function that returns some user data from an api.
export async function selectRecipientData({ email }) {
engage.selectRecipientData({
listId: listId,
email: email,
returnContactLists: false,
}, function(err, result) {
if(err) {
console.log(err);
} else {
let recipient = JSON.stringify(result);
// this logs successfully
console.log('Recipient details: ' + recipient );
return recipient;
}
});
}
When I call this function within a post request. The data is logged within the promise but is undefined when returned as per below:
server.post('/api/v1/public/selectrecipientdata', async (req, res) => {
formData = req.body;
let { email } = formData;
if (!email) {
res.json({ error: 'Email is required' });
return;
}
try {
let recipientData = await selectRecipientData({ email });
// why is this undefined?
console.log('This is Undefined: '+ JSON.stringify(recipientData) );
res.json({recipientData});
} catch (err) {
res.json({ error: err.message || err.toString() });
}
});
Anyone tell me why? Thanks
You've written selectRecipientData as a callback style function, but you're calling it as an async/await style. If engage.selectRecipientData returns a promise, you could do something like:
export async function selectRecipientData({email}) {
const result=await engage.selectRecipientData({
listId: listId,
email: email,
returnContactLists: false,
});
const recipient=JSON.stringify(result);
console.log('Recipient details: ' + recipient );
return recipient;
}
Otherwise, to convert it to a promise you could do something like:
export function selectRecipientData({email}) {
return new Promise((resolve,reject)=>{
engage.selectRecipientData({
listId: listId,
email: email,
returnContactLists: false,
}, function(err, result) {
if (err) {
reject(err);
}
else {
let recipient = JSON.stringify(result);
console.log('Recipient details: ' + recipient);
resolve(recipient);
}
});
});
}

Categories

Resources