Menu

Rutas en Express y express.Router: parámetros y prefijos

Una ruta en Express es un método, una ruta y un handler: app.get('/users/:id', handler). Agrupa las rutas relacionadas en un express.Router() y móntalo bajo un prefijo con app.use('/api', router).

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

El routing en Express asocia un método HTTP y una ruta a una función handler: app.get('/users', handler) responde a las peticiones GET a /users, y app.post(), app.put() y app.delete() hacen lo mismo para los otros métodos. Un segmento que empieza por dos puntos, como en /users/:id, es un parámetro de ruta cuyo valor acaba en req.params. Para mantener ordenada una app que crece, pon las rutas relacionadas en un express.Router() y móntalo bajo un prefijo con app.use('/api', router).

GET /users/2 responde {"id":2,"name":"Linus"}. Los parámetros de ruta siempre son strings, por eso el handler compara con Number(req.params.id). Envía POST /users con el body {"name": "Grace"} para obtener 201, y luego DELETE /users/1 y GET /users para ver cómo cambia la lista.

express.Router() con un prefijo

Un router es una mini app con sus propias rutas y middleware. Sus rutas son relativas: una ruta escrita como /:id dentro de un router montado en /api/books responde a /api/books/:id. En un proyecto real cada router vive en su propio archivo y termina con module.exports = router.

GET /api/books/1 devuelve {"id":1,"title":"Dune"}. router.route('/:id') escribe la ruta una sola vez y encadena un handler por método; envía PUT /api/books/1 y obtienes {"updated":"1"}. Cambia la ruta de montaje a /v2/books y el mismo router responde ahí.

El orden de las rutas: gana la primera que coincide

Express prueba las rutas en el orden en que las registras y se detiene en la primera que envía una respuesta. Una ruta con parámetro captura cualquier cosa en esa posición, así que una ruta fija registrada después nunca se alcanza:

GET /users/new responde {"route":"/users/:id","id":"new"}: la ruta con parámetro se registró primero y se la quedó. Sube la ruta /users/new por encima de /users/:id y vuelve a ejecutar para obtener {"route":"/users/new"}. Luego envía GET /books para llegar al handler 404 del final.

El handler 404

Express responde a una petición que no coincide con ninguna ruta con su propia página HTML, Cannot GET /books. En una API normalmente quieres JSON, así que añade un app.use() sin ruta como última ruta de todas, como en el bloque de arriba. Solo se ejecuta cuando todas las rutas anteriores han dejado pasar la petición. Los errores que lanzan los handlers son otro caso, con su propio handler de cuatro argumentos, explicado en manejo de errores en Express.

Rutas en Express 5

Express 5 cambió la sintaxis de las rutas, y la mayoría de los ejemplos que hay por internet están escritos para Express 4:

PatrónExpress 4Express 5
Cualquier rutaapp.get('*', fn)app.get('/*splat', fn)
Parámetro opcional/users/:id?/users{/:id}
Patrón en un parámetro/users/:id(\\d+)No soportado; comprueba el valor en el handler

Un * suelto o un ? después de un parámetro lanza un TypeError al registrar la ruta, así que la app no arranca.

Errores comunes

Registrar el handler 404 primero. app.use() sin ruta coincide con todo, así que todas las peticiones reciben el 404. Déjalo al final.

Olvidar que el prefijo se elimina. Dentro de un router montado en /api, req.path no incluye /api. Usa req.originalUrl cuando necesites la ruta completa.

Comparar un parámetro con un número. req.params.id === 1 siempre es false porque req.params.id es el string '1'.

Preguntas frecuentes

¿Qué diferencia hay entre app.use y app.get?

app.get('/users', fn) ejecuta fn solo para peticiones GET cuya ruta es exactamente /users. app.use('/users', fn) se ejecuta para cualquier método y cualquier ruta que empiece por /users, y por eso se usa para montar routers y middleware.

¿Cómo hago que las rutas de Express distingan mayúsculas?

Las rutas ignoran las mayúsculas por defecto, así que /Users coincide con /users. Desactívalo con app.set('case sensitive routing', true), o por router con express.Router({ caseSensitive: true }).

¿Por qué req.params está vacío dentro de un router anidado?

Un router solo ve los parámetros de sus propias rutas. Si está montado en /users/:userId/posts, créalo con express.Router({ mergeParams: true }) para que req.params.userId de la ruta padre esté disponible.

¿Pongo todas las rutas en un archivo?

No cuando ya tienes más de unas pocas. Crea un router por recurso (routes/users.js, routes/orders.js), expórtalo con module.exports = router y monta cada uno en el archivo principal con app.use().

Ilustración de los lenguajes de programación de Coddy

Aprende a programar con Coddy

Comenzar