Handle multer.single('file') error when upload multiple files - javascript

I followed the Multer code:
app.post('/profile', upload.single('avatar'), function (req, res, next) {
})
One single file should be uploaded. But if one tries to upload multiple files, how to catch the error MulterError: Unexpected field?
I have tried below to no success:
app.post('/profile', upload.single('avatar'), function (req, res, next) {
try {
} catch (error) {
// Why cannot catch any error?
}
})

when upload.single executes next() then only it comes here,
app.post('/profile', upload.single('avatar'), function (req, res, next) {
try {
} catch (error) {
// It catches only errors from above `try block`
}
});
If upload.single faces any error it does not call next() instead it gets passed to next listner. To catch any error of upload.single you must add this after above app.post(/profile).
app.use(function (err, req, res, next) {
var error = err.message;
res.status(500);
res.send({ "error": error });
});

Related

How add middleware for 404 errors on express

setting
app.use("/api/tobaccos", tobaccos);
app.use(function(err, req, res, next) {
console.error(err.message);
});
api:
router.get("/:id", async (req, res) => {
console.log("GET TOBACCO:" + req.params.id);
await Tobacco.findById(req.params.id)
.then(tobacco => res.status(200).json({ status: "success", data: tobacco }))
.catch(error => res.status(404).json({
status: "fail",
msg: "Tobacco not found!",
code: "error.tobaccoNotFound"
}));
});
I'm trying to add middleware for all 404 errors
app.use(function(err, req, res, next) {
console.error(err.message);
});
or this doesn't work
app.get('*', function(req, res){
res.status(404).send('what???');
});
What is wrong?
In Express, 404 responses are not the result of an error, so the error-handler middleware will not capture them. This behavior is because a 404 response simply indicates the absence of additional work to do; in other words, Express has executed all middleware functions and routes, and found that none of them responded. All you need to do is add a middleware function at the very bottom of the stack (below all other functions) to handle a 404 response:
app.use(function (req, res, next) {
res.status(404).send("Sorry can't find that!")
})
Add routes dynamically at runtime on an instance of express.Router() so the routes are not superseded by a middleware function.
Reference: https://expressjs.com/en/starter/faq.html
You can add this middleware in your root file. It sends error for any invalid routes.
//Handles 404 errors
app.use((req, res, next) => {
const error = new Error('Error Occured');
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
Alternatively, you can try which captures all 404 errors
app.use(function(req, res, next) {
res.status(404).send( 'Error Occured! ');
});

JS, correct syntax from arrow to normal

Im learning and trying to understand javascript, and in a video im following, the dude used this code
app.post('/content/uploads', (req,res) => {
upload(req, res, (err) => {
console.log(req.file);
res.send('testing');
})
});
now im trying to convert it to normal, i understand that app.post('/content/uploads', (req,res) => {
translates to app.post('/content/uploads', function(req, res){
but when i try to do upload(req, res, (err) => {, i cant.
What i tried is
upload(function(req, res, (err)){
but i get an error in
upload(function(req, res, (err)){
^
SyntaxError: Unexpected token '('
what is the correct way to translate it?
My full failed translation looks like this
app.post('/content/uploads', function(req, res){
upload(function(req, res, (err)){
if(err){
res.render('index', {
msg: err
});
} else {
console.log(req.file);
res.send('test');
}
});
});
Thanks
I suggest you spend some time getting comfortable with the arrow syntax, it's not "abnormal".
In any case, you may find this tool useful: https://babeljs.io/en/repl
You can paste code and select only ES2015 on the left (uncheck the others) and see how it translates the code.
For example, it will output:
app.post('/content/uploads', function (req, res) {
upload(req, res, function (err) {
console.log(req.file);
res.send('testing');
});
});
app.post('/content/uploads', function (req,res) {
upload(req, res, function (err) {
console.log(req.file);
res.send('testing');
})
});
upload(req, res, (err)=>{
//TODO
});
The above code is equivalent to:
var someFunc = (err)=>{
//TODO
};
upload(req, res, someFunc);
So, you can write it with function keyword like this:
upload(req, res, function (err) {
//TODO
});

Express4 error middleware sequence

Came accros a sequence of code execution which I found unusual here is the code:
server.js
const Actions_Single_PVC = require('./routes/Actions_single_PVC.js');
app.use('/Actions_single_PVC', Actions_Single_PVC);
app.use((err, req, res, next) => {
console.log('invalid token');
});
Actions_single_PVC.js
router.post('/', asyncMW(async (req, res, next) => {
throw new Error();
}));
router.use((err, req, res, next) => {
console.log('error');
}
And in case you have never seen this construction before here is asyncMW:
const asyncMiddleware = fn =>
(req, res, next) => {
Promise.resolve(fn(req, res, next))
.catch(next);
};
module.exports = asyncMiddleware;
What I didn't understand was that when an error is thrown (I reproduced it here with throw new Error();) that the error handling middleware in the server.js file is executed. I expected that the error handling middleware of the Actions_single_PVC.js would get executed.
Question:
Why is the error middlware in server.js executed and not the error middlware in Actions_single_PVC.js?
It is because the following code applies middleware to only request with base path matching Actions_single_PVC.
app.use('/Actions_single_PVC', Actions_Single_PVC);
Whereas following code is apply middleware to all global requests.
app.use((err, req, res, next) => {
console.log('invalid token');
});
If you'll hit the url /Actions_single_PVC then the middlewares in Actions_single_PVC will get hit.

Node.js (Express) error handling middleware with router

Here's my application structure:
- app.js
- routes
---- index.js
The ExpressJS app creates error handlers for development and production environments. Here's a code snippet from app.js:
app.use('/', routes); // routing is handled by index.js in the routes folder
//The following middleware are generated when you create the Express App
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error.ejs', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
And inside of routes/index.js, where I handle all the routing:
var router = express.Router();
router.get('/', function (req, res) {
someAsyncFunction(function(err, result) {
if (err) throw err; // Handle this error
}
});
module.exports = router;
I want the err to be passed to one of the error handlers instead of being thrown. How can I do this?
You have to pass it to the next callback which is usually the third parameter in the route handler
var router = express.Router();
router.get('/', function (req, res, next) {
someAsyncFunction(function(err, result) {
if (err) {
next(err); // Handle this error
}
}
});
module.exports = router;
calling next(err) will allow the error to be caught in a middleware down the chain with the following signature:
app.use(function (err, req, res, next){
// do something about the err
});
Reference: http://expressjs.com/en/guide/error-handling.html
You can also create a middleware function to handle error in all routes without copying code everywhere, using arrow functions if you like.
1) Create a const function to handle errors.
either:
const handleErrorAsync = func => (req, res, next) => {
func(req, res, next).catch((error) => next(error));
};
or
const handleErrorAsync = func => async (req, res, next) => {
try {
await func(req, res, next);
} catch (error) {
next(error);
}
};
2) In your router use it for every request:
var router = express.Router();
router.get('/req1', handleErrorAsync(async (req, res, next) => {
let result = await someAsyncFunction1();
if(result){
// res.send whatever
}
}));
router.post('/req2', handleErrorAsync(async (req, res, next) => {
let result = await someAsyncFunction2(req.body.param1);
if(result){
// res.send whatever
}
}));
router.post('/req3', handleErrorAsync(async (req, res, next) => {
let result = await someAsyncFunction3(req.body.param1, req.body.param2);
if(result){
// res.send whatever
}
}));
module.exports = router;
3) In your server main app handle error:
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error.ejs', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
This way you can reuse the error handling function in any route. Also, if there are any unhandled errors in any of your functions, this will catch them as well.
Try catch error handling taken from Here

Catch express bodyParser error

I want to catch the error from the bodyParser() middleware when I send a json object and it is invalid because I want to send a custom response instead of a generic 400 error.
This is what I have and it works:
app.use (express.bodyParser ());
app.use (function (error, req, res, next){
//Catch bodyParser error
if (error.message === "invalid json"){
sendError (res, myCustomErrorMessage);
}else{
next ();
}
});
But this seems to me a very ugly approach because I'm comparing the error message which could change in future express versions. There's any other way to catch bodyParser() errors?
EDIT:
This is the error when the request body has an invalid json:
{
stack: 'Error: invalid json\n at Object.exports.error (<path>/node_modules/express/node_modules/connect/lib/utils.js:55:13)\n at IncomingMessage.<anonymous> (<path>/node_modules/express/node_modules/connect/lib/middleware/json.js:74:71)\n at IncomingMessage.EventEmitter.emit (events.js:92:17)\n at _stream_readable.js:872:14\n at process._tickDomainCallback (node.js:459:13)',
arguments: undefined,
type: undefined,
message: 'invalid json',
status: 400
}
Pretty printed stack:
Error: invalid json
at Object.exports.error (<path>/node_modules/express/node_modules/connect/lib/utils.js:55:13)
at IncomingMessage.<anonymous> (<path>/node_modules/express/node_modules/connect/lib/middleware/json.js:74:71)
at IncomingMessage.EventEmitter.emit (events.js:92:17)
at _stream_readable.js:872:14
at process._tickDomainCallback (node.js:459:13)
I think your best bet is to check for SyntaxError:
app.use(function (error, req, res, next) {
if (error instanceof SyntaxError) {
sendError(res, myCustomErrorMessage);
} else {
next();
}
});
From the answer of #alexander but with an example of usage
app.use((req, res, next) => {
bodyParser.json({
verify: addRawBody,
})(req, res, (err) => {
if (err) {
console.log(err);
res.sendStatus(400);
return;
}
next();
});
});
function addRawBody(req, res, buf, encoding) {
req.rawBody = buf.toString();
}
what I did was just:
app.use(bodyParser.json({ limit: '10mb' }))
// body parser error catcher
app.use((err, req, res, next) => {
if (err) {
res.status(400).send('error parsing data')
} else {
next()
}
})
Ok, found it:
bodyParser() is a convenience function for json(), urlencoded() and multipart(). I just need to call to json(), catch the error and call to urlencoded() and multipart().
bodyParser source
app.use (express.json ());
app.use (function (error, req, res, next){
//Catch json error
sendError (res, myCustomErrorMessage);
});
app.use (express.urlencoded ());
app.use (express.multipart ());
All errors include a type property from 1.18.0 release onwards. For parse failure, err.type === 'entity.parse.failed'.
app.use(function (error, req, res, next) {
if (error.type === 'entity.parse.failed') {
sendError(res, myCustomErrorMessage);
} else {
next();
}
});
I found checking for SyntaxError to be not enough, therefore I do:
if (err instanceof SyntaxError &&
err.status >= 400 && err.status < 500 &&
err.message.indexOf('JSON') !== -1) {
// process filtered exception here
}
create new module "hook-body-parser.js"
hook everything with body parser over here
const bodyParser = require("body-parser");
module.exports = () => {
return [
(req, res, next) => {
bodyParser.json()(req, res, (error) => {
if (error instanceof SyntaxError) {
res.sendStatus(400);
} else {
next();
}
});
},
bodyParser.urlencoded({ extended: true }),
];
};
and use over express like this
...
app.use(hookBodyParser())
...
if you want to catch all errors thrown by body-parsr for example
entity.too.large or encoding.unsupported
just place this middleware right after your body-parser initialization
$ npm i express-body-parser-error-handler
https://www.npmjs.com/package/express-body-parser-error-handler
for example:
const bodyParserErrorHandler = require('express-body-parser-error-handler')
const { urlencoded, json } = require('body-parser')
const express = require('express')
const app = express();
router.route('/').get(function (req, res) {
return res.json({message:"🚀"});
});
// body parser initilization
app.use('/', json({limit: '250'}));
// body parser error handler
app.use(bodyParserErrorHandler());
app.use(router);
...
(bodyParser, req, res) => new Promise((resolve, reject) => {
try {
bodyParser(req, res, err => {
if (err instanceof Error) {
reject(err);
} else {
resolve();
}
});
} catch (e) {
reject(e);
}
})
Bullet-proof. Future-aware. WTFPL-Licensed. And also useful w/ async/await.

Categories

Resources