I'm validating user input and result in express and am returning 422 if the input is invalid and a 400 if result is empty. The problem is that I can't log the response object when an error occurs.
Nodejs:
if (q === '' || q.length < 3 || q.length > 150) {
console.log('invalid query');
return res.sendStatus(422).send('Search not found');
} else {
try {
// Fetch redis data
const data = await GET_ASYNC('data');
// stuff here
// Result Validation
if (!Array.isArray(data) || !data.length) {
res.status(400).send('Search not found');
} else {
// do stuff
res.status(200).send(data);
}
} catch (err) {
console.error(err);
res.sendStatus(500); // Server error
}
Now my react code:
const searchDb = useCallback(async() => {
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
try {
axios.get(`/api/bestProduct?q=${searchValue}`,
{ cancelToken: source.token })
.then(res => {
console.log(res) // nothing shows up
const data = res.data;
setData(data)
});
} catch (err) {
if (axios.isCancel(err)) {
console.log(err.response); // nothing shows up
} else {
console.log('hello??') // nothing
return setError(`There's been a problem on our end.`)
}
}
}, [])
I've looked at other solution and tried to log the res and res.status but nothing shows up. This is what my console looks like during the error:
Related
I am a webdev student trying to create an Ecommerce -API with Node and Express JS connected with MongoDB but I am getting this return in postman : "Product is not defined" in my Non_Admin Checkout function.
I don't really know what my mistakes are. Can you help me?
Here are my codes:
UserController
module.exports.checkout = async (data) => {
try{
let is_user_updated = await User.findById(data.userId).then((user) => {
user.orders.push({productId: data.productId})
return user.save().then((updated_user, error) => {
if(error){
return false
}
return true
})
})
}catch(err){return err.message}
try{
let is_product_updated = await Product.findById(data.productId).then((product) => {
product.orders.push({userId:data.userId})
return ordered.save().then((updated_product, error) => {
if(error){
return false
}
return true
})
})
}catch(err){return err.message}
if(is_user_updated && is_product_updated){
return {
message: 'User checkout is successful!'
}
}
return {
message: 'Something went wrong.'
}
}
I am creating a loop to create/update users using functions with built-in promises:
for (const user of usersjson.users) {
let getuser = getUser(url, okapikey, user[fieldMap.externalSystemId],
'externalSystemId'); //Check if user exists on the server
await getuser
.then(async (data) => {
if (data.users.length != 0) { //If user exists in the array
update = updateUser(url, okapikey, createduser, data.users[0].id);//Create update function
promises.push(update); //Store function in array
i++;
} else {
create = createNewUser(url, okapikey, createduser);//Create create function
promises.push(create); //Store function in array
i++;
}
}).catch((err) => {
console.error(err);
});
if (promises.length == 50 || i == usersjson.users.length) {//Run functions in batches of 50
await Promise.allSettled(promises)
.then((responses)=> {
for (const response of responses) { //For each promise response
if (response.status == 'fulfilled') { //If fulfilled
if (response.value.status == 204) {
console.log(`${response.value.status}: User ${response.value.request.path.substring(7)} was updated.`);
} else {
if (response.value.status == 201 && response.value.headers.location) {
console.log(`${response.value.status}: User ${response.value.headers['location']} was created.`);
} else {
console.log(response.value.headers.location);
}
}
} else { //Handle rejections
console.log(`There was an error with the user:${response.value}`);
}
}
}).catch((err)=> {
console.log(err);
});
promises=[]; //Empty Promise array
}
}
async function updateUser(url, token, user, userid)
{
return new Promise((resolve, reject) => {
//Create headers for put request
const options = {
method: "put",
headers: {
'x-okapi-token': token,
'x-okapi-tenant':'tenant',
'Content-type':"application/json"
}
};
//Make API get call
user.id=userid; //Adding the required field ID to the JSON
axios.put(`${url}/users/${userid}`, JSON.stringify(user), options)
.then(response => {
if (response.status == 204) {
resolve(response);
} else {
reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
}
}).catch((err) => {
console.error(`Error Code: ${err.response.status}`);
if (typeof err.response.data == 'string') {
console.error(err.response.data);
reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
} else if (err.response.data.errors[0].message) {
console.error(`Error Text: ${err.response.data.errors[0].message}`);
reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
} else {
reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
}
console.log(err.response);
});
});
};
async function createNewUser (url, token, user) {
return new Promise((resolve, reject) => {
//Create headers for put request
const options = {
headers: {
'X-Okapi-token': token,
'Content-type':"application/json"
}
};
//Make API get call
axios.post(`${url}/users`, JSON.stringify(user), options)
.then(response => {
if (response.status == 201) {
resolve(response);
} else {
reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Text: ${err.response.data.errors[0].message},\nError Status: ${err}`)
}
}).catch((err) => {
console.error(`Error on ${user.externalSystemId}: ${err}`);
if (err.response.data && typeof err.response.data == 'string') {
console.error(err.response.data);
reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Text: ${err.response.data.errors[0].message},\nError Status: ${err}`)
} else if (err.response.data.errors[0].message) {
console.error(`Error Text: ${err.response.data.errors[0].message}`);
reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Text: ${err.response.data.errors[0].message},\nError Status: ${err}`)
} else {
reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Text: ${err.response.data.errors[0].message},\nError Status: ${err}`)
}
});
});
};
const getUsers = (url,user,password) =>
{
return new Promise((resolve, reject) => {
//Create headers for POST request
const options = {
method: 'post',
headers: {
'Authorization': 'Basic '+Buffer.from(`${user}:${password}`).toString('base64')
}
}
//Make API get call
axios.get(url, options)
.then(response => {
resolve(response.data);
}).catch((err) => {
console.error(err);
reject(err);
});
});
};
The code and loop works fine when every promise is fulfilled, but once a promise is rejected, the loop breaks. I get the error message, for example:
Error on XXX: Error: Request failed with status code 422 Error Text:
User with this username already exists
node:internal/process/promises:246
triggerUncaughtException(err, true /* fromPromise */);
^
[UnhandledPromiseRejection: 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(). The promise rejected with
the reason "Error Code: 422: XXX, Error Text: User with this username
already exists, Error Status: Error: Request failed with status code
422".] { }
Looking at the code and error, I believe this comes from the "createNewUser" function.
I'm not sure why the code breaks - I added catches to all the functions, handled rejections, and added catch statements in the main body of the code, but the loop still breaks.
What I need is for the loop to continue as usual even if one function fails (I will later change the log from console.log to an actual log file).
update = updateUser(url, okapikey, createduser, data.users[0].id);//Create update function
promises.push(update); //Store function in array
create = createNewUser(url, okapikey, createduser);//Create create function
promises.push(create); //Store function in array
This is inaccurate. You are not storing functions in that array, you actually call the updateUser/createNewUser functions here and store the resulting promises in the array. Then, your loop goes on to sequentially (because of the await) do more getUser operations before actually calling Promise.allSettled on the promises array. In the meantime, some of the promises might already have been rejected without having any handlers attached to them.
This is basically the same problem as discussed in Waiting for more than one concurrent await operation and Any difference between await Promise.all() and multiple await?.
To fix it, collect actual functions that you can execute later in your array:
let functions = [];
for (const user of usersjson.users) {
i++;
try {
const data = await getUser(url, okapikey, user[fieldMap.externalSystemId], 'externalSystemId');
if (data.users.length != 0) {
functions.push(() =>
// ^^^^^
updateUser(url, okapikey, createduser, data.users[0].id)
); // Create update function and store it in array
} else {
functions.push(() =>
// ^^^^^
createNewUser(url, okapikey, createduser)
); // Create create function and store it in array
}
} catch(err) {
console.error(err);
}
if (functions.length == 50 || i == usersjson.users.length) { // in batches of 50
const promises = functions.map(fn => fn()); // Run functions
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
const responses = await Promise.allSettled(promises);
for (const response of responses) {
if (response.status == 'fulfilled') {
if (response.value.status == 204) {
console.log(`${response.value.status}: User ${response.value.request.path.substring(7)} was updated.`);
} else {
if (response.value.status == 201 && response.value.headers.location) {
console.log(`${response.value.status}: User ${response.value.headers['location']} was created.`);
} else {
console.log(response.value.headers.location);
}
}
} else {
console.log(`There was an error with the user:${response.value}`);
}
}
functions = []; // empty functions array
}
}
(I've tried to avoid awaiting any .then(…) chains)
I'm trying to develop an API post, in middle execution I have validation such as check name already in use or not. I set error handler callback, it successfully send response 'Already registered', but when I checked to CLI, it show error
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I dont know whats wrong, I use this error handler in the past and it seems look ok.
Here is my code in router:
createUserAccount: async function (req, res) {
const programData = req.body;
try {
await service.create(programData, function (code, err, result) {
if (err) {
if(code === 409){
res.status(HTTPSTATUS.CONFLICT).send(err.message);
} else {
res.status(HTTPSTATUS.BAD_REQUEST).send(err.message);
}
} else {
res.status(HTTPSTATUS.CREATED).json(result);
}
})
} catch (e) {
console.log(e)
res.status(HTTPSTATUS.BAD_REQUEST).json("Failed.");
}
Here is my function in my service:
const config = require('#configs/config.json')
const sequelize = require('sequelize');
const SEQUELIZE = new sequelize(config[env]);
module.exports = {
createAccount: async (name, password, callback) => {
try {
let check,
institution_id;
const checkName = await Profile.count(
{
where: {
name: name
}
}
);
//result checkName = 1
if(checkName > 0){
//then successfully execute this condition and
return callback(409, 'Already registered.', null);
//this show in console ----> POST /API/v1/user/profile 409 616.152 ms - 31
}
await Login.create({
username: email,
password: password
}).then(resLogin => {
const response = {
id: resLogin.id,
}
callback(201, null, response);
}).catch( error => {
callback(400, error, null);
})
} catch (e) {
callback(400, e, null);
}
},
create: async (payload, callback) => {
let loginID = null;
let {
profile,
address
} = payload;
let {
name,
email,
password
} = profile;
try {
await module.exports.createAccount(name, password, function (code, error, result) {
if(error){
const res = {message: error};
//what I need is the execution is end in here
return callback(code, res, null);
}
loginID = result.id;
});
//but the fact is it still execute this whole function if got callback error from createAccount()
let transaction = await SEQUELIZE.transaction();
await Address.create(address, {transaction})
.then( async resAddress => {
await transaction.commit();
return callback(201, null, resProfile);
}).catch(async e => {
return callback(400, e, null);
})
} catch (e) {
console.log(e);
callback(e, null);
}
};
I am sending an HTTP request from angular to a node/express API. How do I get the actual error message I send from the node/express API
I am handling my exceptions well when they are thrown in the API but the moment I try to read the message in Angular I only get the name of the type of error I throw. For example, if I throw a 409 the error received by angular is just "Conflict" and does not contain the details I send. Please look at my code below.
I am sending my request as below
register(user: UserAccount) {
return this.http
.post(`${config.apiUrl}/users/register`, user)
.pipe(
map((res: HttpResponse<Response>) => {
return res;
}))
.pipe(catchError(err => this.errorHandler.handleError(err)));
}
My handle error is as below:
handleError(error: HttpErrorResponse) {
console.log(error);
if (error) {
let errMessage = '';
try {
errMessage = error.message;
} catch (error) {
errMessage = error.statusText;
}
return throwError(errMessage || error || 'Server error');
}
return throwError(error.error || error || 'Server error');
}
This how I am throwing my error when I occurs in my Node/Express API
registerUser (req, res) {
debug(chalk.blue(`*** insert user`))
userRepo
.create(req.body)
.then(user => {
debug(chalk.green(`*** Insert User ok!`))
res.status(200).json({
status: true,
error: null,
user: user
})
})
.catch(err => {
debug(chalk.red(`*** insertUser error: ${util.inspect(err)}`))
if (err['type'] && err['type'] === '409') {
res.status(409).json({
status: false,
error: err['message'],
user: null
})
} else {
res.status(400).json({
status: false,
error: err,
user: null
})
}
})
}
I want to be able to receive the json object with the information about the error but all I am getting when I access the error item is, for example, in the case of raising a 409, I only get 'Conflict'
The response data in case of error is inside the error property of HttpErrorResponse. So you may need to modify the handleError method as below.
handleError(error: HttpErrorResponse) {
console.log(error);
if (error) {
let errMessage = '';
try {
// error.error holds the json response sent from API.
errMessage = JSON.stringify(error.error);
} catch (error) {
errMessage = error.statusText;
}
return throwError(errMessage || error || 'Server error');
}
return throwError(error.error || error || 'Server error');
}
Server-side express code
registerUser(req, res) {
debug(chalk.blue(`*** insert user`))
userRepo
.create(req.body)
.then(user => {
/**
* SUCCESS TO-DO
* .
* .
* .
* .
*/
return res.send(200).json(user)
})
.catch(err => {
/**
* error handler in server
* FAILURE TO-DO
* .
* .
* .
*/
if (err['type'] && err['type'] === '409') {
res.status(409).json({
status: false,
error: 'some 409 type error',
user: null
})
} else {
res.status(400).json({
status: false,
error: 'some 400 type error',
user: null
})
}
})
}
Your angular code
handleError(error: HttpErrorResponse) {
console.log(error);
if (error) {
let errMessage = '';
try {
errMessage = error.message; // <- here is the problem
} catch (error) {
errMessage = error.statusText;
}
return throwError(errMessage || error || 'Server error');
}
return throwError(error.error || error || 'Server error');
}
Firstly, if I may rename your HttpErrorResponse object as http_error as it is too generic. However, the trick lies in reading from the error key of the http_error object, and not from the message key.
Client-side error handler(angular)
handleError(http_error: HttpErrorResponse) {
// {status: false, error: 'some 409/400 type error', user: null }
const errMessage = http_error.error;
/* TO-DO STUFF */
return throwError(errMessage || 'Server error');
}
I'm trying to make my Server side part to handle the errors from my 'Controllers' class to my 'Routes' class so i can show them in the Postman.
I think i should work with Promises but i don't get the way they works.
This is the code in my Controller Class,
async validatingWithDB(email: string, password: string) {
await this.client.connect(async () => {
try {
let saltKey = await this.client.query(
"SELECT salt FROM userinfo WHERE email=$1", [email]);
if (saltKey.rowCount == 1) {
let hashedLoginPassword = this.saltingValidation(password, saltKey.rows[0].salt).hash;
let result = await this.client.query(
'SELECT id FROM userinfo WHERE email=$1 AND password=$2', [email, hashedLoginPassword]);
if (result.rowCount > 1 || result.rowCount < 1) {
throw Error("Wrong or non existing user !");
} else {
console.log("Succes Login !");
}
} else {
throw Error("Wrong or non existing user !");
}
} catch (err) {
console.error(err.message);
}
});
};
}
//this is in Routes Class
app.route('/login')
.post(async (req: Request, res: Response) => {
try {
if (req.body.email !== 0) {
if (req.body.password !== 0) {
await
this.authenticationService.validatingWithDB(req.body.email,
req.body.password)
res.status(200).send(new Result(
true, { Message: 'Login Successfully !'
}
));
} else {
throw new Error("Password too short");
}
} else {
throw new Error("Email is too short");
}
} catch {
res.status(400).send(new Result(
false, { Message: 'Bad request, Please try again' }, ErrorCodes.BadRequest
));
}
})