Para comprender correctamente todo lo que hablaremos en esta serie, es conveniente tener un conocimiento básico sobre el lenguaje de Ruby. Podrás conseguir toda la información desees aquí
Introducción
La semana pasada vimos una ligera introducción a middleware cuando construíamos un esqueleto de aplicación con estructura similar y muy sencilla a un proyecto de Ruby on Rails. El middleware en este caso lo utilizamos en el archivo config.ru
y lo hicimos para poder indicarle a nuestra aplicación en qué orden y con que nombre es que debe buscar y comparar la solicitud realizada por el usuario dentro de nuestra aplicación; en pocas palabras lo utilizamos para el enrutamiento.
Rack
Ya hemos hablado bastante sobre Rack, y conocemos que Sinatra es un DSL construido en Ruby que va directamente sobre Rack. Para construir aplicaciones modulares y flexibles debemos estar muy claros que tenemos a nuestra disposición el uso de Rack directamente; el cual nos permite realizar enrutamiento y mil cosas más en nuestra aplicación. En este capítulo estaremos enfocados en enrutamiento con middleware y routers utilizando: El encabezado X-Cascade con Rack::Cascade, Middleware con Rack::URLMap o como un Router utilizando Rack::Mount.
A continuación veremos como funciona cada una de estas herramientas.
Deben tomar en cuenta que estamos utilizando la aplicación realizada la semana pasada y por consiguiente no todas las rutas van a funcionar cuando utilicemos Rack::Cascade y Rack::Mount ya que estas dos maneras de enrutamiento tienen control sobre a quien le desean entregar la solicitud y estas rutas no fueron diseñadas para que funcionaran correctamente con todos los métodos.
Rack::Cascade
Rack cascade es un tipo de middleware que realiza lo siguiente: Se le entrega un lista de aplicaciones Rack y cada una de estas se prueba de manera consecutiva, la primera de estas aplicaciones en devolver una respuesta que no sea un código 404 será la que se retorne. A simple vista parece muy normal y realmente es así. Una de las diferencias de usar Rack cascase en vez de middleware como map es que si llegáramos a tener una ruta que devuelve un código 404 y otra ruta que no pero ambas tienen los mismos “slugs” (URL) se devolverá la respuesta que queremos ya que se obvia la ruta con el código 404, cosa que no pasa cuando se usa map.
Cómo funciona Rack::Cascade:
# config.ru run Rack::Cascade.new [ProductsController, UsersController, ApplicationController]12 # config.rurun Rack::Cascadenew[ProductsController,UsersController,ApplicationController]
Muy sencillo creamos un cascade y le entregamos todas nuestras aplicaciones en el orden que deseamos, él se encargará del resto.
Rack::URLMap
Rack URLMap aunque no lo sepan lo hemos estado utilizando con el método map que funciona para definir rutas. El método map es un envoltorio a Rack::URLMap y simplifica un poco la sintaxis de este. En el fondo al utilizar map o Rack::URLMap cada ruta o endpoint es como una pila de middleware separada y nos permite configurar y correr muchas aplicaciones bajo el mismo Rack pero cada una de ellas con su URL personal y con su propio middleware interno.
Como Sinatra en sí es un router, nosotros únicamente debemos definir un endpoint o ruta principal en la pila de middleware, luego cada aplicación individual se encarga de sus rutas internas lo cual nos permite tener una aplicación muy modular.
Basados en el código de la semana pasada haremos el cambio únicamente en el config.ru
y luego agregaremos una nueva ruta.
12345 # config.ru run Rack::URLMapnew({ "/users"=>UsersController, "/"=>ApplicationController})
Luego para agregar cualquier ruta solo basta con agregar un “slug” como “/products” y conocer el nombre de su controlador.
run Rack::URLMap.new({ "/users" => UsersController, "/products" => ProductsController, "/" => ApplicationController })12345 run Rack::URLMapnew({ "/users"=>UsersController, "/products"=>ProductsController, "/"=>ApplicationController})
Si hacen la prueba utilizando su navegador web o utilizando curl
de la misma manera que la semana pasada se darán cuenta que funciona igual.
Rack::Mount
Rack Mount es un router. Los rotures reciben la solicitud y deciden a quien se la van a entregar, esto puede aumentar la flexibilidad con la que escribimos las rutas de nuestra aplicación pero a su vez la complejidad de las mismas. Por otra parte Rack::Mount no viene integrada directamente en rack, sino más bien es una gema aparte que debe ser instalada gen isntall rack-mount
.
12345678 # config.ruRoutes=Rack::Mount::RouteSetnew do|set| setadd_route UsersController,{:request_method=>'GET',:path_info=>%r{^/users$}} setadd_route ProductsController,{:request_method=>'GET',:path_info=>%r{^/products$}} setadd_route ApplicationController,{:request_method=>'GET',:path_info=>%r{^/$}}end run Routes
Según tengo entendido Rack mount no fue diseñada para uso directo si no más bien para uso de otras librerías, por consiguiente creo que no es algo muy popular.
Rack::Mount utilizando Sinatra
Utilizando únicamente Sinatra también podemos implementar un Rack Router de la siguiente manera.
# routes.rb class Routes < ApplicationController get('/users') { UsersController.call(env) } get('/products') { ProductsController.call(env) } end12345 # routes.rbclassRoutes<ApplicationController get('/users'){UsersControllercall(env)} get('/products'){ProductsControllercall(env)}end
Se debe crear un archivo para manejo de rutas de la manera descrita para luego invocar use Routes
bien sea desde el config.ru o desde la aplicación sinatra.
Las diferencias entre un middleware y un router tales como Cascade o Mount son difíciles de percibir pero principalmente middleware se encuentra atado a una sola ruta (endpoint) específico y un router no. Podemos decir que el router conoce todas las rutas y él decide cual usar basándose en el criterio de la solicitud.
Conclusión
En este noveno capítulo, hemos visto como funcionan las distintas posibilidades que nos entrega Rack a la hora de decidir por un enrutamiento. A mi parecer la manera más útil para realizarlo es mediante map o Rack::URLMap ya que es probable que sea la manera más común y sencilla de utilizar cuando decidimos desarrollar de forma modular una aplicación. Si te surge algún tipo de duda no te detengas y déjanos un comentario, que gustosamente lo responderemos.
¡Hasta el próximo capítulo!