res.json is not sending my error message to the client? - javascript

I have this error handler that retreives specific error messages based on what happens. But the thing is when I run my error handler function with .catch() it will work if i'm logging to the node console, but when i try send it to the client via res.json() it will only send the status code, not any part of my error handler.
function errorHandler(error){
if (error.name === 'SequelizeValidationError') {
const errors = error.errors.map(err => err.message);
return errors;
} else {
throw error;
}
}
router.post('/create', async(req, res) => {
await Movie.create(req.body)
.then(() => res.json("Movie Created"))
.catch( err => res.status(401).json(errorHandler(err)) );
});
This is my code for the error handler and the route i'm talking about. It works in the node console, but like I said it only sends the status 401 code to the client and nothing else. How can I get my error message send to the client as well?
Thank you!

Because its not waiting for result from errorHandler. Make them wait for it.
Try this.
function errorHandler(error, cb){
if (error.name === 'SequelizeValidationError') {
const errors = error.errors.map(err => err.message);
cb(errors);
} else {
throw error;
}
}
router.post('/create', async(req, res) => {
await Movie.create(req.body)
.then(() => res.json("Movie Created"))
.catch( err => {
errorHandler(err, function(errors){
res.status(401).json(errors);
});
});
})
Or you can return a Promise and await on errorHandler.

Related

Can anyone explain why my program is not showing the correct alert?

