Definiendo nuestras rutas con NancyFx
Una vez que ya hemos aprendido a hacer nuestra primera API REST con NancyFx, y una vez que también hemos aprendido a usar llamadas asíncronas en nuestras API REST, vamos a dar un paso adelante, y vamos a ver como trabajar con las rutas o patrones dentro de NancyFx.
A modo recordatorio, conviene refrescar que cuando hablamos de rutas, éstas serán definidas en el constructor del módulo de la forma Method + Pattern + Action + Condition (optional).
Las rutas las podremos definir siguiendo un patrón.
Aquí NancyFx nos proporciona una versatilidad muy amplia, pudiendo establecer dicho patrón de diferentes maneras para cubrir nuestras necesidades.
De esta manera y a modo resumen, podremos asignar los siguientes patrones:
- Segmentos literales, con un patrón concreto some/literal/segments
- Capturar segmentos, encargado de capturar lo que pasemos /{name}
- Capturar segmentos opcionales, siendo el segmento opcional /{name?}
- Capturar segmentos opcionales y con valor por defecto, /{name?unnamed}/
- Aplicar una expresión regulada a un segmento, /(?<age>[\d]{1,2})
- Segmento codicioso (no se bien como traducir esto), permitirá obtener cualquiere elemento detrás del indicado /{name*}
- Segmento codicioso con expresión regulada, ^(?<name>[a-z]{3,10}(?:/{1})(?<action>[a-z]{5,10}))$
- Capturar múltiples segmentos, /{file}.{extension}
Si tienes dudas sobre cómo definir los patrones en NancyFx, podrás obtener más información en la Wiki oficial de NancyFx.
Para entender esto mejor, lo mejor es practicar y verlo con un ejemplo de código.
Supongamos el siguiente módulo, que utilizará una expresión regulada a un segmento, precisamente utilizando el que aparece en la documentación de NancyFx y que he puesto más arriba:
namespace WebAppNancyFxPatterns.Modules { using System.Threading; using System.Threading.Tasks; public class PersonModule : Nancy.NancyModule { public PersonModule() { Get[@"/person/(?<age>[\d]{1,2})", runAsync: true] = async (parameters, cancellationToken) => { return await GetAgeAsync(parameters.age, cancellationToken); }; } private async Task<string> GetAgeAsync(int age, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return await Task.FromResult(age.ToString()); } } }
El ejemplo es muy sencillo.
Básicamente espera que hagamos una llamada GET a /person/{age} siendo age un valor entero de una o dos cifras.
De hecho, nuestro ejemplo en ejecución se mostrará de la siguiente manera:
Si por cualquier caso, nos confundiéramos en la URL y pusiéramos por ejemplo:
/person/a
NancyFx nos devolvería un error:
Ahora bien, si en lugar de un valor no numérico (como espera), pusiéramos un valor numérico pero más alto del esperado (valor numérico de 1 a 2 dígitos), NancyFx entenderá el valor como válido, pero como sólo espera de 1 a 2 dígitos, si por ejemplo ponemos:
/persona/321
En realidad, NancyFx truncará la entrada numérica a los dígitos esperados en la expresión regulada, es decir, el valor 321 pasado lo truncará admitiendo solamente los dos primeros dígitos.
Ahora bien, dentro de nuestro módulo, podemos definir todos los verbos y patrones que consideremos oportuno, teniendo en cuenta que debemos mantener un orden lógico a la hora de establecer las rutas a las que respondes.
Así que a modo de ejemplo, veremos un patrón más dentro de nuestro módulo.
Nuestro módulo quedará ahora de la siguiente manera:
namespace WebAppNancyFxPatterns.Modules { using System.Threading; using System.Threading.Tasks; public class PersonModule : Nancy.NancyModule { public PersonModule() { Get[@"/person/(?<age>[\d]{1,2})", runAsync: true] = async (parameters, cancellationToken) => { return await GetAgeAsync(parameters.age, cancellationToken); }; Get[@"/person/name/{name}", runAsync: true] = async (parameters, cancellationToken) => { return await GetNameAsync(parameters.name, cancellationToken); }; } private async Task<string> GetAgeAsync(int age, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return await Task.FromResult(age.ToString()); } private async Task<string> GetNameAsync(string name, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return await Task.FromResult($"Hi {name.ToUpper()}"); } } }
Nuestro ejemplo, respondiendo al nuevo patrón incorporado, quedará de la siguiente forma:
Como podemos apreciar, el uso de patrones en NancyFx es muy sencillo.
De igual manera y como es lógico, podemos utilizar no sólo el verbo GET que hemos usado en estos ejemplos, sino también otros verbos diferentes según nuestras necesidades.
¡Happy Coding!