Saltar al contenido

Rutas catch-all con [...rest]

Cuando un solo segmento no basta: el operador de propagación en el nombre del fichero captura cero, uno o muchos tramos de la URL en un único parámetro. Cómo la cola llega como una cadena con barras, cómo trocearla para migas de pan, y qué reglas de precedencia deciden quién atiende una URL cuando varias podrían.

Los tres puntos: de un segmento a una cola entera

La diferencia entre [slug] y [...ruta] es la diferencia entre uno y muchos. src/pages/blog/[slug].astro casa con /blog/algo —un solo tramo— y no con /blog/algo/mas. En cambio src/pages/docs/[...ruta].astro casa con /docs, con /docs/guia, con /docs/guia/instalacion y con cualquier profundidad que le eches: el ... significa desde aquí, todo lo que venga.

TXT
src/pages/docs/[...ruta].astro  casa con:  /docs                    ->  ruta = undefined  /docs/guia               ->  ruta = "guia"  /docs/guia/instalacion   ->  ruta = "guia/instalacion"  /docs/api/v2/errores     ->  ruta = "api/v2/errores"

El nombre después de los puntos —ruta, rest, slug— vuelve a ser tu elección, y es la clave con la que leerás el valor. Lo que cambia radicalmente es lo que captura: no un tramo, sino la concatenación de todos los tramos restantes, unidos por las mismas barras que los separaban en la URL. Un [...rest] es, en esencia, una esponja que absorbe el resto del camino.

La diferencia de aridad frente a un corchete normal conviene tenerla nítida:

  • [slug] casa con exactamente un segmento: /blog/a sí, /blog/a/b no.
  • [...rest] casa con cero o más segmentos: /docs, /docs/a, /docs/a/b/c, todos.
  • Un [slug] entrega un valor atómico; un [...rest] entrega una cadena que tú decides cómo trocear.

La cola entera en un parámetro: leerla y trocearla

Dentro del fichero, la cola capturada vive en Astro.params bajo el nombre que elegiste, igual que cualquier parámetro. La diferencia es su contenido: una cadena que puede contener barras. Para /docs/guia/instalacion, Astro.params.ruta es la cadena "guia/instalacion" —un texto con una barra dentro—, no tres valores separados.

ASTRO
---// src/pages/docs/[...ruta].astroconst { ruta } = Astro.params;const segmentos = ruta?.split('/') ?? [];---<nav aria-label="migas">  {segmentos.map((seg, i) => (    <span>{seg}{i < segmentos.length - 1 ? ' / ' : ''}</span>  ))}</nav>

Ese split('/') es el gesto clave del patrón: reconvierte la cola aplanada en el array de tramos que la componía, y con ese array construyes lo que necesites. Las migas de pan son el caso canónico —cada segmento es un eslabón del rastro que llevó al visitante hasta aquí—, pero el mismo troceo sirve para resolver a qué documento apunta la ruta, para resaltar la sección activa en un menú lateral o para reconstruir enlaces acumulando prefijos. La cola es un dato compacto; trocearla es recuperar su estructura.

Fíjate en la asimetría con [slug]. Un parámetro normal te da un valor atómico ya listo para usar; un catch-all te da una cadena estructurada que casi siempre querrás descomponer. Es más potente porque captura una jerarquía entera, y por eso mismo exige un paso extra de interpretación: la potencia y el trabajo de troceo van de la mano.

Enumerar en el build, y quién gana cuando varias rutas casan

En modo estático, un catch-all sigue necesitando getStaticPaths, con una particularidad: los valores que devuelves para el parámetro pueden contener barras, porque representan una cola de varios segmentos. Enumeras rutas completas, no tramos sueltos.

ASTRO
---export async function getStaticPaths() {  return [    { params: { ruta: undefined } },        // la raiz, /docs    { params: { ruta: 'guia' } },            // /docs/guia    { params: { ruta: 'guia/instalacion' } },// /docs/guia/instalacion  ];}---

Aquí surge una pregunta inevitable: si un catch-all casa con todo lo que cuelga de /docs, ¿qué pasa cuando también existe una ruta más específica, como src/pages/docs/guia.astro? Astro resuelve el conflicto con una regla de precedencia: lo más específico gana. Una ruta totalmente estática vence a una con un [param], y una con [param] vence a un [...rest]. El catch-all es la última red, el que atiende solo lo que ninguna ruta más concreta reclamó.

El orden de preferencia, de mayor a menor especificidad, es fácil de recordar:

  • Rutas totalmente estáticas —docs/guia.astro—, lo más concreto y lo primero en ganar.
  • Rutas con un segmento dinámico —docs/[pagina].astro—, en el medio.
  • Rutas catch-all —docs/[...ruta].astro—, la red final que recoge lo demás.

Con este orden puedes componer sin miedo lo general y lo particular en la misma carpeta: la ruta específica se antepone a su caso concreto, y el comodín recoge todo lo que nadie más reclamó. No compiten al azar; hay una jerarquía determinista que razonas de antemano.

Esa jerarquía de precedencia es lo que permite mezclar sin miedo lo general y lo particular. Puedes tener un [...ruta].astro cubriendo un árbol entero y, a la vez, un fichero estático para una página de ese árbol que merece un trato distinto: la específica se antepone, el resto cae en el comodín. No compiten al azar; hay un orden determinista que puedes razonar de antemano.