I have written this function which allows users to add images to the server. However, my alerts don't seem to be working. I've tried to console.log the alert messages instead of having them as alerts but that doesn't seem to work either. Any tips would be great.
client.js
async function picsub(event){
event.preventDefault();
var image=document.getElementById('imageFile');
const formData = new FormData();;
formData.append('image',image.files[0]);
let i={
method:'POST',
body:formData,
}
fetch('http://127.0.0.1:8090/pics', i).then((response) => {
return response.text();
}).then((response) => {
if (response === 'success') {
alert('pic added');
} else {
alert('An error has occurred');
}
}).catch((e) => {
alert('An error has occurred');
form.reset();
}
const form = document.getElementById("form");
form.addEventListener("submit", picsub);
server.js
const app = express();
const port = 8090;
let pictures=[];
app.post('/pics', (req, res) => {
const pic = req.body;
console.log(pic);
pictures.push(pic);
res.status(201);
});
In your express, you only setup the status, but you didn't send any message from server. So, your then or catch in fetch will be executed.
then will be executed when you receive the response from server.
catch will be executed when you have failed connection between client and server.
In your case, you didn't send any response from server, fetch function will wait for response until timeout. But, you didn't setup any timeout. That means there are no response from server or any failed connection. So, your then or catch in fetch will not be executed. Unless, you shut down the server. But, browser will help you setup the default timeout, such as Chrome. It use 300 seconds as timeout.
So, you need to send message with res.end("success") like below.
app.get('/pics', function (req, res) {
const pic = req.body;
console.log(pic);
pictures.push(pic);
res.status(201).end("success");
})
And in your client.js, you should complete the bracket in the fetch function.
fetch('http://127.0.0.1:8090/pics', i).then((response) => {
return response.text();
}).then((response) => {
if (response === 'success') {
alert('pic added');
} else {
alert('An error has occurred');
}
}).catch((e) => {
alert('An error has occurred');
}) // ===> here
Try not using async here. Also, try console.log() some things within the function, especially near the alert(). This way, you know it even gets to the alert()

Mongoose and multiple save error handling

I'm using mongoose + express to build a simple MERN app.
I need to create multiple documents and save them, but I need to catch all errors.
I'm using this code and it works, but I'd like to handle all errors at once, not repeat the same code multiple times.
If I use try...catch block and remove the callback error handler, I obtain UnhandledPromiseRejectionWarning.
model.save((err, doc) => {
if (err) return console.error(`ERR ${err.message}`);
});
I've tried this:
export const init = async () => {
try {
const newDoc = new MyModel({ test: 'test'});
const savedDoc = await newDoc.save();
console.log('All done :)');
} catch (err) {
console.log('Error');
res.status(400).send(err);
}
}
But I can't catch the error: in debug mode, the program never enter the catch block and I obtain, in case of error for example:
UnhandledPromiseRejectionWarning: MongoError: E11000 duplicate key error collection
Any suggestion?
model.save()
.then(success => {
if(!success) {
// Handle your error
}
// Success
return model2.save();
})
.then(success2 => {
})
// etc..
.catch(err => {
// Handle your error
});
try{
const savedModel = await model.save();
console.log("Model created successfully");
res.status(200).send("Model created successfully");
}catch (err){
console.log(err);
res.status(400).send(err);
}

How to catch a Typeorm transaction error in NestJs

I have a server side written in node.js and nestJs, querying with typeorm.
I'm trying to wrap some query's to the database with transaction as suggested here with some changes inspired by typeorm's docs, like this:
getManager().transaction(async transactionalEntityManager => {
transactionalEntityManager.save<Entity>(newEntity)
transactionalEntityManager.save<Entity1>(newEntity1)
});
The transaction works well and rollback the database if there was an error.
tested this way:
getManager().transaction(async transactionalEntityManager => {
transactionalEntityManager.save<Entity>(newEntity)
throw 'There is an error'
transactionalEntityManager.save<Entity1>(newEntity1)
});
The execution of the transaction is inside a graphQL Mutation, so I should return an error to the client if something went wrong, the problem is that I can't catch the errors from the transaction.
Tried doing this:
#Mutation(returns => Entity)
async create(): Promise<Entity> {
let entity = null;
let error = null;
getManager().transaction(async transactionalEntityManager => {
try {
entity = await transactionalEntityManager.save<Entity>(newEntity)
await transactionalEntityManager.save<Entity1>(newEntity1);
} catch (err) {
error = err
}
})
if (error) {
return error
}
return entity
}
when I throw error I catch it successfully, but when a real error occurs I can console.log() it in the server but it never reaches to return to the client.
You are not awaiting your transaction to finish thus, the exception can be thrown after your function call end and you don't get the exception.
Just await your transaction and it should be fine.
await getManager().transaction(async transactionalEntityManager => {
...
throw 'ERROR THAT SHOULD BE CATCHED'
}
Also it returns the result of the inner function so it can be useful.
const ok = await getManager().transaction(async transactionalEntityManager => {
await transactionalEntityManager.save<Entity>(newEntity)
await transactionalEntityManager.save<Entity>(newEntity2)
return 'OK'
}

How catch error in the front-end from response of expressjs?

My problem is the next:
//express server
app.post('/register', (req, res) => {
const {
password,
passwordConfirm
} = req.body;
if (password === passwordConfirm) {
//...
} else {
res.status(400).json("Passwords aren't matching")
}
})
//react function
onSubmitSignIn = () => {
const { password, passwordConfirm } = this.state;
let data = new FormData();
data.append('password', password);
data.append('passwordConfirm', passwordConfirm);
fetch('http://localhost:3001/register', {
method: 'post',
body: data
})
.then(response => response.json())
.then(user => {
//logs error message here
console.log(user)
})
//but I want to catch it here, and set the message to the state
.catch(alert => this.setState({alert}))
}
When I send the status code, and the message from express as the response, the front-end obviously recognize it as the response, that's why it logs the message to the console as "user". But how to send error which goes to the catch function?
fetch will really only error if it for some reason can't reason the API. In other words it will error on network errors. It will not explicitly error for non 2XX status codes.
You need to check the ok property as described here:
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful
https://developer.mozilla.org/en-US/docs/Web/API/Response/ok
--
fetch('http://localhost:3001/register', {
method: 'post',
body: data
})
.then(response => {
if (!response.ok) {
throw new Error('my api returned an error')
}
return response.json()
})
.then(user => {
console.log(user)
})
.catch(alert => this.setState({alert}))
The problem is, that fetch is not recognizing the HTTP errors as Promise rejections.
The Promise returned from fetch() won't reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally, and it will only reject on network failure or if anything prevented the request from completing.
(Source)
You can checkout the linked source of the fetch repo which also states a suggestion for handling HTTP error statuses.
What if you throw an error :
app.get("/", function (req, res) {
throw new Error("BROKEN"); // Express will catch this on its own.
});
And then catch this error in the front end ?
See here for reference
EDIT
Maybe should you return the error with return next() so that the rest of the code is not processed in the server method :
app.get("/", function (req, res) {
return next(new Error('BROKEN'));
});
//express server
app.post('/register', (req, res) => {
try {
const {
password,
passwordConfirm
} = req.body;
if (password === passwordConfirm) {
//...
} else {
res.status(400).json("Passwords aren't matching")
}
} catch (error) {
res.status(500).send(error);
}
})
//react function
onSubmitSignIn = () => {
const {
password,
passwordConfirm
} = this.state;
let data = new FormData();
data.append('password', password);
data.append('passwordConfirm', passwordConfirm);
fetch('http://localhost:3001/register', {
method: 'post',
body: data
})
.then(response => response.json())
.then(user => {
//logs error message here
console.log(user)
})
//but I want to catch it here, and set the message to the state
.catch(alert => this.setState({
alert
}))
}

How to set default rejected promise behavior for all my Express middlewares?

I'm using promises inside express middleware. I want to use the async/await methods.
app.get('/data1',async function(req,res) {
data = await getData1(); // This line throw an error,
res.send(data)
})
app.get('/data2',async function(req,res) {
data = await getData2(); // This line throw an error
res.send(data)
})
This makes the browser wait forever.
On the server I see
(node:251960) UnhandledPromiseRejectionWarning: Unhandled promise rejection
Now, to fix it for one middleware I'm doing:
app.get('/data1',async function (req,res){
return (async function(){
data = await getData1()
})().catch(() => {
res.send("You have an error")
}
})
app.get('/data2',async function (req,res){
return (async function(){
data = await getData2()
})().catch(() => {
res.send("You have an error")
}
})
I don't like this repetion. How can I set default error? I have tried for example:
app.use(function(error,req,res,next)){
res.send('You have an error')
}
But it didn't work.
In other words: How to set default function to be called when Express middlewares returning a rejected promise?
Now I found a way how to do it, I'm still keep the question open for more suggestions
app.get("/data1",
wrap_middleware(async (req, res) => {
data1=await getData1()
res.send(data1)
})
}
app.get("/data1",
wrap_middleware(async (req, res) => {
data2=await getData2()
})
}
function wrap_middleware(func) {
return async (req, res, next) => {
func(req, res, next).catch(err => {
console.log(err.message);
res.send("Error");
});
};
}
I don't understand the use of sending the same error for different function but I think the handling error code could be write in more readable way (just catch the error and do with them what you want the same way you catch errors in any route middleware):
function getData1(){
return new Promise( (resolve,reject) => {
setTimeout(() =>{
reject(new Error('error has occur!'));
},2000);
});
}
router.get('/data1', async (req,res, next) => {
try{
const data = await getData1();
res.send(data);
}
catch(ex){
res.send(ex.message);
// next(ex); => sending it to express to handle it
}
});
If you want a global error handling then its not any different from any code you want catch errors globally - you can set a function that take as param , the response object and the async code and create general catch for every async call comes from middleware (which has response object)

Categories