I am using firebase cloud functions and I want to validate my api request call on postman. On wrong input it must send a error response back to my postman.
api call
const validator = require('./libs/validators');
export const createUser = functions.https.onRequest((req, res) => {
// #ts-ignore
// ts-lint:disable-next-line
corsHandler(req, res, async () => {
const validData = validateData(req.body);
res.send(validData);
try {
const user = await admin.auth().createUser({ email: validData.email, password: validData.password });
await admin.auth().setCustomUserClaims(user.uid, { isAdmin: false, isSubscribed: false });
await admin.firestore().collection('users').doc(user.uid).set(
{ validData }, { merge: true }
);
res.send(user);
} catch (e: any) {
throw (res.status(400).send(e.message));
}
});
});
function validateData(body: any) {
if (body === undefined) {
throw Error("Invalid data");
}
return validator.newStudentValidator(body);
}
validators.ts
export const newStudentValidator = function (body: any) {
try {
if (body.name === null) {
throw new Error('name is required');
}
if (!body.email.match(/^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)) {
throw new Error("Invalid email");
}
if (body.password === undefined) {
throw new Error("Password is undefined");
}
if (body.university === undefined) {
throw new Error("University is undefined");
}
if (body.sem === undefined) {
throw new Error("Semister is undefined");
}
}
catch (e: any) {
throw new Error(e.message);
}
const allowed = ['name', 'email', 'password', 'university', 'sem'];
const filtered = Object.keys(body).filter(key => allowed.includes(key)).reduce((obj: any, key) => {
obj[key] = body[key];
return obj;
}, {});
return filtered;
}
i get this error everytime enter image description here
I am writing mysql query with transaction but its not waiting to be completed and returns the result even before the function has executed.
Can someone please help me to know how to make function to wait for response?
The calling function is something like this:
deductUserPoint = await helper.deductUserPoint2(data)
console.log('===============================================')
console.log(deductUserPoint)
if (deductUserPoint.isError === true) {
let error = {}
error.isError = true
error.message = 'Unable to deduct amount'
error.error = deductUserPoint.error
res.status(200).json(error)
} else {
res.status(200).json({ 'isError': false, 'message': 'success' })
}
I always get deductUserPoint as undefined because it does not wait for deductUserPoint2 to return response
The deductUserPoint2 is as follows:
async deductUserPoint2(params) {
try {
this.db.connection.getConnection(function(err, conn) {
console.log('1111111111')
conn.beginTransaction(function(err) {
if (err) {
throw err
}
console.log(params)
console.log('2222222222')
conn.query('SELECT id, `expert_id`, user_id, status FROM `call` WHERE `id` = ?', [params.callId], function (error, callInfo, fields) {
if (error) {
return conn.rollback(function() {
throw error
})
}
console.log('33333333')
let callLength = null
if (params.callMinute === 'entire_day') {
callLength = 'entire_day'
} else {
const callMinutes = Math.round(params.callMinute)
if (callMinutes <= 30) {
callLength = '30_min'
} else if (callMinutes >= 31 && callMinutes <= 60) {
callLength = '60_min'
} else if (callMinutes >= 61 && callMinutes <= 90) {
callLength = '90_min'
} else if (callMinutes >= 91) {
callLength = '120_min'
}
}
console.log('4444444444')
conn.query('SELECT `amount` FROM `expert_charges` WHERE `status` = "active" AND `call_length` = ? AND `expert_id` = ?', [callLength, callInfo[0].expert_id], function (error, points, fields) {
if (error) {
return conn.rollback(function() {
throw error
})
}
console.log('555555555555')
let data = {
fromUserId: callInfo[0].user_id,
fromUserType: 'user',
to_user_id: 0,
to_user_type: null,
category: 'call',
type: 'debited',
callId: params.callId,
amount: points[0].amount,
note: params.note,
point: points[0].amount,
current_balance_point: 0
}
let input = Object.values(data)
conn.query('INSERT INTO wallet (`from_user_id`, `from_user_type`, `to_user_id`, `to_user_type`, `category`, `type`, `call_id`, `amount`, `note`, `point`, `current_balance_point`) VALUES ?', [[input]], function (error, wallet, fields) {
if (error) {
return conn.rollback(function() {
throw error
})
}
console.log('666666666666')
conn.query('UPDATE user SET total_points = total_points - ? WHERE id = ?', [points[0].amount, callInfo[0].user_id], function (error, updateUserPoint, fields) {
if (error) {
return conn.rollback(function() {
throw error
})
}
console.log('7777777777')
conn.commit(function(err) {
if (err) {
return conn.rollback(function() {
throw err
})
}
console.log('888888888')
return {
"isError": false,
"status": "success"
}
})
})
})
})
})
})
})
} catch (error) {
console.log(error)
return {
"isError": true,
"error": error.toString()
}
}
Error it prints is :
undefined
(node:4197) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'isError' of undefined
at router.post (/Users/msmexmac/node/msmex-backend/msmex-api/api/wallet.js:120:23)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:4197) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:4197) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
1111111111
{ callId: 5, note: 'Deduction for call', callMinute: 25 }
2222222222
33333333
4444444444
555555555555
666666666666
7777777777
888888888
You can't use async functions like that, you have to return a promise to be able to wait for your callbacks. Your function would have to end up like this:
function deductUserPoint2(params) {
return new Promise(function (resolve, reject) {
try {
this.db.connection.getConnection(function (err, conn) {
console.log('1111111111')
conn.beginTransaction(function (err) {
if (err) {
return reject(err)
}
console.log(params)
console.log('2222222222')
conn.query('SELECT id, `expert_id`, user_id, status FROM `call` WHERE `id` = ?', [params.callId], function (error, callInfo, fields) {
if (error) {
return conn.rollback(function () {
return reject(error)
})
}
console.log('33333333')
let callLength = null
if (params.callMinute === 'entire_day') {
callLength = 'entire_day'
} else {
const callMinutes = Math.round(params.callMinute)
if (callMinutes <= 30) {
callLength = '30_min'
} else if (callMinutes >= 31 && callMinutes <= 60) {
callLength = '60_min'
} else if (callMinutes >= 61 && callMinutes <= 90) {
callLength = '90_min'
} else if (callMinutes >= 91) {
callLength = '120_min'
}
}
console.log('4444444444')
conn.query('SELECT `amount` FROM `expert_charges` WHERE `status` = "active" AND `call_length` = ? AND `expert_id` = ?', [callLength, callInfo[0].expert_id], function (error, points, fields) {
if (error) {
return conn.rollback(function () {
return reject(error)
})
}
console.log('555555555555')
let data = {
fromUserId: callInfo[0].user_id,
fromUserType: 'user',
to_user_id: 0,
to_user_type: null,
category: 'call',
type: 'debited',
callId: params.callId,
amount: points[0].amount,
note: params.note,
point: points[0].amount,
current_balance_point: 0
}
let input = Object.values(data)
conn.query('INSERT INTO wallet (`from_user_id`, `from_user_type`, `to_user_id`, `to_user_type`, `category`, `type`, `call_id`, `amount`, `note`, `point`, `current_balance_point`) VALUES ?', [[input]], function (error, wallet, fields) {
if (error) {
return conn.rollback(function () {
return reject(error)
})
}
console.log('666666666666')
conn.query('UPDATE user SET total_points = total_points - ? WHERE id = ?', [points[0].amount, callInfo[0].user_id], function (error, updateUserPoint, fields) {
if (error) {
return conn.rollback(function () {
return reject(error)
})
}
console.log('7777777777')
conn.commit(function (err) {
if (err) {
return conn.rollback(function () {
return reject(err)
})
}
console.log('888888888')
return resolve({
"isError": false,
"status": "success"
})
})
})
})
})
})
})
})
} catch (error) {
console.log(error)
return resolve({
"isError": true,
"error": error.toString()
})
}
})
}
Then you use reject(err) instead of throw err and resolve(value) instead of return value.
Another approach is using utils.promisify as #georg suggested.
trying to test nodejs module.export function that will return based on request but it throws below error any idea what is implemented wrong here its expecting error >
v1Transform.js
module.exports = async (req, res) => {
try {
const validateResponse = responseHandler(req.drugPriceResponse);
} catch (error) {
if (error instanceof AppError) {
res.status(error.response.status).send(error.response.payload);
} else {
res.status(500).send(defaultErrorResponse);
}
}
}
main.test.js
describe('v1Transform()', () => {
it('should return error if accounts are ommitted', () => {
try {
v1Transform(req);
} catch (error) {
expect(error.response).to.deep.equal({
status: 500,
payload: {
'status': 500,
'title': 'Internal Server Error',
'detail': 'Accounts are not valid'
}
});
}
});
});
Error
1) v1Transform()
should return error if prices are ommitted:
AssertionError: expected undefined to deeply equal { Object (status, payload) }
I need to store firebase authentication token as a user in react native asyncstorage. here is my code.
loginUser = async (email, pw) => {
if (this.state.isConnected) {
if (email != '' && pw != '') {
try {
let user = fb.auth().signInWithEmailAndPassword(email, pw).catch((err) => {
alert('Invalid email or password');
});
this.storeUser(JSON.stringify(user))
console.log(user);
} catch (error) {
console.log(error);
}
}
}
}
storeUser = async (user) => {
try {
await AsyncStorage.setItem('User', JSON.stringify(user)).then(() => {
console.log("Success user");
})
} catch (e) {
console.log(e);
}
}
but it gives me this error
TypeError: Converting circular structure to JSON
at JSON.stringify (<anonymous>)
can anyone help me with this?
There is an incorrect usage of the signInWithEmailAndPassword(email, pw) function call, the firebase.auth.signInWithEmailAndPassword() function returns a Promise<UserCredential> object which will error out when you call JSON.stringify() on it.
The returned UserCredential object needs to be retrieved from the Promise by using the then() method of the Promise class. See below:
try {
fb.auth().signInWithEmailAndPassword(email, pw).then(function(userCred) => {
this.storeUser(userCred);
console.log(JSON.stringify(userCred)); // so you can see a JSON string in the logs
}).catch((err) => {
alert('Invalid email or password');
});
}
Disclaimer: As the entire function is not shown, play with the above
From Above Code the mistake is converting two times
await AsyncStorage.setItem('User', user).then(() => {
Updated Code :
loginUser = async (email, pw) => {
if (this.state.isConnected) {
if (email != '' && pw != '') {
try {
let user = fb.auth().signInWithEmailAndPassword(email, pw).catch((err) => {
alert('Invalid email or password');
});
this.storeUser(JSON.stringify(user))
console.log(user);
} catch (error) {
console.log(error);
}
}
}
}
storeUser = async (user) => {
try {
await AsyncStorage.setItem('User', user).then(() => {
console.log("Success user");
})
} catch (e) {
console.log(e);
}
}
I have this code with callbacks:
function getUserToken(data, callback) {
var password_sha256 = sha256(data.password);
getAppById(data.app_id).then(function(res) {
console.log("app"+res);
if (!res) {
console.log("No app");
callback(err, { meta: {
code: 403,
error_message: "There are no app with your id!"
} });
} else {
if (res.user_password == password_sha256) {
console.log("user found");
callback(err, { meta: { code: 200 },
token: password_sha256,
type: 1 });
return;
} else if (res.owner_password == password_sha256) {
console.log("owner found");
callback(err, { meta: { code: 200 },
token: password_sha256,
type: 0 });
} else {
console.log("user not found");
callback(err, { meta: {
code: 403,
error_message: "There are no users with your password!"
} });
}
}
});
}
I post some data using this function:
router.post('/api/login', (req, res) => {
db.getUserToken(req.body, function(err, result) {
console.log(result);
if (result.error) {
return res.status(403).send(result);
} else {
return res.status(200).send(result);
}
});
});
And then getUserToken found, for example, user, so I have "user found" in console log, but callback function in /api/login not working. Where is my error and how can I fix them?
Instead of callback, you can return a Promise, either native or using an external library like Kris Kowal Q
var Q = require('q');
function getUserToken(data) {
var deferred = Q.defer();
var password_sha256 = sha256(data.password);
getAppById(data.app_id).then(function(res) {
if (!res) {
deferred.reject("There are no app with your id!");
} else {
if (res.user_password == password_sha256) {
deferred.resolve({
token: password_sha256,
type: 1
});
} else if (res.owner_password == password_sha256) {
deferred.resolve({
token: password_sha256,
type: 0
});
} else {
console.log("user not found");
deferred.reject("There are no users with your password!");
}
}
})
.catch(function(error) {
deferred.reject(error);
});
return deferred.promise;
}
Then simply process or catch error when you post data
router.post('/api/login', (req, res) => {
db.getUserToken(req.body)
.then(function(result) {
res.status(200).send(result);
})
.catch(function(error) {
res.status(403).send(error);
});
});
Instead of using callback(err, data) you should use callback(null,data).This will give you required output.