javascript 51 lines · 9 steps

Content negotiation with res.format in Express

One Express route serves JSON, HTML, or CSV from the same data by matching the client's Accept header.

Explained by highlit
1const express = require('express');
2const router = express.Router();
3 
4router.get('/articles/:slug', async (req, res, next) => {
5 try {
6 const article = await Article.findBySlug(req.params.slug);
7 
8 if (!article) {
9 return res.format({
10 'application/json': () => res.status(404).json({ error: 'Article not found' }),
11 'text/html': () => res.status(404).render('errors/404', { slug: req.params.slug }),
12 default: () => res.status(406).send('Not Acceptable')
13 });
14 }
15 
16 const related = await article.relatedArticles({ limit: 5 });
17 
18 res.format({
19 'application/json': () => {
20 res.json({
21 data: article.toJSON(),
22 related: related.map((a) => a.toSummary())
23 });
24 },
25 
26 'text/html': () => {
27 res.render('articles/show', {
28 article,
29 related,
30 title: article.title
31 });
32 },
33 
34 'text/csv': () => {
35 res.attachment(`${article.slug}.csv`);
36 res.send(article.toCsvRow());
37 },
38 
39 default: () => {
40 res.status(406).json({
41 error: 'Not Acceptable',
42 supported: ['application/json', 'text/html', 'text/csv']
43 });
44 }
45 });
46 } catch (err) {
47 next(err);
48 }
49});
50 
51module.exports = router;
01 / 01
STEP 01

Walkthrough

Space play ←→ step click any line
Three takeaways
  1. 1res.format lets one handler serve multiple representations by branching on the Accept header instead of duplicating routes.
  2. 2Always supply a default branch so unsupported Accept headers return a clean 406 rather than falling through silently.
  3. 3Wrapping async handler logic in try/catch and forwarding to next(err) routes failures into Express's error middleware.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Content negotiation with res.format in Express — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code