Este artículo continúa la serie de introducción a Nancy, un framework para aplicaciones web escrito en C#. En el artículo anterior (Primer contacto con NancyFX) hacíamos una breve introducción a la sintaxis, y veíamos un ejemplo muy básico de rutas. En este veremos con un poco más de detalle qué es un módulo, cómo funciona el sistema de rutas, cómo definirlas, y qué tipo de respuestas podemos dar.
Módulos
using System; namespace NancyFxSinatra { public class SampleModule : Nancy.NancyModule { public SampleModule() { Get["/"] = _ => "Hello World!"; } } }
En el artículo anterior mostrábamos el siguiente código. Las rutas están definidas en el constructor de un módulo, que es a su vez la pieza clave que define el comportamiento de nuestra aplicación.
Un módulo hereda de la clase NancyModule y se puede definir en cualquier parte de la aplicación. No es necesario declararlos explícitamente ya que Nancy se encargará de buscarlos por nosotros. Esta búsqueda se realiza al iniciar la aplicación, quedando en caché una vez encontrados.
Esto nos permitiría, en una hipotética aplicación de gestión tener nuestro ProductModule, que gestionara productos, y nuestro CategoriesModule que gestionara categorías. Los módulos pueden encontrarse en diferentes carpetas, o incluso en diferentes ensamblados.
Rutas
Todos los caminos conducen a Roma
Una ruta se compone por:
Método + Patrón + Acción.
Método
El método es el verbo HTTP por el que accedemos a un recurso. A continuación podemos ver un ejemplo de acceso a diferentes recursos con el mismo patrón.
using System; namespace NancyFxSinatra { public class Routes : Nancy.NancyModule { public Routes () { Get["/routes"] = _ => "Respuesta usando GET\n"; Post["/routes"] = _ => "Respuesta usando POST\n"; } } }
Para probarlo en este caso usaremos la línea de comandos y la utilidad curl, que permite hacer peticiones a una pagina, y devuelve el resultado. Se encuentra disponible para Mac y Linux de manera nativa, y para Windows lo podemos obtener de su página oficial.
Si queremos probar la llamada por GET, usamos el comando:
curl -X GET http://127.0.0.1:8080/routes
Y la salida que obtendremos será:
Respuesta usando GET
Por otra parte, si queremos probar la llamada por POST, el comando será:
curl -X POST http://127.0.0.1:8080/routes
Con la correspondiente salida:
Respuesta usando POST
Así podemos probar el resto de métodos HTTP soportados, que son GET, POST, PUT, DELETE, PATCH, HEAD y OPTIONS.
Patrón
El patrón, por su parte, nos permite detectar una url específica, así como capturar elementos. Podemos destacar los siguiente patrones:
- «/users»: Detecta la coincidencia exacta.
- «/users/{id}»: Al caso anterior, captura además cualquier elemento que se pase a continuación. En el caso de «/users/roberto», id tendría el valor de roberto.
- «/users/{id}/{format?}»: Además de lo anterior, detecta una ruta que puede contener, o no ese valor. En el caso de «/users/roberto/json», format tendría el valor de json. Si por lo contrario usamos una ruta de «/users/roberto» también será capturada, ya que el parámetro es opcional.
- «users/{cur*}»: A diferencia del anterior, solamente detecta y captura entradas que comiencen por cur, por lo tanto «/users/roberto» no sería detectado, pero «/users/cur1239» sí.
Podemos encadenar patrones como hemos visto antes para crear rutas más complejas, y usar expresiones regulares para una captura más específica.
Acción
Las acciones son el contenido de nuestra llamada, es decir, el resultado de la misma, es de tipo Response, sin embargo, según la respuesta del método se puede devolver:
- entero: Se interpreta entonces como código de estado HTTP (ejemplo, 404).
- HttpStatusCode: Código de respuesta incluido en Nancy, que corresponde también a estados HTTP.
- texto: Interpretado como el cuerpo de la respuesta.
Para demostrarlo, veamos 4 tipos de respuesta, las 3 primeras son las que hemos mostrado, mientras que la última devuelve un error y además de una respuesta en el cuerpo.
Get ["/actions/ok"] = _ => 202; Get ["/actions/auth"] = _ => HttpStatusCode.Forbidden; Get ["/actions/text"] = _ => "Hola Mundo";Get["/actions/error"] = _ => { Response res = ((Response)"Error con mensaje\n"); res.StatusCode = HttpStatusCode.InternalServerError; return res; };
Usando curl (con la opción -v para que muestre también las cabeceras) podemos comprobar que el resultado de la petición corresponde con los códigos que hemos mostrado.
Resumen
En este artículo hemos visto qué son los módulos, cómo, usando comandos HTTP, podemos especificar la manera para acceder a un recurso. Hemos visto también, cómo capturar rutas específicas o que cumplan con algún criterio, y finalmente, hemos devuelto mensajes HTTP usando números y enumerados. En el próximo artículo veremos cómo usar ViewEngines y plantillas HTML para contenido.
Más información:
- Documentación de NancyFx: Defining routes
- W3C.org: HTTP Methods
- Un artículo interesante de curl: Http from the command line