Skip to content

Releases: expressjs/codemod

v1.1.0@v5-migration-recipe: feat: update package.json in v5 migration recipe (#143)

Choose a tag to compare

@bjohansebas bjohansebas released this 23 Jun 04:25
Immutable release. Only release title and notes can be modified.
2f7f1e5

Migrate recipes for Express.js v5

This codemod migration recipe helps you update your Express.js v4 applications to be compatible with Express.js v5 by addressing deprecated APIs.

Included transformations:

References

v1.0.0@static-mime

Choose a tag to compare

@bjohansebas bjohansebas released this 23 Jun 03:30
Immutable release. Only release title and notes can be modified.
44aae41

Migrate express.static.mime

In Express 5, mime is no longer an exported property of express.static. The
mime-types package should be used to
work with MIME type values instead.

This codemod rewrites every express.static.mime reference to use a mime-types
binding and adds the corresponding import/require to the file:

  1. Replaces express.static.mime with a mime-types local binding (default name mime).
  2. Adds the import once per file, matching how express is imported
    (import mime from 'mime-types' for ESM, const mime = require('mime-types') for CommonJS).
  3. Reuses an existing mime-types import when the file already has one, and falls
    back to a non-colliding name (mimeTypes) when mime is already taken.

The object Express 4 exposed as express.static.mime was a mime@1.x
instance, whose API is not identical to mime-types. The codemod rewrites
each member accordingly:

express.static.mime (mime@1.x) mime-types Handled by
.lookup(path) .lookup(path) rename of the binding
.extension(type) .extension(type) rename of the binding
.types / .extensions .types / .extensions rename of the binding
.charsets.lookup(type) .charset(type) method rewrite
.define(map) no equivalent flagged with a TODO comment
.load(path) no equivalent flagged with a TODO comment
.default_type no equivalent flagged with a TODO comment

Example

  import express from 'express'
+ import mime from 'mime-types'

- const type = express.static.mime.lookup('json')
+ const type = mime.lookup('json')

Renamed method

- const charset = express.static.mime.charsets.lookup('text/html')
+ const charset = mime.charset('text/html')

Methods without a mime-types equivalent

define, load, and default_type cannot be migrated automatically, so the
codemod points them at the new binding and flags them for manual review:

- express.static.mime.define({ 'text/x-custom': ['cstm'] })
+ mime.define({ 'text/x-custom': ['cstm'] }) /* TODO: 'mime-types' has no define(); migrate manually */

CommonJS

  const express = require('express')
+ const mime = require('mime-types')

- express.static.mime.lookup('json')
+ mime.lookup('json')

package.json

For projects that depend on express, the codemod also adds mime-types to the
same dependency section, so the newly referenced package is declared:

  "dependencies": {
-   "express": "^5.0.0"
+   "express": "^5.0.0",
+   "mime-types": "^3.0.0"
  }

An existing mime-types entry is left untouched, and package.json files without
express are not modified.

Notes

  • Behavior differs slightly even for the shared methods: mime-types returns
    false for unknown input, whereas mime@1.x lookup() fell back to
    default_type (application/octet-stream). Review code that relied on that
    fallback.
  • Members flagged with a TODO comment (define, load, default_type) have no
    mime-types equivalent and must be migrated by hand.
  • Run npm install after the migration so the added mime-types dependency is installed.

References

v1.0.0@sendfile-options: feat: add codemod to migrate res.sendFile() options for Express 5 (#149)

Choose a tag to compare

@bjohansebas bjohansebas released this 23 Jun 04:00
Immutable release. Only release title and notes can be modified.
d6c9ddd

Migrate res.sendFile options

Express 5 changes several res.sendFile options, mirroring the express.static
changes:

  • The dotfiles option now also applies to hidden directories in the path, not
    just hidden files. In Express 4 a hidden directory in the path was served by
    default; Express 5 returns a 404 Not Found unless you opt in with
    dotfiles: 'allow'.
  • The hidden option is removed and replaced by dotfiles.
  • The from option (an undocumented alias for root) is removed and replaced by root.

This codemod updates res.sendFile() calls to preserve the Express 4 behavior:

  1. Adds an explicit dotfiles: 'allow' option to calls that don't already specify a dotfiles (or hidden) option.
  2. Renames hidden to dotfiles (hidden: truedotfiles: 'allow', hidden: falsedotfiles: 'ignore').
  3. Renames from to root.

Only calls whose receiver is a response object (a route/middleware handler
parameter, e.g. the res in (req, res) => res.sendFile(...)) are rewritten.

Example

  app.get('/build', (req, res) => {
-   res.sendFile('/var/www/app/.cache/index.html')
+   res.sendFile('/var/www/app/.cache/index.html', { dotfiles: 'allow' /* Express 5: preserve v4 behavior */ })
  })

With existing options

- res.sendFile('index.html', { maxAge: '1d' })
+ res.sendFile('index.html', { maxAge: '1d', dotfiles: 'allow' /* Express 5: preserve v4 behavior */ })

Removed hidden / from options

- res.sendFile(req.params.name, { hidden: true, from: '/uploads' })
+ res.sendFile(req.params.name, { dotfiles: 'allow', root: '/uploads' })

With a trailing callback

The options object is inserted before the callback:

- res.sendFile('index.html', (err) => next(err))
+ res.sendFile('index.html', { dotfiles: 'allow' /* Express 5: preserve v4 behavior */ }, (err) => next(err))

Security Consideration

After running this codemod, review each res.sendFile() call to determine if
serving dotfiles is actually necessary for your application. If you don't need to
serve dotfiles, you can:

  1. Remove the dotfiles: 'allow' option to use the new Express 5 default ("ignore")
  2. Or explicitly set dotfiles: 'deny' to return a 403 Forbidden for dotfile requests

Note that passing a root option scopes the dotfiles check to the part of the
path relative to root, so a hidden directory in root itself is unaffected.

References

static-dotfiles@v1.0.0

Choose a tag to compare

@bjohansebas bjohansebas released this 17 Jun 02:32
Immutable release. Only release title and notes can be modified.
cab8746

Migrate express.static options

Express 5 changes several express.static options:

  • The dotfiles option now defaults to "ignore" (Express 4 served dotfiles by default). Files inside a directory that starts with a dot (.), such as .well-known, will no longer be accessible and will return a 404 Not Found error.
  • The hidden option is removed and replaced by dotfiles.
  • The from option (an undocumented alias for root) is removed and replaced by root.

This codemod updates express.static() calls to preserve the Express 4 behavior:

  1. Adds an explicit dotfiles: 'allow' option to calls that don't already specify a dotfiles (or hidden) option.
  2. Renames hidden to dotfiles (hidden: truedotfiles: 'allow', hidden: falsedotfiles: 'ignore').
  3. Renames from to root.

Example

- app.use(express.static('public'))
+ app.use(express.static('public', { dotfiles: 'allow' /* Express 5: preserve v4 behavior */ }))

With existing options

- app.use(express.static('public', { maxAge: '1d' }))
+ app.use(express.static('public', { maxAge: '1d', dotfiles: 'allow' /* Express 5: preserve v4 behavior */ }))

Removed hidden option

- app.use(express.static('public', { hidden: true }))
+ app.use(express.static('public', { dotfiles: 'allow' }))

Removed from option

- app.use(express.static('uploads', { from: '/uploads' }))
+ app.use(express.static('uploads', { root: '/uploads', dotfiles: 'allow' /* Express 5: preserve v4 behavior */ }))

Security Consideration

After running this codemod, review each express.static() call to determine if serving dotfiles is actually necessary for your application. If you don't need to serve dotfiles, you can:

  1. Remove the dotfiles: 'allow' option to use the new Express 5 default ("ignore")
  2. Or explicitly set dotfiles: 'deny' to return a 403 Forbidden for dotfile requests

For directories like .well-known that need to be served (e.g., for Android App Links or Apple Universal Links), consider serving them explicitly:

app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' }))
app.use(express.static('public'))

References

v5-migration-recipe@1.0.0

Choose a tag to compare

@bjohansebas bjohansebas released this 13 Jan 15:59
Immutable release. Only release title and notes can be modified.
add40f7

Migrate recipes for Express.js v5

This codemod migration recipe helps you update your Express.js v4 applications to be compatible with Express.js v5 by addressing deprecated APIs.

Included transformations:

References

route-del-to-delete@1.0.0

Choose a tag to compare

@bjohansebas bjohansebas released this 13 Jan 15:00
Immutable release. Only release title and notes can be modified.
ce5c9ad

Migrate legacy app.del() to app.delete()

Migrates usage of the legacy APIs app.del() to app.delete().
Initially, del was used instead of delete, because delete is a reserved keyword in JavaScript. However, as of ECMAScript 6, delete and other reserved keywords can legally be used as property names. The app.del() method was deprecated in Express 4 and removed in Express 5.

Example

Migrating app.del()

The migration involves replacing instances of app.del() with app.delete().

- app.del('/some-route', (req, res) => {
+ app.delete('/some-route', (req, res) => {
    // Some logic here
 });

References

redirect-arg-order@1.0.0

Choose a tag to compare

@bjohansebas bjohansebas released this 13 Jan 15:10
Immutable release. Only release title and notes can be modified.
a0a45a0

Migrate legacy res.redirect(url, status)

Migrates usage of the legacy APIs res.redirect(url, status) to the new signature
res.redirect(status, url). This usage was deprecated in Express 4, in Express 5 you must use the new signature res.redirect(status, url).

Example

Migrating res.redirect(url, status)

The migration involves replacing instances of res.redirect(url, status) with res.redirect(status, url).

app.get('/some-route', (req, res) => {
  // Some logic here
- res.redirect(url, status);
+ res.redirect(status, url);
});

References

explicit-request-params@1.0.0

Choose a tag to compare

@bjohansebas bjohansebas released this 13 Jan 15:34
Immutable release. Only release title and notes can be modified.
5464214

Migrate legacy req.param(name)

The req.param(name) helper that used to magically look up values from multiple places has been removed. This potentially confusing and dangerous method of retrieving form data has been removed. You will now need to specifically look for the submitted parameter name in the req.params, req.body, or req.query object.

Examples

Replacing req.param('body') and req.param('query')

Replace req.param('body') with req.body and
req.param('query') with req.query.

app.get('/', (req, res) => {
  // Before
- const reqBody = req.param('body');
- const reqQuery = req.param('query');
  // After
+ const reqBody = req.body;
+ const reqQuery = req.query;
});

Replacing req.param('paramName')

Replace req.param('paramName') with req.params.paramName.

app.get('/user/:id', (req, res) => {
  // Before
- const userId = req.param('id');
  // After
+ const userId = req.params.id;
});

References

status-send-order@1.0.0

Choose a tag to compare

@bjohansebas bjohansebas released this 09 Jan 22:43
Immutable release. Only release title and notes can be modified.
5856cfd

Migrate legacy res.send(obj, status), res.send(status), res.json(obj, status) and res.jsonp(obj, status)

Migrates usage of the legacy APIs res.send(obj, status), res.json(obj, status), and res.jsonp(obj, status) to use the recommended approach of specifying the status code
using the res.status(status).send(obj), res.status(status).json(obj), and
res.status(status).jsonp(obj) methods respectively. The older APIs that allowed
specifying the status code as a second argument have been deprecated.

Example

Migrating res.send(obj, status)

The migration involves replacing instances of res.send(obj, status) with res.status(status).send(obj).

app.get('/some-route', (req, res) => {
  // Some logic here
- res.send(obj, status);
+ res.status(status).send(obj);
});

Migrating res.json(obj, status)

The migration involves replacing instances of res.json(obj, status) with res.status(status).json(obj).

app.get('/some-route', (req, res) => {
  // Some logic here
- res.json(obj, status);
+ res.status(status).json(obj);
});

Migrating res.jsonp(obj, status)

The migration involves replacing instances of res.jsonp(obj, status) with res.status(status).jsonp(obj).

app.get('/some-route', (req, res) => {
  // Some logic here
- res.jsonp(obj, status);
+ res.status(status).jsonp(obj);
});

Migrating res.send(status)

The migration involves replacing instances of res.send(status) with res.sendStatus(status).

app.get('/some-route', (req, res) => {
  // Some logic here
- res.send(status);
+ res.sendStatus(status);
});

References

pluralize-method-names@1.0.0

Choose a tag to compare

@bjohansebas bjohansebas released this 09 Jan 22:46
Immutable release. Only release title and notes can be modified.
d9782a6

Migrate pluralized request methods

Migrates deprecated request methods to their pluralized versions that were deprecated in Express 4 and removed in Express 5.

Example

Migrating req.acceptsCharset(charset)

The migration involves replacing instances of req.acceptsCharset(charset) with req.acceptsCharsets(charset).

app.get('/', (req, res) => {
- const charset = req.acceptsCharset('utf-8');
+ const charset = req.acceptsCharsets('utf-8');
  res.json({ charset });
});

Migrating `req.acceptsEncoding(encoding)

The migration involves replacing instances of req.acceptsEncoding(encoding) with req.acceptsEncodings(encoding).

app.get('/', (req, res) => {
- const encoding = req.acceptsEncoding('gzip');
+ const encoding = req.acceptsEncodings('gzip');
  res.json({ encoding });
});

Migrating req.acceptsLanguage(language)

The migration involves replacing instances of req.acceptsLanguage(language) with req.acceptsLanguages(language).

app.get('/', (req, res) => {
- const language = req.acceptsLanguage('en');
+ const language = req.acceptsLanguages('en');
  res.json({ language });
});

References