firebase aync await getting null object in try catch - node.js

I am working on firebase api for realtime database, I am using async await, but it is not working for that i have used try catch in node js, I can see i am getting status 0, so it invokes catch, but in catch i am getting error as null object, can anyone please help me why i am not getting proper error in that ? even my try code is correct still it invokes catch, here i have added my whole code, can anyone please look in my code, and help me to resolve this error ? i am getting this response,
Response :
{"status":0,"data":{}}
API :
export const check_await = functions.https.onRequest(async (req, res) => {
try {
if (req.method === 'POST') {
const body_data = req.body;
const db = admin.database();
const org_id = body_data.company_id;
const highfive_id = body_data.highfive_id;
const ref = db.ref("organizations/" + org_id + "/highfive/" + highfive_id);
const snapshot = await ref.on("value");
const data = snapshot.val();
cors(req, res, () => { return res.send({ 'status': 1, 'data': data, 'msg': 'High five feed record get successfully' }); });
} else {
cors(req, res, () => { return res.send({ 'status': 0, 'msg': "Only POST method is allowed" }); });
}
} catch (error) {
cors(req, res, () => { return res.send({ 'status': 0, 'data': error }); });
}
});

Finally i resolved the issue, i need to use once instead of on, here is my full code of it,
export const check_await = functions.https.onRequest(async (req, res) => {
try {
if (req.method === 'POST') {
const body_data = req.body;
const db = admin.database();
const org_id = body_data.company_id;
const highfive_id = body_data.highfive_id;
const ref = db.ref("organizations/" + org_id + "/highfive/" + highfive_id);
const snapshot = await ref.once("value");
const data = snapshot.val();
cors(req, res, () => { return res.send({ 'status': 1, 'data': data, 'msg': 'High five feed record get successfully' }); });
} else {
cors(req, res, () => { return res.send({ 'status': 0, 'msg': "Only POST method is allowed" }); });
}
} catch (error) {
cors(req, res, () => { return res.send({ 'status': 0, 'data': error.message }); });
}
});

Related

SyntaxError: await is only valid in async function in nodeJs

I have created the following function that makes a call to a third party API to create an order and on the response iam calling model function that checks if a user with the user ID exits or not and some operation is done accordingly.
createOrder: async function (req, res, next) {
let formData = req.body;
razorPayInstance.instance.orders.create({
amount: formData.amount * 100,
currency: "INR",
payment_capture: 1
})
.then(response => {
let planSubscription = await PlanSubscription.findOne({ user_id:formData.user_id });
if(planSubscription) {
// do something
} else {
// do something
}
return res.status(200).json(res.fnSuccess(response));
})
.catch(error => {
console.log(error);
});
}
Iam getting the following error in node console :
let planSubscription = await PlanSubscription.findOne({ user_id:formData.user_id });
^^^^^
SyntaxError: await is only valid in async function
Can anybody please point out what is wrong here
You can't await some expression inside a function which is not async. Just use async function inside then.See more about await here
createOrder: async function (req, res, next) {
let formData = req.body;
razorPayInstance.instance.orders.create({
amount: formData.amount * 100,
currency: "INR",
payment_capture: 1
})
.then(async(response) => { //change here
let planSubscription = await PlanSubscription.findOne({ user_id:formData.user_id });
if(planSubscription) {
// do something
} else {
// do something
}
return res.status(200).json(res.fnSuccess(response));
})
.catch(error => {
console.log(error);
});
}

How to test if a function was called in my express controller function

