Skip to content

docs: fix result comments that differ from Express behavior - #2551

Open
yxshee wants to merge 2 commits into
expressjs:mainfrom
yxshee:fix/api-example-outputs
Open

yxshee wants to merge 2 commits into
expressjs:mainfrom
yxshee:fix/api-example-outputs

Conversation

@yxshee

@yxshee yxshee commented Oct 26, 2026

Copy link
Copy Markdown

What this changes

I ran the examples in the 4.x and 5.x API reference against a local server, using real HTTP requests, with express@5.3.0 and express@4.22.3. These claims did not match what Express does:

  1. req.is() with a wildcard (4.x and 5.x). With Content-Type: text/html; charset=utf-8, req.is('text/*') returns 'text/html', not 'text/*'. With application/json, req.is('application/*') returns 'application/json'. type-is returns the real type when the pattern has a *.
  2. res.type() (4.x and 5.x). After res.type('html') the header is text/html; charset=utf-8. Same for .html, json and application/json. res.set() adds the charset. png stays image/png, so that line is unchanged.
  3. res.cookie() with encode: String (4.x and 5.x). The real header is ...; Domain=example.com; Path=/. There is no trailing ;.
  4. res.cookie() with an object value (4.x and 5.x). The text said the value is parsed by bodyParser(). It is cookieParser() that reads the j: JSON cookie back. I checked that req.cookies.cart comes back as { items: [1, 2, 3] } and req.body is undefined.
  5. express.static dotfiles (4.x and 5.x). The text said "deny" responds with 403 and "ignore" with 404, and then next() is called. With the default fallthrough: true, both just call next(). With fallthrough: false, they call next(err) with a 403 or 404 error. I reworded both lines to say that. This matches the "403/next()" and "404/next()" notes in the serve-static README.
  6. res.attachment('path/to/logo.png') (5.x only). Express 5 sends Content-Disposition: attachment; filename=logo.png with no quotes, because content-disposition@1 only quotes when it has to. Express 4 still sends filename="logo.png", so I left the 4.x page alone.

How I checked it

I started an app with app.listen(0) and sent requests with http.request. The same script ran against both versions:

express 5.3.0
req.is {"ct":"text/html; charset=utf-8","text/*":"text/html","application/*":false}
req.is {"ct":"application/json","text/*":false,"application/*":"application/json"}
res.attachment -> Content-Disposition: attachment; filename=logo.png | Content-Type: image/png
res.cookie encode:String -> some_cross_domain_cookie=http://mysubdomain.example.com; Domain=example.com; Path=/
res.cookie object -> cart=j%3A%7B%22items%22%3A%5B1%2C2%2C3%5D%7D; Path=/
read back with cookieParser(): {"cookies":{"cart":{"items":[1,2,3]}},"body":"undefined"}
res.type -> {".html":"text/html; charset=utf-8","html":"text/html; charset=utf-8","json":"application/json; charset=utf-8","application/json":"application/json; charset=utf-8","png":"image/png"}
static /deny/.env 404 next() called, reached fallback
static /ign/.env 404 next() called, reached fallback
static /denyft/.env 403 next(err) called with status 403
static /ignft/.env 404 next(err) called with status 404

express 4.22.3
(same, except)
res.attachment -> Content-Disposition: attachment; filename="logo.png" | Content-Type: image/png

I also ran the other result comments on these pages, including req.accepts*, req.range, req.route, res.format, res.links, app.param, app.mountpath, app.path(), express.json/urlencoded and the router examples. They match, so I did not touch them.

prettier --check passes on the changed files. The changes add no new words for cspell.

Run each example against express@5.3.0 and express@4.22.3 and correct
the claims that do not match:

- req.is() with a wildcard type returns the matched content type
  ('text/html', 'application/json'), not the wildcard.
- res.type() sets 'text/html; charset=utf-8' and
  'application/json; charset=utf-8', since res.set() adds the charset.
- res.cookie() with encode: String emits no trailing ';'.
- Object cookie values are parsed back by cookieParser(), not
  bodyParser().
- express.static dotfiles "deny" and "ignore" call next() by default;
  the 403/404 only happens via next(err) when fallthrough is false.
- 5.x only: res.attachment() sends filename=logo.png without quotes
  (content-disposition@1 only quotes when needed).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NQDmA3mwGfL83pbg9WQ6ey
@yxshee
yxshee requested a review from a team as a code owner October 26, 2026 12:14
@netlify

netlify Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for expressjscom-preview ready!

Name Link
🔨 Latest commit 08f25ac
🔍 Latest deploy log https://app.netlify.com/projects/expressjscom-preview/deploys/6aecbed787becd328fde8651
😎 Deploy Preview https://deploy-preview-2551--expressjscom-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 99 (🟢 up 2 from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 100 (no change from production)
PWA: 80 (no change from production)
View the detailed breakdown and full score reports
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant