Router
Un objeto router es una instancia de middleware y rutas. Puedes pensar en él
como una “mini-aplicación,” capaz solo de realizar funciones de middleware y enrutamiento.
Cada aplicación Express tiene un router de aplicación integrado.
Un router se comporta como middleware en sí mismo, así que puedes usarlo como argumento de app.use() o como argumento del método use() de otro router.
El objeto express de nivel superior tiene un método Router() que crea un nuevo objeto router.
Una vez que has creado un objeto router, puedes añadir middleware y rutas de métodos HTTP (como get, put, post,
etc.) a él igual que en una aplicación. Por ejemplo:
// invoked for any requests passed to this routerrouter.use((req, res, next) => { // .. some logic here .. like any other middleware next();});
// will handle any request that ends in /events// depends on where the router is "use()'d"router.get('/events', (req, res, next) => { // ..});Puedes entonces usar un router para una URL raíz particular de esta forma, separando tus rutas en archivos o incluso mini-aplicaciones.
// only requests to /calendar/* will be sent to our "router"app.use('/calendar', router);Métodos
Router()
Argumentos
options Opciones que configuran el comportamiento del router.
caseSensitive Activa la sensibilidad a mayúsculas/minúsculas. Desactivado por defecto, tratando /Foo y /foo como iguales.
mergeParams Preserva los valores de req.params del router padre. Si el padre y el hijo tienen nombres de parámetros en conflicto, el valor del hijo tiene prioridad.
strict Habilita el enrutamiento estricto. Deshabilitado por defecto, /foo y /foo/ son tratados de la misma manera por el router.
Crea un nuevo objeto router.
const express = require('express');const router = express.Router({ caseSensitive: true, strict: true });
router.get('/events', (req, res) => { res.send('events');});
// mount the router on an appapp.use('/calendar', router);import express from 'express';
const router = express.Router({ caseSensitive: true, strict: true });
router.get('/events', (req, res) => { res.send('events');});
// mount the router on an appapp.use('/calendar', router);router.all()
Argumentos
path La ruta para la cual se invocan los callbacks de ruta.
callback Una o más funciones middleware/manejadoras. Cada una puede llamar a next('route') para saltar los callbacks restantes.
Este método es igual a los métodos router.METHOD(), excepto que coincide con todos los métodos HTTP (verbos).
Este método es extremadamente útil para
mapear lógica “global” para prefijos de ruta específicos o coincidencias arbitrarias.
Por ejemplo, si colocaras la siguiente ruta al principio de todas las demás
definiciones de rutas, requeriría que todas las rutas a partir de ese punto
requirieran autenticación, y cargaría automáticamente un usuario. Ten en cuenta
que estos callbacks no tienen que actuar como puntos finales; loadUser
puede realizar una tarea, luego llamar a next() para continuar coincidiendo con las rutas
subsiguientes.
router.all('{*splat}', requireAuthentication, loadUser);O el equivalente:
router.all('{*splat}', requireAuthentication);router.all('{*splat}', loadUser);Otro ejemplo de esto es la funcionalidad “global” con lista blanca. Aquí, el ejemplo es muy similar al anterior, pero solo restringe las rutas con el prefijo “/api”:
router.all('/api/{*splat}', requireAuthentication);router.METHOD()
Argumentos
path La ruta para la cual se invocan los callbacks de ruta.
callback Una o más funciones middleware/manejadoras. Cada una puede llamar a next('route') para saltar los callbacks restantes.
Los métodos router.METHOD() proporcionan la funcionalidad de enrutamiento en Express,
donde METHOD es uno de los métodos HTTP, como GET, PUT, POST, etc.,
en minúsculas. Por lo tanto, los métodos reales son router.get(), router.post(),
router.put(), etc.
Nota
La función router.get() se llama automáticamente para el método HTTP HEAD además del
método GET si router.head() no fue llamado para la ruta antes de router.get().
Nota
router.query() enruta peticiones HTTP QUERY, reflejando app.query(). El método QUERY está controlado por el runtime y requiere Node.js >=20.19.3 <21 || >=22.2.0.
Puedes proporcionar múltiples callbacks, y todos son tratados por igual, y se comportan
como middleware, excepto que estos callbacks pueden invocar next('route')
para omitir los callbacks de ruta restantes. Puedes usar este mecanismo para realizar
pre-condiciones en una ruta y luego pasar el control a las rutas subsiguientes cuando no haya
razón para continuar con la ruta coincidente.
El siguiente fragmento ilustra la definición de ruta más simple posible. Express traduce los strings de ruta a expresiones regulares, usadas internamente para coincidir con las peticiones entrantes. Los query strings no se consideran al realizar estas coincidencias, por ejemplo “GET /” coincidiría con la siguiente ruta, al igual que “GET /?name=tobi”.
router.get('/', (req, res) => { res.send('hello world');});También puedes usar expresiones regulares — útil si tienes restricciones muy específicas, por ejemplo lo siguiente coincidiría con “GET /commits/71dbb9c” así como con “GET /commits/71dbb9c..4c084f9”.
router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, (req, res) => { const from = req.params[0]; const to = req.params[1] || 'HEAD'; res.send(`commit range ${from}..${to}`);});Puedes usar la primitiva next para implementar un control de flujo entre diferentes
funciones de middleware, basándose en un estado específico del programa. Invocar next con
el string 'router' causará que todos los callbacks de ruta restantes en ese router
sean omitidos.
El siguiente ejemplo ilustra el uso de next('router').
function fn(req, res, next) { console.log('I come here'); next('router');}router.get('/foo', fn, (req, res, next) => { console.log("I don't come here");});router.get('/foo', (req, res, next) => { console.log("I don't come here");});app.get('/foo', (req, res) => { console.log(' I come here too'); res.end('good');});router.param()
Argumentos
name El nombre del parámetro de ruta al que adjuntar el trigger. A diferencia de app.param(), esto no
acepta un array.
callback El trigger llamado como callback(req, res, next, value, name).
Añade disparadores de callback a los parámetros de ruta, donde name es el nombre del parámetro y callback es la función de callback. El parámetro name es obligatorio.
Los parámetros de la función de callback son:
req, el objeto de petición.res, el objeto de respuesta.next, indicando la siguiente función middleware.- El valor del parámetro
name. - El nombre del parámetro.
Nota
A diferencia de app.param(), router.param() no acepta un array de parámetros de ruta.
Por ejemplo, cuando :user está presente en una ruta, puedes mapear lógica de carga de usuario para proporcionar automáticamente req.user a la ruta, o realizar validaciones sobre la entrada del parámetro.
router.param('user', (req, res, next, id) => { // try to get the user details from the User model and attach it to the request object User.find(id, (err, user) => { if (err) { next(err); } else if (user) { req.user = user; next(); } else { next(new Error('failed to load user')); } });});Las funciones de callback de parámetros son locales al router en el que se definen. No son heredadas por apps o routers montados, ni se activan para parámetros de ruta heredados de routers padre. Por lo tanto, los callbacks de parámetros definidos en router solo se activarán por parámetros de ruta definidos en las rutas de router.
Un callback de parámetro se llamará solo una vez en un ciclo petición-respuesta, incluso si el parámetro coincide en múltiples rutas, como se muestra en los siguientes ejemplos.
router.param('id', (req, res, next, id) => { console.log('CALLED ONLY ONCE'); next();});
router.get('/user/:id', (req, res, next) => { console.log('although this matches'); next();});
router.get('/user/:id', (req, res) => { console.log('and this matches too'); res.end();});En GET /user/42, se imprime lo siguiente:
CALLED ONLY ONCEalthough this matchesand this matches toorouter.route()
Argumentos
path La ruta de la ruta a crear.
Devuelve una instancia de una sola ruta que puedes usar luego para manejar verbos HTTP
con middleware opcional. Usa router.route() para evitar la duplicación de nombres de ruta y
así errores de escritura.
Basándose en el ejemplo de router.param() anterior, el siguiente código muestra cómo usar
router.route() para especificar varios manejadores de métodos HTTP.
const router = express.Router();
router.param('user_id', (req, res, next, id) => { // sample user, would actually fetch from DB, etc... req.user = { id, name: 'TJ', }; next();});
router .route('/users/:user_id') .all((req, res, next) => { // runs for all HTTP verbs first // think of it as route specific middleware! next(); }) .get((req, res, next) => { res.json(req.user); }) .put((req, res, next) => { // just an example of maybe updating the user req.user.name = req.params.name; // save user ... etc res.json(req.user); }) .post((req, res, next) => { next(new Error('not implemented')); }) .delete((req, res, next) => { next(new Error('not implemented')); });Este enfoque reutiliza la única ruta /users/:user_id y añade manejadores para
varios métodos HTTP.
Nota
Cuando usas router.route(), el orden del middleware se basa en cuándo se crea la route, no
en cuándo se añaden los manejadores de método a la ruta. Para este propósito, puedes considerar que los manejadores de método
pertenecen a la ruta a la que fueron añadidos.
router.use()
Argumentos
path La ruta de montaje para el middleware. Por defecto es /.
callback Una o más funciones middleware a montar.
Usa la función o funciones middleware especificadas, con ruta de montaje opcional path, que por defecto es ”/”.
Este método es similar a app.use(). Un ejemplo simple y caso de uso se describe abajo. Consulta app.use() para más información.
El middleware es como una tubería de plomería: las peticiones empiezan en la primera función middleware definida y van bajando por la pila de middleware procesando cada ruta que coinciden.
const express = require('express');const app = express();const router = express.Router();
// simple logger for this router's requests// all requests to this router will first hit this middlewarerouter.use((req, res, next) => { console.log('%s %s %s', req.method, req.url, req.path); next();});
// this will only be invoked if the path starts with /bar from the mount pointrouter.use('/bar', (req, res, next) => { // ... maybe some additional /bar logging ... next();});
// always invokedrouter.use((req, res, next) => { res.send('Hello World');});
app.use('/foo', router);
app.listen(3000);import express from 'express';
const app = express();const router = express.Router();
// simple logger for this router's requests// all requests to this router will first hit this middlewarerouter.use((req, res, next) => { console.log('%s %s %s', req.method, req.url, req.path); next();});
// this will only be invoked if the path starts with /bar from the mount pointrouter.use('/bar', (req, res, next) => { // ... maybe some additional /bar logging ... next();});
// always invokedrouter.use((req, res, next) => { res.send('Hello World');});
app.use('/foo', router);
app.listen(3000);La ruta de “montaje” se elimina y no es visible para la función middleware. El efecto principal de esta característica es que una función middleware montada puede operar sin cambios de código independientemente de su nombre de ruta de “prefijo”.
El orden en que defines middleware con router.use() es muy importante.
Se invocan secuencialmente, por lo tanto el orden define la precedencia del middleware. Por ejemplo,
normalmente un logger es el primer middleware que usarías, para que cada petición quede registrada.
const logger = require('morgan');
router.use(logger());router.use(express.static(path.join(__dirname, 'public')));router.use((req, res) => { res.send('Hello');});import logger from 'morgan';
router.use(logger());router.use(express.static(path.join(__dirname, 'public')));router.use((req, res) => { res.send('Hello');});Ahora supón que quisieras ignorar el registro de peticiones para archivos estáticos, pero continuar
registrando rutas y middleware definidos después de logger(). Simplemente moverías la llamada a express.static() al principio,
antes de añadir el middleware logger:
router.use(express.static(path.join(__dirname, 'public')));router.use(logger());router.use((req, res) => { res.send('Hello');});Otro ejemplo es servir archivos desde múltiples directorios, dando precedencia a ”./public” sobre los demás:
app.use(express.static(path.join(__dirname, 'public')));app.use(express.static(path.join(__dirname, 'files')));app.use(express.static(path.join(__dirname, 'uploads')));El método router.use() también soporta parámetros nombrados para que tus puntos de montaje
para otros routers puedan beneficiarse de la precarga usando parámetros nombrados.
Nota
Aunque estas funciones middleware se añaden vía un router particular, cuándo se ejecutan se define por la ruta a la que están adjuntas (no el router). Por lo tanto, el middleware añadido vía un router puede ejecutarse para otros routers si sus rutas coinciden.
Por ejemplo, este código muestra dos routers diferentes montados en la misma ruta:
const authRouter = express.Router();const openRouter = express.Router();
authRouter.use(require('./authenticate').basic(usersdb));
authRouter.get('/:user_id/edit', (req, res, next) => { // ... Edit user UI ...});openRouter.get('/', (req, res, next) => { // ... List users ...});openRouter.get('/:user_id', (req, res, next) => { // ... View user ...});
app.use('/users', authRouter);app.use('/users', openRouter);A pesar de que el middleware de autenticación se añadió vía el authRouter se ejecutará también en las rutas definidas por el openRouter ya que ambos routers estaban montados en /users. Para evitar este comportamiento, usa rutas diferentes para cada router.