Cuando trabajamos con Elixir y sus frameworks web como Plug y Phoenix, uno de los aspectos fundamentales es el manejo de rutas dinámicas. Aunque en este caso nos centraremos en Plug, todo lo que veremos es aplicable a Phoenix, ya que este último utiliza Plug internamente para gestionar las rutas.
Al iniciar un servidor web con Plug, este se encarga de comparar la ruta que visitamos con las rutas que hemos declarado en nuestro router. Por ejemplo, si tenemos una ruta definida como get "/saludar", al visitar esa URL se ejecutará el código asociado. Si añadimos otra ruta como get "/saludar/Dani", esta se activará cuando accedamos a esa ruta específica.
Sin embargo, si queremos manejar saludos personalizados para muchas personas, no es práctico definir una ruta para cada nombre. Aquí es donde entran en juego las rutas dinámicas. Podemos definir una ruta con un parámetro dinámico usando el símbolo dos puntos : seguido del nombre de la variable que queremos capturar. Por ejemplo, la ruta get "/saludar/:persona" capturará cualquier valor que venga después de /saludar/ y lo almacenará en la variable persona.
Esto funciona de manera similar al pattern matching que conocemos en Elixir, pero aplicado a las cadenas de texto que forman las rutas. Así, si visitamos /saludar/paula, la variable persona tendrá el valor "paula". Lo interesante es que esta variable puede contener cualquier cadena que no incluya una barra /, por lo que nombres con números, puntos o guiones también serán capturados sin problema.
Además, podemos definir rutas con múltiples parámetros dinámicos. Por ejemplo, una ruta como /api/v1/empleados/:nombre/ofertas/:id capturará tanto el nombre del empleado como el id de la oferta. Es importante recordar que, aunque el parámetro id pueda representar un número, siempre se capturará como una cadena, por lo que si necesitamos trabajar con él como número, deberemos convertirlo explícitamente.
También podemos combinar variables dinámicas con prefijos o sufijos en la ruta. Por ejemplo, si queremos capturar la versión de una API que siempre empieza con una v, podemos definir la ruta como /api/v:version, donde version capturará el número o cadena que siga a la v. Esto nos permite validar que la ruta tenga un formato específico, ya que si el prefijo no coincide, la ruta no será considerada válida.
En cuanto a sufijos, podemos hacer algo similar. Por ejemplo, si definimos una ruta como /saludar/:persona.gritar, podemos capturar la variable persona siempre que la ruta termine con .gritar. Esto nos permite aplicar transformaciones específicas, como convertir el saludo a mayúsculas. Sin embargo, hay que tener en cuenta que el orden en que definimos las rutas es crucial. Las rutas más específicas deben ir antes que las más generales para que el sistema de matching funcione correctamente y no se ejecute una ruta menos específica antes que la que realmente queremos.
Finalmente, existe una forma de capturar rutas completas o globs usando el operador asterisco *. Por ejemplo, si definimos una ruta como /hola/*todo, la variable todo capturará todos los segmentos restantes de la ruta como una lista de cadenas. Esto es especialmente útil cuando queremos manejar rutas con una estructura variable o anidada, como directorios y archivos en un sistema de archivos virtual.
Este mecanismo nos permite construir aplicaciones web muy flexibles, donde podemos capturar y procesar rutas dinámicas con parámetros, prefijos, sufijos y rutas completas, todo ello manteniendo un código limpio y organizado. Además, dado que Phoenix utiliza Plug para el manejo de rutas, todo lo que hemos visto es directamente aplicable en ese framework, permitiéndonos definir rutas dinámicas que se dirijan a controladores o que hagan forwards a otros módulos según nuestras necesidades.