Actualización a Express v5
Express 5 no es muy diferente de Express 4; aunque mantiene la misma API básica, todavía hay cambios que rompen la compatibilidad con la versión anterior. Por lo tanto, una aplicación construida con Express 4 podría no funcionar si la actualizas para usar Express 5.
Instalación
Para instalar esta versión, necesitas tener Node.js versión 18 o superior. Luego, ejecuta el siguiente comando en el directorio de tu aplicación:
npm install "express@5"yarn add "express@5"pnpm add "express@5"bun add "express@5"Luego puedes ejecutar tus pruebas automatizadas para ver qué falla, y corregir los problemas según las actualizaciones que se listan a continuación. Después de abordar los fallos de las pruebas, ejecuta tu aplicación para ver qué errores ocurren. Descubrirás de inmediato si la aplicación usa algún método o propiedad que no esté soportado.
Codemods de Express 5
Para ayudarte a migrar tu servidor de Express, hemos creado un conjunto de codemods que te ayudarán a actualizar automáticamente tu código a la última versión de Express.
Ejecuta el siguiente comando para ejecutar todos los codemods disponibles:
npx codemod@latest @expressjs/v5-migration-recipeyarn dlx codemod@latest @expressjs/v5-migration-recipepnpm dlx codemod@latest @expressjs/v5-migration-recipebunx codemod@latest @expressjs/v5-migration-recipeSi quieres ejecutar un codemod específico, puedes ejecutar el siguiente comando:
npx codemod@latest @expressjs/name-of-the-codemodyarn dlx codemod@latest @expressjs/name-of-the-codemodpnpm dlx codemod@latest @expressjs/name-of-the-codemodbunx codemod@latest @expressjs/name-of-the-codemodPuedes encontrar la lista de codemods disponibles aquí.
Métodos y propiedades eliminados
Si usas alguno de estos métodos o propiedades en tu aplicación, fallará. Así que necesitarás cambiar tu aplicación después de actualizar a la versión 5.
app.del()
Express 5 ya no soporta la función app.del(). Si usas esta función, se lanza un error. Para registrar rutas HTTP DELETE, usa la función app.delete() en su lugar.
Inicialmente, se usaba del en lugar de delete, porque delete es una palabra reservada en JavaScript. Sin embargo, a partir de ECMAScript 6, delete y otras palabras reservadas pueden usarse legalmente como nombres de propiedades.
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/route-del-to-deleteyarn dlx codemod@latest @expressjs/route-del-to-deletepnpm dlx codemod@latest @expressjs/route-del-to-deletebunx codemod@latest @expressjs/route-del-to-deleteO puedes actualizar tu código manualmente:
app.del('/user/:id', (req, res) => {app.delete('/user/:id', (req, res) => { res.send(`DELETE /user/${req.params.id}`);});app.param(fn)
La signatura app.param(fn) se usaba para modificar el comportamiento de la función app.param(name, fn). Ha estado obsoleta desde v4.11.0, y Express 5 ya no la soporta en absoluto.
Nombres de métodos pluralizados
Los siguientes nombres de métodos han sido pluralizados. En Express 4, usar los métodos antiguos resultaba en una advertencia de obsolescencia. Express 5 ya no los soporta en absoluto:
req.acceptsCharset() es reemplazado por req.acceptsCharsets().
req.acceptsEncoding() es reemplazado por req.acceptsEncodings().
req.acceptsLanguage() es reemplazado por req.acceptsLanguages().
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/pluralize-method-namesyarn dlx codemod@latest @expressjs/pluralize-method-namespnpm dlx codemod@latest @expressjs/pluralize-method-namesbunx codemod@latest @expressjs/pluralize-method-namesO puedes actualizar tu código manualmente:
app.all('/', (req, res) => { req.acceptsCharset('utf-8'); req.acceptsEncoding('br'); req.acceptsLanguage('en'); req.acceptsCharsets('utf-8'); req.acceptsEncodings('br'); req.acceptsLanguages('en');
// ...});Dos puntos iniciales (:) en el nombre para app.param(name, fn)
Un carácter de dos puntos inicial (:) en el nombre de la función app.param(name, fn) es un remanente de Express 3, y por razones de compatibilidad con versiones anteriores, Express 4 lo soportaba con una advertencia de obsolescencia. Express 5 lo ignorará silenciosamente y usará el parámetro name sin el prefijo de dos puntos.
Esto no debería afectar tu código si sigues la documentación de Express 4 de app.param, ya que no menciona los dos puntos iniciales.
req.param(name)
Este método potencialmente confuso y peligroso de obtener datos de formularios ha sido eliminado. Ahora necesitarás buscar específicamente el nombre del parámetro enviado en el objeto req.params, req.body, o req.query.
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/explicit-request-paramsyarn dlx codemod@latest @expressjs/explicit-request-paramspnpm dlx codemod@latest @expressjs/explicit-request-paramsbunx codemod@latest @expressjs/explicit-request-paramsO puedes actualizar tu código manualmente:
app.post('/user', (req, res) => { const id = req.param('id'); const body = req.param('body'); const query = req.param('query'); const id = req.params.id; const body = req.body; const query = req.query;
// ...});res.json(obj, status)
Express 5 ya no soporta la signatura res.json(obj, status). En su lugar, establece el estado y luego encadénalo al método res.json() así: res.status(status).json(obj).
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/status-send-orderyarn dlx codemod@latest @expressjs/status-send-orderpnpm dlx codemod@latest @expressjs/status-send-orderbunx codemod@latest @expressjs/status-send-orderO puedes actualizar tu código manualmente:
app.post('/user', (req, res) => { res.json({ name: 'Ruben' }, 201); res.status(201).json({ name: 'Ruben' });});res.jsonp(obj, status)
Express 5 ya no soporta la signatura res.jsonp(obj, status). En su lugar, establece el estado y luego encadénalo al método res.jsonp() así: res.status(status).jsonp(obj).
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/status-send-orderyarn dlx codemod@latest @expressjs/status-send-orderpnpm dlx codemod@latest @expressjs/status-send-orderbunx codemod@latest @expressjs/status-send-orderO puedes actualizar tu código manualmente:
app.post('/user', (req, res) => { res.jsonp({ name: 'Ruben' }, 201); res.status(201).jsonp({ name: 'Ruben' });});res.redirect(url, status)
Express 5 ya no soporta la signatura res.redirect(url, status). En su lugar, usa la siguiente signatura: res.redirect(status, url).
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/redirect-arg-orderyarn dlx codemod@latest @expressjs/redirect-arg-orderpnpm dlx codemod@latest @expressjs/redirect-arg-orderbunx codemod@latest @expressjs/redirect-arg-orderO puedes actualizar tu código manualmente:
app.get('/user', (req, res) => { res.redirect('/users', 302); res.redirect(302, '/users');});
// A redirect that relies on the default 302 status is unaffectedapp.get('/admin', (req, res) => { res.redirect('/dashboard');});res.redirect(‘back’) y res.location(‘back’)
Express 5 ya no soporta la cadena mágica back en los métodos res.redirect() y res.location(). En su lugar, usa el valor req.get('Referrer') || '/' para redirigir de vuelta a la página anterior. En Express 4, los métodos res.redirect('back') y res.location('back') estaban obsoletos.
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/back-redirect-deprecatedyarn dlx codemod@latest @expressjs/back-redirect-deprecatedpnpm dlx codemod@latest @expressjs/back-redirect-deprecatedbunx codemod@latest @expressjs/back-redirect-deprecatedO puedes actualizar tu código manualmente:
app.get('/user', (req, res) => { res.redirect('back'); res.redirect(req.get('Referrer') || '/');});res.send(body, status)
Express 5 ya no soporta la signatura res.send(obj, status). En su lugar, establece el estado y luego encadénalo al método res.send() así: res.status(status).send(obj).
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/status-send-orderyarn dlx codemod@latest @expressjs/status-send-orderpnpm dlx codemod@latest @expressjs/status-send-orderbunx codemod@latest @expressjs/status-send-orderO puedes actualizar tu código manualmente:
app.get('/user', (req, res) => { res.send({ name: 'Ruben' }, 200); res.status(200).send({ name: 'Ruben' });});res.send(status)
Express 5 ya no soporta la signatura res.send(status), donde status es un número. En su lugar, usa la función res.sendStatus(statusCode), que establece el código de estado del encabezado de respuesta HTTP y envía la versión en texto del código: "Not Found", "Internal Server Error", y así sucesivamente.
Si necesitas enviar un número usando la función res.send(), entrecomilla el número para convertirlo en una cadena, para que Express no lo interprete como un intento de usar la antigua signatura no soportada.
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/status-send-orderyarn dlx codemod@latest @expressjs/status-send-orderpnpm dlx codemod@latest @expressjs/status-send-orderbunx codemod@latest @expressjs/status-send-orderO puedes actualizar tu código manualmente:
app.get('/user', (req, res) => { res.send(200); res.sendStatus(200);});res.sendfile()
La función res.sendfile() ha sido reemplazada por una versión en camelCase res.sendFile() en Express 5.
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/camelcase-sendfileyarn dlx codemod@latest @expressjs/camelcase-sendfilepnpm dlx codemod@latest @expressjs/camelcase-sendfilebunx codemod@latest @expressjs/camelcase-sendfileO puedes actualizar tu código manualmente:
app.get('/user', (req, res) => { res.sendfile('/path/to/file'); res.sendFile('/path/to/file');});Opciones de res.sendFile()
Las opciones hidden y from para res.sendFile() ya no están soportadas. Usa dotfiles y root en su lugar.
La opción dotfiles se aplica tanto a directorios ocultos en la ruta como a archivos ocultos. Por ejemplo, un archivo servido desde una ruta absoluta como /var/www/app/.cache/index.html ahora requiere dotfiles: 'allow', a pesar de que index.html no es un dotfile. En Express 4 un directorio oculto en la ruta se servía por defecto; Express 5 devuelve 404 a menos que lo habilites explícitamente.
Esta verificación solo se aplica a la parte de la ruta que send evalúa. Cuando pasas un root, solo se verifica la porción relativa a root, por lo que un directorio oculto dentro de root no se ve afectado.
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/sendfile-optionsyarn dlx codemod@latest @expressjs/sendfile-optionspnpm dlx codemod@latest @expressjs/sendfile-optionsbunx codemod@latest @expressjs/sendfile-optionsO puedes actualizar tu código manualmente:
app.get('/files/:name', (req, res) => { res.sendFile(req.params.name, { hidden: true, from: '/uploads' }); res.sendFile(req.params.name, { dotfiles: 'allow', root: '/uploads' });});Si sirves una ruta absoluta que contiene un directorio oculto, habilítalo con dotfiles: 'allow' o usa root para que el segmento oculto no sea parte de la ruta evaluada:
app.get('/build', (req, res) => { res.sendFile('/var/www/app/.cache/index.html'); res.sendFile('/var/www/app/.cache/index.html', { dotfiles: 'allow' }); // or: res.sendFile('index.html', { root: '/var/www/app/.cache' });});Opciones de express.static()
Las opciones hidden y from para express.static() ya no están soportadas. Usa dotfiles y root en su lugar. Ten en cuenta que from nunca estuvo documentado en la API pero era aceptado como un alias de root. El valor por defecto de dotfiles es ahora "ignore".
La verificación de dotfiles ahora también se aplica a directorios ocultos en la ruta de la petición, no solo a archivos ocultos. Una petición como GET /.well-known/acme-challenge/... que se servía por defecto en Express 4 ahora devuelve 404 a menos que establezcas dotfiles: 'allow'. Esto solo afecta a la parte de la ruta relativa al root configurado; un directorio oculto dentro del propio root no se ve afectado.
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/static-dotfilesyarn dlx codemod@latest @expressjs/static-dotfilespnpm dlx codemod@latest @expressjs/static-dotfilesbunx codemod@latest @expressjs/static-dotfilesO puedes actualizar tu código manualmente:
const express = require('express');const app = express();
app.use(express.static('public', { hidden: true }));app.use(express.static('public', { dotfiles: 'allow' }));Si dependes de servir un directorio oculto como .well-known (por ejemplo, retos ACME/Let's Encrypt), habilítalo explícitamente. Esto es necesario incluso si nunca usaste la opción hidden:
app.use(express.static('public'));app.use(express.static('public', { dotfiles: 'allow' }));router.param(fn)
La signatura router.param(fn) se usaba para modificar el comportamiento de la función router.param(name, fn). Ha estado obsoleta desde v4.11.0, y Express 5 ya no la soporta en absoluto.
express.static.mime
En Express 5, mime ya no es una propiedad exportada del campo static.
Usa el paquete mime-types para trabajar con valores de tipo MIME.
Cómo actualizar
Puedes actualizar tu código automáticamente ejecutando el siguiente comando:
npx codemod@latest @expressjs/static-mimeyarn dlx codemod@latest @expressjs/static-mimepnpm dlx codemod@latest @expressjs/static-mimebunx codemod@latest @expressjs/static-mimeO puedes actualizar tu código manualmente:
express.static.mime.lookup('json');const mime = require('mime-types');mime.lookup('json');Cambios en tipos MIME
Varios tipos MIME han cambiado debido a actualizaciones en mime-db. Estos cambios solo afectan a express.static() y res.sendFile(). Para una lista completa de cambios, consulta el changelog de mime-db.
Express 4 usa la versión 1.52.0 de mime-db, mientras que Express 5 usa versiones más recientes que reflejan las actualizaciones de IANA y otras especificaciones de tipos MIME. El cambio más notable es que los archivos JavaScript (.js) ahora se sirven como text/javascript en lugar de application/javascript.
En Express 5, los cambios en los tipos MIME por actualizaciones de mime-db no se consideran cambios que rompen compatibilidad, así que ten cuidado al actualizar tus dependencias, ya que los tipos MIME pueden cambiar entre versiones menores o de parche.
Logs de depuración express:router
La lógica de manejo del Router ahora es realizada por una dependencia separada (router) mantenida por el equipo de Express, por lo que los logs de depuración se han movido a un namespace diferente. Antes de Express 5.1, estos logs de depuración no existían. Para obtenerlos, actualiza a una versión reciente de Express 5 o actualiza el paquete router en tu package-lock.json:
| v4 | v5 |
|---|---|
express:router | router |
express:router:layer | router:layer |
express:router:route | router:route |
express:* (incluye todo) | express:* + router + router:* |
Cómo actualizar
DEBUG=express:* node index.jsDEBUG=express:*,router,router:* node index.jsCambios
Estas APIs todavía existen pero su comportamiento ha cambiado. Revisa estos cambios para asegurarte de que tu aplicación funcione como se espera.
Sintaxis de coincidencia de rutas por path
La sintaxis de coincidencia de rutas por path es cuando se proporciona una cadena como primer parámetro a las APIs app.all(), app.use(), app.METHOD(), router.all(), router.METHOD(), y router.use(). Se han hecho los siguientes cambios en cómo la cadena de path se compara con una petición entrante:
-
El comodín
*debe tener un nombre, coincidiendo con el comportamiento de los parámetros:, usa/*splaten lugar de/*app.get('/*', async (req, res) => {app.get('/*splat', async (req, res) => {res.send('ok');});Nota
*splatcoincide con cualquier ruta sin la ruta raíz. Si necesitas coincidir también con la ruta raíz/, puedes usar/{*splat}, envolviendo el comodín en llaves.app.get('/{*splat}', async (req, res) => {res.send('ok');}); -
El carácter opcional
?ya no está soportado, usa llaves en su lugar.app.get('/:file.:ext?', async (req, res) => {app.get('/:file{.:ext}', async (req, res) => {res.send('ok');}); -
Los caracteres de expresiones regulares no están soportados. Por ejemplo:
app.get('/[discussion|page]/:slug', async (req, res) => {app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => {res.status(200).send('ok');}); -
Algunos caracteres han sido reservados para evitar confusión durante la actualización (
()[]?+!), usa\para escaparlos. -
Los nombres de parámetros ahora soportan identificadores válidos de JavaScript, o entre comillas como
:"this".
Promesas rechazadas manejadas desde middleware y handlers
El middleware de petición y los handlers que devuelven promesas rechazadas ahora se manejan reenviando el valor rechazado como un Error al middleware de manejo de errores. Esto significa que usar funciones async como middleware y handlers es más fácil que nunca. Cuando se lanza un error en una función async o una promesa rechazada es awaited dentro de una función async, esos errores se pasarán al manejador de errores como si se llamara next(err).
Los detalles sobre cómo Express maneja los errores se cubren en la documentación de manejo de errores.
Cómo actualizar
Ahora puedes usar async/await directamente sin capturar errores manualmente. Si getUserById lanza un error o rechaza, next será llamado automáticamente con el valor rechazado.
app.get('/user/:id', (req, res, next) => { getUserById(req.params.id) .then((user) => res.send(user)) .catch(next);});app.get('/user/:id', async (req, res) => { const user = await getUserById(req.params.id); res.send(user);});express.urlencoded
El método express.urlencoded hace que la opción extended sea false por defecto.
Cómo actualizar
Si tu aplicación depende del comportamiento de extended, establécelo explícitamente en true:
app.use(express.urlencoded());app.use(express.urlencoded({ extended: true }));Dotfiles en express.static
La opción dotfiles del middleware express.static ahora tiene por defecto "ignore". En Express 4, los dotfiles se servían por defecto. Como resultado, los archivos dentro de un directorio que empieza con un punto (.), como .well-known, ya no serán accesibles y devolverán un error 404 Not Found. Esto puede romper funcionalidades que dependen de servir dot-directories, como Android App Links y Apple Universal Links.
Cómo actualizar
Sirve dot-directories específicos explícitamente usando la opción dotfiles: "allow". Esto te permite servir de forma segura solo los dot-directories deseados mientras mantienes el comportamiento seguro por defecto para otros dotfiles.
app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' }));app.use(express.static('public'));router.param() con un array de nombres
router.param(name, fn) ya no acepta un array para name. En Express 4 se aceptaba un array silenciosamente; en Express 5, pasar cualquier cosa que no sea una cadena lanza TypeError: argument name must be a string. (Ten en cuenta que app.param() todavía acepta un array de nombres.)
Cómo actualizar
Registra cada nombre de parámetro con su propia llamada a router.param():
router.param(['id', 'page'], (req, res, next, value) => { // ...});const loadParam = (req, res, next, value) => { // ...};router.param('id', loadParam);router.param('page', loadParam);app.listen
En Express 5, el método app.listen invocará la función callback proporcionada por el usuario (si se proporciona) cuando el servidor recibe un evento de error. En Express 4, dichos errores se lanzaban. Este cambio transfiere la responsabilidad del manejo de errores a la función callback en Express 5. Si hay un error, se pasará a la callback como argumento.
Por ejemplo:
const server = app.listen(8080, '0.0.0.0', (error) => { if (error) { throw error; // e.g. EADDRINUSE } console.log(`Listening on ${JSON.stringify(server.address())}`);});app.router
El objeto app.router, que fue eliminado en Express 4, ha regresado en Express 5. En la nueva versión, este objeto es simplemente una referencia al Router base de Express, a diferencia de Express 3, donde una aplicación tenía que cargarlo explícitamente.
req.body
La propiedad req.body devuelve undefined cuando el body no ha sido analizado. En Express 4, devuelve {} por defecto.
app.post('/user', (req, res) => { console.dir(req.body); // Express 4 // => {} // Express 5 // => undefined});req.host
En Express 4, la función req.host eliminaba incorrectamente el número de puerto si estaba presente. En Express 5, el número de puerto se mantiene.
req.params
El objeto req.params ahora tiene un prototipo nulo cuando se usan rutas de cadena. Sin embargo, si la ruta se define con una expresión regular, req.params sigue siendo un objeto estándar con un prototipo normal. Además, hay dos cambios importantes de comportamiento:
Wildcard parameters are now arrays:
Los comodines (por ejemplo, /*splat) capturan segmentos de ruta como un array en lugar de una sola cadena.
app.get('/*splat', (req, res) => { // GET /foo/bar console.dir(req.params); // => [Object: null prototype] { splat: [ 'foo', 'bar' ] }});Unmatched parameters are omitted:
En Express 4, los comodines no coincidentes eran cadenas vacías ('') y los parámetros : opcionales (usando ?) tenían una clave con valor undefined. En Express 5, los parámetros no coincidentes se omiten completamente de req.params.
// v4: unmatched wildcard is empty stringapp.get('/*', (req, res) => { // GET / console.dir(req.params); // => { '0': '' }});
// v4: unmatched optional param is undefinedapp.get('/:file.:ext?', (req, res) => { // GET /image console.dir(req.params); // => { file: 'image', ext: undefined }});
// v5: unmatched optional param is omittedapp.get('/:file{.:ext}', (req, res) => { // GET /image console.dir(req.params); // => [Object: null prototype] { file: 'image' }});req.query
La propiedad req.query ya no es una propiedad escribible y en su lugar es un getter. El parser de consultas por defecto ha cambiado de "extended" a "simple".
app.get('/search', (req, res) => { // This is no longer possible in Express 5 req.query.page = 1;});res.clearCookie
El método res.clearCookie ignora las opciones maxAge y expires proporcionadas por el usuario.
app.get('/logout', (req, res) => { res.clearCookie('session', { maxAge: 0, expires: new Date(0) }); res.clearCookie('session');});res.status
El método res.status solo acepta enteros en el rango de 100 a 999, siguiendo el comportamiento definido por Node.js, y devuelve un error cuando el código de estado no es un entero.
app.get('/user', (req, res) => { res.status(99); // Throws an error res.status(200); // OK});res.vary
res.vary lanza un error cuando falta el argumento field. En Express 4, si se omitía el argumento, mostraba una advertencia en la consola.
app.get('/user', (req, res) => { res.vary(); // Throws an error res.vary('Accept'); // OK});Mejoras
Estos cambios no requieren ningún paso de migración, pero vale la pena conocerlos al actualizar.
res.render()
Este método ahora exige comportamiento asíncrono para todos los motores de vistas, evitando errores causados por motores de vistas que tenían una implementación síncrona y que violaban la interfaz recomendada.
Soporte de codificación Brotli
Middleware como express.json(), express.urlencoded(), express.text(), y express.raw() ahora soportan descompresión Brotli (Content-Encoding: br) para cuerpos de peticiones entrantes, además de gzip y deflate.