Testing newbie, learning the ropes.
I'm trying to test my error handler controller. After a few hours, I have managed to get it working but need some feedback on the implementation.
Something feels wrong when I start changing the NODE_ENV but I'm not sure how to get around it.
I've written tests separate tests for sendErrorDev and sendErrorProd, so here I just need to test to see if they were called?
errorController.js:
const AppError = require('../utils/appError');
const handleValidationErrorDB = err => {
const errors = Object.values(err.errors).map(el => el.message);
const message = `Invalid input data. ${errors.join('. ')}`;
return new AppError(message, 400);
};
const sendErrorDev = (err, req, res) => {
return res.status(err.statusCode).json({
status: err.status,
error: err,
message: err.message,
stack: err.stack
});
};
const sendErrorProd = (err, req, res) => {
if (err.isOperational) {
return res.status(err.statusCode).json({
status: err.status,
message: err.message
});
}
return res.status(500).json({
status: 'error',
message: 'Something went very wrong!'
});
};
const handleGlobalErrors = (err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
if (process.env.NODE_ENV === 'development') {
helpers.sendErrorDev(err, req, res);
} else if (process.env.NODE_ENV === 'production') {
let error = { ...err };
error.message = err.message;
if (error.name === 'ValidationError')
error = helpers.handleValidationErrorDB(error);
helpers.sendErrorProd(error, req, res);
}
};
const helpers = {
sendErrorDev,
sendErrorProd,
handleGlobalErrors,
handleValidationErrorDB
};
module.exports = helpers;
errorController.test.js:
const { mockRequest, mockResponse } = require('../express-mocks');
const AppError = require('../../src/utils/appError');
const errorController = require('../../src/controllers/errorController');
describe('errorController', () => {
describe('handleGlobalErrors', () => {
let req;
let res;
let newError;
beforeEach(() => {
req = mockRequest();
res = mockResponse();
newError = new AppError('Some error', 500);
});
afterEach(() => {
process.env.NODE_ENV = 'test';
});
it('should call sendErrorDev in development', () => {
process.env.NODE_ENV = 'development';
const spy = jest
.spyOn(errorController, 'sendErrorDev')
.mockImplementation(jest.fn());
errorController.handleGlobalErrors(newError, req, res);
expect(spy).toHaveBeenCalled();
spy.mockRestore();
});
it('should call sendErrorProd in production', () => {
process.env.NODE_ENV = 'production';
const spy = jest
.spyOn(errorController, 'sendErrorProd')
.mockImplementation(jest.fn());
errorController.handleGlobalErrors(newError, req, res);
expect(spy).toHaveBeenCalled();
spy.mockRestore();
});
});
});
You are passing null as the first parameter to .call which is supposed to be the object you want to invoke the function as a method of. Try removing the .call and just invoke it as:
errorController.handleGlobalErrors(newError, req, res);

How to use sinon for middleware testing in nodejs?

Trying to test failure scenario for the middleware , v1TransformResponse will throw error on some validation now in unit testing i am not able to get expected result , any idea what is implemented wrong in below test ? i have added the error i am getting.
server.js
app.post('/cvs/v1/drugprice/:membershipId', orchestrateDrugPrice, v1TransformResponse);
v1TransformResponse.js
module.exports = async (req, res) => {
try {
const validateResponse = responseHandler(req.drugPriceResponse);
const transformedResponse = transformResponse(validateResponse);
const filterDrug = filteredResponse(transformedResponse);
logDrugPriceResponse('TRANSFORMED_RESPONSE V1', filterDrug);
res.status(200).send({ drugPrice: filterDrug });
} catch (error) {
if (error instanceof AppError) {
res.status(error.response.status).send(error.response.payload);
} else {
res.status(500).send(defaultErrorResponse);
}
}
};
main.test.js
const { expect } = require('chai');
const sinon = require('sinon');
const { spy, stub } = require('sinon');
const request = require('supertest');
const app = require('./../../../server/server');
const v1TransformResponse = require('./../../../server/middleware/v1TransformResponse');
const orchestrateDrugPrice = require('./../../../server/middleware/orchestrateDrugPrice');
describe('v1Transform()', () => {
let status,
send,
res;
beforeEach(() => {
status = stub();
send = spy();
res = { send, status };
status.returns(res);
});
describe('if called with a request that doesn\'t have an example query', () => {
const req = {
drugPriceResponse: [{
'brand': false,
'drugName': 'Acitretin',
'drugStrength': '10mg',
'drugForm': 'Capsule',
'retailPrice': {
'copayEmployer': '0',
'costAnnual': '3',
'costEmployer': '733.84',
'costToday': 'N/A',
'daysSupply': '30',
'deductible': 'n/a',
'memberCopayAmount': '30',
'NDC11': '378702093',
'penalties': 'N/A',
'totalDrugCost': '763.84'
}
}]
};
beforeEach(() => (req, res));
it('should return error if prices are ommitted', async () => {
try {
await v1TransformResponse(req, res);
} catch (error) {
expect(error.response).to.deep.equal({
httpStatus: 500,
payload: {
status: 500,
title: 'Internal Server Error',
detail: 'Drug prices are not valid'
}
});
}
});
});
});
ERROR:
if called with a request that doesn't have an example query
should return error if prices are ommitted:
AssertionError: expected undefined to deeply equal { Object (httpStatus, payload) }
The middleware v1TransformResponse doesn't throw errors in failure case. It calls res.status method. You need to check the parameter passed to it.
it('should return error if prices are ommitted', async () => {
await v1TransformResponse(req, res);
expect(res.status.getCall[0].args[0]).to.equal(500);
});

How to response data after create data "model.save()" in MongoDB?

