Last active
January 13, 2018 00:31
-
-
Save scwood/13ce8ba54b5a5851aa69b3d4e2ed2959 to your computer and use it in GitHub Desktop.
async functions, next(error) and why it's neccessary
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Some background: | |
| // Express will handle uncaught exceptions inside of middleware by sending them | |
| // to the default error handler. | |
| app.get('/some/endpoint', (req, res, next) => { | |
| const a = {}; | |
| a.some.fake.prop; | |
| // TypeError: Cannot read property 'prop' of undefined | |
| }); | |
| // When someone hits /some/endpoint, express will send the request to the | |
| // default error handler which sends a 500 and a generic error message. | |
| // This is great, however this falls apart as soon as you introduce | |
| // asynchronous behaviour. Fortunately, we can send errors to the error handler | |
| // manually by calling next(error); | |
| // Let's imagine we try to connect to a database in the endpoint but the server | |
| // doesn't have a connection | |
| app.get('/some/endpoint', (req, res, next) => { | |
| doSomeDatabaseThing((error, result) => { | |
| // Error: can't connect to database! | |
| res.send('success'); | |
| }); | |
| }); | |
| // Express knows nothing about this connection error because it happened in an | |
| // asynchronous context. We have to explicitly check if error exists and if it | |
| // does, we need to send it to the error handler manually | |
| app.get('/some/endpoint', (req, res, next) => { | |
| doSomeDatabaseThing((error, result) => { | |
| if (error) { | |
| next(error); | |
| return; | |
| } | |
| res.send('success'); | |
| }); | |
| }); | |
| // Above is how you would pass errors down while using an error first callback | |
| // style asynchronous function but these principles still apply to promises | |
| app.get('/some/endpoint', (req, res, next) => { | |
| doSomeDatabaseThing() | |
| .then((result) => res.send('success')) | |
| .catch(next); // on caught error, we will call next | |
| // the above is identical to saying .catch((error) => next(error)) | |
| }); | |
| // If an error happens in a promise the only way to send it down to the error | |
| // handler is catch in the .catch block and send it on. | |
| // Likewise with async functions, you need a top level try catch that | |
| // encompasses the whole function. If an error is thrown outside that try-catch | |
| // it will be lost because asynchronous functions return a promise implicitly, | |
| // so it's important that the try-catch wraps the entire function. | |
| app.get('/some/endpoint', async (req, res, next) => { | |
| try { | |
| const result = await doSomeDatabaseThing(); | |
| res.send('success'); | |
| } catch (error) { | |
| next(error); | |
| } | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment