Dificultad: Heroe
Duración: 30 min
La serie de Sinatra desde Cero, buscará otorgarte el conocimiento necesario para que puedas desarrollar tus propias aplicaciones Web haciendo uso de esta magnifica herramienta.
En este quinceavo capítulo culminaremos la etapa final de nuestra serie, Sinatra desde Cero. Hablaremos de los controladores y modelos de nuestro API que conforman la lógica de nuestra aplicación y terminaremos de unificar gran parte de los conocimientos que hemos visto a lo largo de esta serie, además de otros que guardan relación con Rails.
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í
La información para este artículo la sacamos de la recopilación de información del libro Sinatra: Up and Running y de la Documentación oficial
Adentrandonos en la lógica del API
En los capítulos pasados estuvimos recorriendo todos los aspectos de nuestra aplicación (API) que tienen que ver con la estructura, Librerías utilizadas, esquema de base de datos, migraciones, etc... En este nuevo episodio vamos a recorrer lo que existe en el directorio /app
.
$ tree app app ├── models │ └── link.rb └── routes ├── base.rb └── links.rb 2 directories, 3 files
Controladores
Vamos a comenzar con el directorio app/routes
y el archivo base.rb
.
El directorio app/routes
lo consideramos como el directorio de los controladores. El archivo base.rb
es el controlador principal de nuestra aplicación, el resto de los controladores heredarán de él, por consiguiente contendrán todos los métodos que el mismo posea.
Podemos observar que este archivo base.rb
contiene una clase llamada Base
que hereda de Sinatra::Application
a su vez por este ser una sub-clase de Sinatra::Base
entonces heredamos el manejo settings, enrutamiento, manejo de errores etc... automaticamente.
Luego podemos observar que existe un bloque de configuración donde decimos donde queda la ruta principal de nuestro proyecto y desabilitamos ciertas opciones sobre las que pueden leer a detalle en Built-in Settings. Por último un bloque before
que almacena el host y el puerto de servidor cuando se realiza una petición. Esto lo utilizaremos para almacenar desde nuestro modelo la dirección interna de nuestra aplicación donde podremos localizar nuestro url corto.
Ahora vamos a ver el archivo links.rb
dentro de app/routes
, el otro controlador.
En este archivo lo primero que vemos es que todo su contenido se encuentra dentro de 3 módulos, Routes
, Api
, v1
. Fue realizado de la siguiente manera para permitirnos versionar nuestro API por si en un futuro quisiéramos modificarlo drásticamente y además tener la posibilidad de correr de forma simultanea una o más versiones del API con URLs no muy diferentes.
Luego nuestra clase Links
hereda de Base
(el controlador principal) y volvemos a tener un bloque before
pero en este caso para restringir que el tipo de contenido de nuestras peticiones a JSON.
A partir de aquí tenemos 3 posibles rutas:
-
get '/': ruta encargada de responder a un URL con un query de ids que posiblemente han sido creados con anterioridad en nuestra aplicación. Recibe
http://localhost:3000/?ids=1,5
ohttp://localhost:3000/
y responde con un objeto JSON con la siguiente estructura{"links":[{"id":1,"uri":"http://...","href":"..."},{ "id": 5,...}]}
en este caso esta sería la respuesta de la primera petición. -
get '/:search' ruta diseñada para responder a los URL cortos, es decir, recibe
http://localhost:3000/ynt70
y retorna un objeto JSON con la siguiente estructura{"links":[{"uri":"http://codehero.co"}]}
-
post '/': encargada de recibir un objeto de tipo JSON
'{"links": [{"uri": "http://..."}, {"uri": "http://..."}]}'
en un arreglo con uno o muchos URLs. Además este método se encarga de llamar a la función de guardado de la data y de retornar una respuesta haya ocurrido un error o no. El estado 422 se refiere a que ocurrió un error en el intento de guardado porqué una validación no se cumplió. Por otra parte el 201 retorna los encabezados de la petición esperados y además retorna la información referente al objeto almacenado.
De esta manera y con estas 3 rutas estamos abarcando poco pero de manera concreta para poder explicar como se realizan las rutas de nuestro API.
Ahora pasaremos a ver el modelo empleado con Sinatra-ActiveRecord.
Modelos
Ahora vamos con la última parte de nuestra aplicación (API), referente a los modelos, bueno, en este caso es sólo uno.
Ahora estamos ubicados en el directorio app/models
en el archivo link.rb
.
Lo primero que encontramos en este archivo es una clase que hereda de ActiveRecord::Base
esto nos permite tener el acceso a datos. Luego encontramos un "famoso" callback relacionado a un método llamado set_uri_hash
. Por ser un callback de tipo before_create
es ejecutado justo antes de realizar el create de un objeto en DB. El método antes mencionado se encarga de crear un "hash" de cinco caracteres base 36, es decir, se escogen cinco caracteres aleatorios que se encuentren entre los números de 0..9 o las letras de la a..z y se asignan a el campo en DB uri_hash
.
Lo próximo que encontramos es una validación sobre el campo uri
el cual necesita estar presente a la hora de crear un nuevo elemento.
A partir de aquí encontramos varios class methods utilizados para manupular la data en nuestro API:
-
search_by: Este método es el utilizado en la ruta
get '/:search'
y es el que hace posible realizar el select sobre unid
,uri
yuri_hash
donde el valor delid
ouri_hash
sea igual al suministrado por el usuario en su consulta. -
by_ids: Este método se encarga de analizar si la petición suministrada por el usuario mediante la ruta
get '/'
contiene un parámetro y devuelve una respuesta en base a eso. -
createnewlink: Este método es el utilizado previo a la creación de un nuevo link en base de datos, es una manera de no tener que utilizar strong parameters para canalizar un posible mass assignment de parámetros. Crea un objeto para un nuevo link y le agrega al campo
uri
lo que viene dentro del parametrouri
, para luego retornar el objeto link. - returnheaderlocation: Este método se encarga de retornar el header de location correcto dependiendo de la cantidad de elementos que se crearon simultaneamente. Si se envían dos o más elementos y los mismos se crean satisfactoriamente podremos visualizar el header Location de la siguiente manera:
HTTP/1.1 201 Created Content-Type: application/json; charset =utf-8 Location: http://localhost:3000/?ids=5,6
- savereceivedrequest: Finalmente hemos llegado al método encargado de almacenar en base de datos todos los links enviados desde la ruta
posts '/'
. Probablemente siempre se envíen varios links para ser almacenados de manera simultanea. Es aquí donde es necesaria una operación transaccional para poder estar seguros de que si uno de estos falla toda la operación de guardado se devuelva (rollback) y así poderle retornar un mensaje de error al usuario.En general es bastante sencillo toda la funcionalidad de nuestro API, cabe destacar que utilicé varias de las prácticas que menciona http://jsonapi.org/ para la realización de la lógica del nuestro API.
Conclusión
En este quinceavo y último capítulo de la serie he terminado de explicar el funcionamiento de nuestro API, con sus controladores y modelos. 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!
Compártela:Please enable JavaScript to view the comments powered by Disqus.comments powered by