I try the response model after create data but it doesn't work. It shows data on "console.log" and it didn't respond when I use "resolve({})".
In the routers.js:
const register = require('./functions/register');
module.exports = router => {
router.get('/', (req, res) => res.end('Welcome to Idol Fan With your Idol !'));
//======REGISTER & LOGIN WITH SOCIAL =====
router.post('/socialuser', (req, res) => {
const social_id = req.body.social_id;
const token = req.body.token;
const name = req.body.name;
const email = req.body.email;
const photoprofile = req.body.photoprofile;
const tokenfirebase = req.body.tokenfirebase;
if (!social_id) {
res.status(400).json({message: 'Invalid Request !'});
} else {
register.registerUser(social_id, name, email, photoprofile, token, tokenfirebase)
.then(result => {
res.status(result.status).json({status: result.status, message: result.message, user: result.user})
})
.catch(err => res.status(err.status).json({message: err.message}));
}
});
}
Function Register.js:
const userfan = require('../models/user');
exports.registerUser = (social_id, name, email, photoprofile, token,
tokenfirebase) =>
new Promise((resolve, reject) => {
const d = new Date();
const timeStamp = d.getTime();
userfan.find({social_id: social_id})
.then(users => {
if (users.length == 0) {
let newUser = new userfan({
social_id: social_id,
name: name,
email: email,
photoprofile: photoprofile,
token: token,
tokenfirebase: tokenfirebase,
created_at: timeStamp
});
newUser.save()
.then(doc => {
console.log("run... " + doc);
resolve({
status: 200,
message: 'User Register Sucessfully !',
user: doc
});
})
.catch(err => {
console.error(err)
if (err.code == 11000) {
reject({status: 409, message: 'User Already Registered !'});
} else {
reject({status: 500, message: 'Internal Server Error !'});
}
});
} else {
return users[0];
}
})
.then(usertemp => resolve({status: 200, message: "Login Successfully !", user: usertemp}))
.catch(err => {
console.log(err.message);
reject({status: 500, message: err.message});
});
});
This is my result after run on server:
As a result and code above. I have a question Why "user: doc" no response?. Thank you so much!
userfan.find.then.then (synchronous since nothing requires waiting) is called before newUser.save.then (asynchronous since under the hood it waits for the DB to answer).
So both resolve are called, but only the first call is considered, and the first one to be called is the one using usertemp. And this one receives undefined as argument, because of the implicit return undefined at the end of userfan.find.then.
Your flow should be:
userfan.find().then(users => {
if (!users.length) {
let newUser = ...
// explicitly return the promise, which will give the created user
return newUser.save().then(doc => {
// format and return the value you want
return {user: doc, message: 'registered'};
});
} else {
// another explicitly returned value, but you already have this
return {user: users[0], message: 'login'};
}
// it's not possible here because we returned before it, but your code reached this point
// and, implicitly, any function ending with no return does:
return undefined;
// this .then receives *either* the promise from newUser.save *or* the object from the else block
}).then(structure => {
structure.status = 200;
return structure; // here structure is {status: 200, message: 'registered'|'login', user: document}
});
Also, note that using the syntax shortcut (without curly braces around the function body) for arrow functions implies the one-line body is returned:
singleArgument => doSomething();
// is actually *strictly* equivalent to
(singleArgument) => { return doSomething(); }
With these ways of writing, it's easy to lose the reflex of writing return when it's needed.

Promise only resolves on the first request

I am developing an API to create a warehouse structure. Because we are using a microservice architecture I need to make a request via rabbitmq to another microservice to generate the address for the new warehouse.
Therefore I use the ampq consume function wrapped in a function which returns a promise. When I hit the endpoint the first time the promise gets resolved and I can continue with my data. But in the second request, the promise will not get resolved.
Maybe it's for an obvious reason but at the moment I don't get it.
So here is my code:
routes.js
router.post('/', (req, res) => {
...
const validate = ajv.compile(warehoseSchema);
const valid = validate(req.body);
if (valid) {
sendToQueue('addressMgmt', req.body.address);
consume()
.then((result) => {
const {
id_address: idAddress,
license_plate: licensePlate,
town,
} = result.body;
createWarehouseHandler(
customernumber, req.body, idAddress, licensePlate, town,
)
.then((insertId) => {
res.json({
id: 'warehouses02',
message: `Warehouse with id ${insertId} successfully created`,
});
})
.catch((err) => {
res.status(err.status).json({
id: err.id,
message: err.message || err.sqlMessage,
});
});
}).catch((err) => {
res.status(err.status).json({
id: err.id,
message: err.message || err.sqlMessage,
});
});
} else {
res.status(417).json({
id: 'warehouses01',
message: `Invalid JSON: ${ajv.errorsText(validate.errors)}`,
});
}
});
const consume = () => new Promise((resolve, reject) => {
const q = 'warehouseMgmt';
amqpCh.consume(q, (msg) => {
const message = JSON.parse(msg.content.toString());
if (Object.keys(message).includes('body')) {
resolve(message);
} else {
const err = new Error();
err.status = 500;
err.id = 'rabbit01';
err.message = 'No message was cosumed';
reject(err);
}
}, { noAck: true });
});
On the first request consume().then() gets called but on the second and following requests, it doesn't.
Thanks for your help

Resources