Skip to content

Commit

Permalink
adding documentation around using promises in middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
ryhinchey committed Apr 5, 2020
1 parent cbdf829 commit 0389f61
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 3 deletions.
43 changes: 43 additions & 0 deletions en/guide/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,49 @@ app.get('/', function (req, res, next) {
})
```

Starting with Express 5, route handlers and middleware that return a Promise will call
`next(value)` automatically when they reject or throw an error. For example:

```js
app.get('/user/:id', function (req, res, next) {
return getUserById(req.params.id).then(function (user) {
res.send(user)
})
})
```

If `getUserById` throws an error or rejects, `next` will be called with either the thrown error or the rejected value.
If no rejected value is provided, `next` will be called with the string `Rejected promise`.

If you want to handle the error before passing it along to `next`, you can use a try/catch block (for functions using async/await) or add a `.catch` to your Promise (or an onRejected callback to `.then`). For example:

```js
app.get('/user/:id', function (req, res, next) {
return getUserById(req.params.id)
.then(function (user) {
res.send(user)
})
.catch(function (error) {
// handle the error
next(error)
})
})
```

With async/await:

```js
app.get('/user/:id', async function (req, res, next) {
try {
var user = await getUserById(req.params.id)
res.send(user)
} catch (error) {
// handle the error
next(error)
}
})
```

If you pass anything to the `next()` function (except the string `'route'`), Express regards the current request as being an error and will skip any remaining non-error handling routing and middleware functions.

If the callback in a sequence provides no data, only errors, you can simplify this code as follows:
Expand Down
84 changes: 81 additions & 3 deletions en/guide/writing-middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ The following figure shows the elements of a middleware function call:
</td></tr>
</table>

Starting with Express 5, middleware functions that return a Promise will call `next(value)` when they reject or throw an error. `next` will be called with either the rejected value or the thrown Error.

<h2>Example</h2>

Here is an example of a simple "Hello World" Express application.
The remainder of this article will define and add two middleware functions to the application:
one called `myLogger` that prints a simple log message and another called `requestTime` that
displays the timestamp of the HTTP request.
The remainder of this article will define and add three middleware functions to the application:
one called `myLogger` that prints a simple log message, one called `requestTime` that
displays the timestamp of the HTTP request, and one called `validateCookies` that validates incoming cookies.

```js
var express = require('express')
Expand Down Expand Up @@ -140,6 +142,82 @@ app.listen(3000)

When you make a request to the root of the app, the app now displays the timestamp of your request in the browser.

<h3>Middleware function validateCookies</h3>

Finally, we'll create a middleware function that validates incoming cookies and sends a 400 response if cookies are invalid.

Here's a simple function that validates the presence of certain cookies.

```js
function cookieValidator (cookies) {
return new Promise(function (resolve, reject) {
if (!cookies.testCookie) {
reject(new Error('Invalid cookies'))
}

resolve()
})
}
```

Here we use [`cookie-parser`](https://github.com/expressjs/cookie-parser) to parse incoming cookies off the `req` object and pass them to our `cookieValidator` function. The `validateCookies` middleware returns a Promise that upon rejection will automatically trigger our error handler.

```js
var express = require('express')
var cookieParser = require('cookie-parser')
var cookieValidator = require('./cookieValidator')

var app = express()

function validateCookies (req, res, next) {
return cookieValidator(req.cookies).then(function () {
next()
})
}

app.use(cookieParser)

app.use(validateCookies)

// error handler
app.use(function (err, req, res, next) {
res.status(400).send(err.message)
})

app.listen(3000)

```

<div class="doc-box doc-notice" markdown="1">
Note how `.then` accepts a function which calls `next()`. This ensures that if `cookieValidator` resolves, the next middleware in the stack will get called. If you pass anything to the `next()` function (except the string `'route'`), Express regards the current request as being an error and will skip any remaining non-error handling routing and middleware functions.
</div>

If your version of node.js supports async/await, you can use async functions directly in your middleware. The above example could be rewritten as follows:

```js
var express = require('express')
var cookieParser = require('cookie-parser')
var cookieValidator = require('./cookieValidator')

var app = express()

async function validateCookies (req, res, next) {
await cookieValidator(req.cookies)
next()
}

app.use(cookieParser)

app.use(validateCookies)

// error handler
app.use(function (err, req, res, next) {
res.status(400).send(err.message)
})

app.listen(3000)
```

Because you have access to the request object, the response object, the next middleware function in the stack, and the whole Node.js API, the possibilities with middleware functions are endless.

For more information about Express middleware, see: [Using Express middleware](/{{ page.lang }}/guide/using-middleware.html).
Expand Down

0 comments on commit 0389f61

Please sign in to comment.