How can I achieve this. In an easy way in ExpressJS?
App.get("/", async (req, res, next) => {
await something.catch(err => {
res.status(500).json("something wrong")
})
if (res.headersSent) return;
res.json("2st response");
});
Can I just call res.json() two time then express automatically understand to end response and not to send second response ? without of using middleware to check that response already send or not!
In your logic here with await, it's easier to just use try/catch instead of .catch() and that makes the flow a lot easier:
App.get("/", async (req, res, next) => {
try {
await something;
} catch(err) {
res.status(500).json("something wrong");
return;
});
res.json("2st response");
});
In general, you don't mix await with .catch() and partly for this reason because using await and try/catch makes code flow like this simpler since you directly return from the outer function in the try/catch(err) statement, but you cannot do that in the .catch() statement.
You can use return before res.send. This way it will send a response and exit the function.
app.get("/", (req, res, next) => {
return res.send("1st responce");
// Unreachable code
if(res.headersSent) return;
res.json("2st responce")
})
Related
I have a problem and I haven't found a solution yet. I want to catch all errors if occur any error in each route but it's very inconvenient when I have to do it many times.
How can i implement it as a middleware same like app.use(ErrorHandle); ?
Code in ErrorHandler.js:
export const ErrorHandler = func => async (req, res, next) => {
try {
await func(req, res, next);
} catch (error) {
next(error);
}
}
Code in index.js
app.use((err, req, res, next) => {
if (err) {
return res.status(err.statusCode || 500).json(err.message);
}
next()
});
Code in route need to catch error:
import { ErrorHandler } from './ErrorHandler';
export const uploadMedia = ErrorHandler(async (req, res) => {
// do something...
let error = new Error();
error.statusCode = 404;
error.message = 'Content not found!';
}
Sorry if misunderstood your question... When you do the code below which you provided, you are assuming that if an error reaches the end of the stack via next(err), such handler should be called. Hence it's the last declaration after all your routes.
app.use((err, req, res, next) => {
if (err) {
return res.status(err.statusCode || 500).json(err.message);
}
next()
});
That, however, won't catch unhandledExceptionErrors. You still need the good old
try {
// throw error somewhere
} catch (e) {
next(e);
}
Personally, I haven't tried this package but it seems so be a nice hack for Express router's inability to handle promise returns. About express-promise-router:
A simple wrapper for Express 4's Router that allows middleware to return promises. This package makes it simpler to write route handlers for Express when dealing with promises by reducing duplicate code.
delete function code
deleteScreen:(screenId)=>{
return new Promise((resolve,reject)=>{
db.get().collection(collection.SCREEN_COLLECTION).removeOne({_id:ObjectID(screenId)}).then((response)=>{
console.log(response)
resolve(response)
})
})
}
http delete route is
router.delete('/delete-screen/:id',services.deleteScreen)
html code is
Delete
The problem is that your router handler actually receives request and request and next, so when you write.
router.delete('/delete-screen/:id',services.deleteScreen)
It means that the function services.deleteScreen will be called in the following way services.deleteScreen(req, res, next); So you need to change the signature of your function.
router.delete('/delete-screen/:id', (req, res) => {
services.deleteScreen(req.params.id)
.then(() => res.end())
.catch((e) => {
res.status = 500; // means internal error;
res.end();
});
})
I'm using Express and I want to use the build-in middlewares to handle errors.
I'm using it this way -
app.use((err,req,res,next)=> {
console.log('error');
)};
Now this middleware is reached only if I'm using next(error) (where error is object of type Error) in my router.
On the other hand, if I simply throw new Error() in my router, the middleware is not called.
Is there any way to omit the next()?
So that if any error is thrown in my router, it will be handled by the middleware?
If you can use Node.js >= 8 that comes with async/await then you can use the following wrapper function over your routes:
const wrap = fn => {
return async function(req, res, next) {
let e = null;
try {
await fn(req, res, next);
} catch (err) {
e = err;
next(err);
}
if (!e) {
next();
}
};
};
app.get(
"/path",
wrap(async (req, res) => {
// use sync style code here which can throw
})
);
If the throw is synchronous, you could invent your own request handler wrapper that would catch any exceptions and turn them into a call to next():
app.get2 = function(path, fn) {
app.get(path, function(req, res, next) {
try {
fn(req, res, next);
} catch(err) {
next(err);
}
});
};
And, sample usage:
app.get2("/test", function(req, res, next) {
throw new Error("testing..."); // will end up in next()
});
Then, if your fn function throws synchronously, then it will be caught by your get2() wrapper and will automatically call next(err) for you.
If you're throwing asynchronously, this won't work. There is no generic wrapper for asynchronous throws because throws into an asynchronous callback don't throw to your code - they throw back into the asynchronous infrastructure for whatever async operation you were using and only they can catch it. If you use promises exclusively for your asynchronous operations, then the promise infrastructure will automatically catch your throws and turn them into rejected promises and you could do something similar to above for a returned and rejected promise. The Koa framework (a derivative of Express) does something similar already and I think Express 5 will have some features like that to.
I'm writing middleware that I'm applying at the route level, like so:
router.get('/foo', myMiddleware, (req, res) => { ... });
so I can do some stuff with the request. But I also need to catch errors to do some special handling. I know I can add a handler afterwards like this:
... (req, res) => { ... }, myErrorHandler);
and it'll get called just fine.
But my question is, is there any way to have a single piece of middleware that can do all of this so I don't need two points of integration? I tried calling req.on('error', (err) => { ... }) within my middleware but it never seems to be called.
Express comes with a built-in error handler that takes care of any errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack.
// Router
router.get('/foo', myMiddleware, (req, res) => { ... });
// Router Error Handler
router.use(function (err, req, res, next) {
});
I ended up solving this by writing a helper function that wraps the actual handler. It looks like this:
function checkPage(handler: express.RequestHandler) {
return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
let _write = res.write;
res.write = chunk => {
if (req.query.verbose) {
return _write.call(res, `<p>${chunk}</p>`);
} else {
return true;
}
}
try {
await handler(req, res, next);
res.write('<hr/><p style="color:green;"><b>happy</b></p>');
} catch (err) {
res.write(`<p style="color:red;">${err}</p>`);
res.write('<hr/><p style="color:red;"><b>SAD!</b></p>')
}
res.end();
}
}
Then in my route handler, I just use it like so:
router.get('/foo', checkPage(async (req, res, next) => {
...
res.write('stuff');
...
}));
When I have a simple function processing the request I can use res.end() and return to end it at any point (some error happened/incorrect data, etc.)
get('/', function (req, res) {
if (!req.param('id')) {
res.send('Must provide ID!');
res.end(); // <-- response is ready, send it to client
return; // <-- request processing stops here, get() finishes
}
// do other stuff
res.send('ok'); // <-- this can never overlap with the previous res.send()
});
However, if there are functions embedded in other functions, return will only quit the last one
get('/', function (req, res) {
validate(req);
// do other stuff
res.send('ok'); // <-- this can cause errors? res was ended already
});
function validate(req, res) {
if (!req.param('id')) {
res.send('Must provide ID!');
res.end(); // <-- send response to client
return; // <-- this one exists only from validate()
}
}
I believe to send the response to client res.end() should be called, but how can I stop further code from processing - i.e. return from all functions?
It is impossible to return from a called function, just use a callback as below:
function validate(req, res, callback) {
if (!req.param('id')) {
res.send('Must provide ID!');
res.end();
} else {
callback();
}
}
get('/', function (req, res) {
validate(req, function () {
res.send('ok');
});
});
You could return true or false in validate function depending on if you had already sent response.
But, it's not node style. Using callbacks is preferred in node.
I know this is an old question but may be helpful for others. You could use res.headersSent like this
get('/', function (req, res) {
validate(req);
// will only be sent if validate hasn't already sent the error message
if(!res.headersSent) {
res.send('ok');
}
});
function validate(req, res) {
if (!req.param('id')) {
res.send('Must provide ID!');
res.end();
}
}