En entornos de trabajo de Ruby, estamos constantemente instalando y usando gemas de terceros. Al trabajar con una API externa también es útil utilizar una gema de Ruby. De esta forma, mantenerla queda fuera del alcance de nuestro proyecto y además podemos reutilizarla en otros (y compartirla 😉).
En este artículo exploraremos como usar Gemas y a encapsular, para que vuestros próximos proyectos sean mucho mas sencillos.
Creando una gema desde cero
Instalar y usar gemas de otros mediante Bundler es algo básico al trabajar con Ruby, pero no todos hemos hecho gemas desde cero. En las siguientes líneas explicaremos cómo hacerlo de forma rápida.
Para ello, en nuestro equipo con ruby y bundler instalados, ejecutaremos el siguiente comando, asegurándonos de escribir rspec cuando nos pregunte sobre los tests a utilizar:
bundle gem my_gem
Esto generará una nueva carpeta my_gem en el directorio donde nos encontremos, con la estructura básica de una gema incluida. El código lo meteremos en la carpeta lib/ y los tests en la carpeta spec/. Por último, el archivo .gemspec incluye los metadatos de la gema y deberíamos editarlo para ponerlo a nuestro gusto.
Cómo usar una Gema de Ruby
Tenemos dos opciones: Compilar e instalar la gema localmente (con lo cual podremos requerirla si abrimos una consola de irb) o añadirla al proyecto donde queramos usarla. Explicaré brevemente ambas:
Para compilar e instalar la gema basta con ejecutar estos dos comandos en la carpeta raíz de la gema:
gem build my_gem.gemspec
gem install ./my_gem-X.Y.Z.gem
Deberemos sustituir X.Y.Z por la versión de nuestra gema (declarada en lib/my_gem/version.rb).
Por otra parte, incluir la gema en nuestro proyecto (y poder probarla antes de publicarla) deberemos añadirla al Gemfile de nuestro proyecto. Podemos hacerlo de esta forma:
gem 'my_gem', path: '/Users/user/Code/gems/my_gem'
No olvidemos el posterior bundle install.
Cómo encapsular una API HTTP
Por norma general, tendremos acceso a una documentación de todos los endpoints (o eso espero, por el bien de tu salud mental). Es completamente normal que no vayamos a utilizarlos todos, así que tomaremos como ejemplo una API inventada cuyo endpoint sea un POST /books para crear un recurso Book.
Voy a explicar por encima la idea y luego dejaré ejemplos de código:
- Trabajaremos sobre la gema Faraday, que permite mucha flexibilidad a la hora de hacer llamadas HTTP.
- Crearemos una clase para encapsular las Request HTTP.
- Crearemos una clase por recurso para encapsular sus acciones.
La cosa quedará más o menos así:
- Una clase Request con un método do, que recibe tres parámetros: method, path, options. Internamente usa Faraday para gestionar la conexión.
- Una clase Book con un método create que recibe name, author, el cual llamará a Request#do.
# lib/mi_api/book.rb
module MiApi
class Book
def self.create(name:, author:)
request.do(:post, '/books', { name: name, author: author })
end
private
def request
Request.new
end
end
end
# lib/mi_api/request.rb
require 'json'
module MiApi
class Request
def do(method, path, opts={})
serialized_opts = serialize_opts(method, opts)
response = connection.send(method, path, serialized_opts)
handle_response(response)
end
private
def serialize_opts(method, opts)
if %i[post put patch].include?(method)
JSON.dump(opts)
else
opts
end
end
def connection
@connection ||= Faraday.new(
url: ENV['MI_API_BASE_URL']
) do |conn|
conn.adapter :net_http
end
end
def handle_response(response)
# TODO
end
end
end
Próximos pasos
Los siguiente que podríamos hacer es mapear los posibles errores que devuelva la API ante errores nuestros, y lanzarlos en caso de que la API nos devuelva estos errores. Por ejemplo, si un Book no tiene name, podríamos devolver un MiApi::Errors::Books::MissingNameError. Por supuesto, también continuar mapeando los endpoints que nos sean útiles, así como gestionar las respuestas de la API.
También haciendo uso de WebMock podemos añadir tests a las requests HTTP que vaya a gestionar nuestra gema. De esta manera podemos asegurarnos de que la llamada HTTP formatea correctamente los parámetros o las respuestas mantienen un formato que coincida con el que estamos esperando.
Wrap-up
Esperamos que te haya resultado útil este pequeño vistazo a cómo encapsular APIs. Si estás haciendo una API, considera crear tú mismo la gema para facilitar a los desarrolladores comunicarse con tu API sin tener que recurrir a manejar llamadas HTTP. Te lo agradecerán. 😜
¿Te ha gustado este artículo? Sigue aprendiendo sobre programación en este artículo de nuestro blog y síguenos en nuestras redes para estar al día de cuando tengamos una nueva publicación para ti.