Não é novidade para ninguém qual é a minha linguagem de programação favorita ultimamente. Ruby, oras! Provavelmente, também não é mais novidade para ninguém que venho focado em um único assunto: desenvolvimento de APIs RESTful. Inclusive, fazendo palestras aqui em Salvador. Então, como juntar esses dois mundos (Ruby + APIs)? A resposta é Grape! Um framework espetacular, que provê uma DSL muito simples e que facilita brutalmente a vida dos desenvolvedores de APIs.
Entretanto, percebi um probleminha! Não encontrei um tutorial sequer na Internet, sobre esse assunto, escrito em português ou espanhol. Péssimo! Portanto, meu objetivo aqui é escrever uma série de publicações sobre como instalar, configurar e usar o Grape para criar suas APIs. Primeiro, será um post em português, depois, me arriscarei a escrever em espanhol também. Será duplamente útil, porque terei a oportunidade de por em prática meus estudos de espanhol. 🙂
API do Bebum
Nosso projeto será uma API para um sistema que disponibilizará informações sobre cervejas. Começaremos com apenas dois modelos: Cerveja e Tipos de Cervejas. Futuramente, poderemos avançar, incluíndo mais modelos e incrementando nossa API! Todo o código que vocês verão aqui estará no Github, no endereço https://github.com/marloncarvalho/bebum-api.
Preste atenção que estamos seguindo rigorosamente (ou o máximo que pudermos) o modelo REST para a criação de APIs. Observe também que estou criando Tags no repositório com os nomes das partes de cada artigo. Por exemplo, teremos a Tag Parte 1, Parte 2 e assim por diante!
Montando seu Ambiente
Sou fã de Mac de longa data, portanto, vou focar basicamente nesta plataforma. Mas, como Mac é um *NIX, a maioria das coisas que farei aqui são replicáveis em um ambiente Linux. Quanto aos usuários Windows… bom, aí não tenho muito a ajudar, pois já tem 10 anos que não uso esse ambiente. Inicialmente, você precisa ter o interpretador Ruby instalado. No meu caso, eu uso o RVM – Ruby Version Manager para esta tarefa. O RVM instala e gerencia as versões do Ruby que você tem em sua máquina. Sugiro fortemente usá-lo!
Instalando o Ruby com o RVM
Para instalar o RVM, conforme descrito na página deles, basta digitar no console:
\curl -sSL https://get.rvm.io | bash -s stable
Depois disso, vamos instalar o Ruby na versão 2.1.2 usando o comando:
rvm install 2.1.2
Com o Ruby instalado, vamos agora instalar o Gem do Grape digitando no console:
sudo gem install grape
Pronto, seu ambiente está montado para nosso primeiro projeto com Grape. Fácil, não?
Bundler
Você já conhece o Bundler? Ainda não? Que feio! O Bundler é um gerenciador de dependências para Ruby. Com ele, fica mais fácil você definir quais gems seu projeto necessita e baixá-los. Caso ainda não o tenha instalado, faça gem install bundler no seu console para instalá-lo. O Bundler espera que você tenha um arquivo Gemfile na raiz do seu projeto. Neste arquivo, você deve listar cada Gem que seu projeto depende. Uma vez que você cria este arquivo, basta digitar bundle install no console, dentro do diretório onde está o arquivo Gemfile, para que ele baixe as dependências.
Estrutura do Projeto
Eu poderia começar com uma estrutura extremamente enxuta, mas seria simplista demais e já existem dezenas de artigos em inglês ensinando a usar o Grape que já fazem isso, então… Nosso próximo passo agora é montar a estrutura do nosso projeto. Crie um diretório qualquer em sua máquina e monte uma estrutura de diretórios semelhante à da imagem abaixo. Você também tem a possibilidade de baixar essa estrutura direto do nosso repositório.
Esta é uma estrutura que eu sugiro, mas não significa que você deve utilizá-la sempre. Fique à vontade para modificá-la, conforme suas necessidades. Outro detalhe digno de nota é que ainda faltam alguns diretórios nessa estrutura. Por exemplo, ainda precisamos dos diretórios db e spec, mas faremos isso nos próximos artigos.
Nesta estrutura, o diretório app conterá todas as classes relacionadas ao negócio da nossa aplicação. Este diretório é subdividido em api e models, onde api manterá somente as classes responsáveis em manter a lógica da nossa API RESTful e models conterá as classes de modelo, onde estarão, de fato, nossas regras de negócio.
Já o diretório api é subdividido em outros dois subdiretórios, chamados v1 e v2. Esta divisão é interessante para facilitar a criação de novas versões da nossa API. Observe que tanto dentro de app, como dentro de v1 e v2, existe um arquivo chamado base.rb. Eles estão aí para unir em um único ponto todas as APIs que disponibilizaremos. Não se preocupe se ainda está confuso, pois detalharemos esses arquivos com cuidado a seguir. Dentro dos diretórios v1 e v2 ainda temos uma pasta entities, que será responsável em manter as classes que irão expor os dados do nosso sistema em um formato de recursos.
Finalizando, o diretório model não tem nenhum subdiretório. Todos os demais arquivos são velhos conhecidos de todo programador Ruby e não vou detalhá-los aqui!
Modelos
Vamos nos focar agora na pasta models, onde temos, até este momento, apenas um arquivo chamado model.rb. Este arquivo contém as nossas classes de modelo. Obviamente, você pode, caso prefira, separar as classes em arquivos distintos. Talvez façamos isso no futuro, entretanto, para simplificar, vamos deixar em apenas um arquivo.
module Models # Cervejas. class Cerveja attr_accessor :id, :nome, :tipo end # Tipos de Cervejas class Tipo attr_accessor :id, :nome end end
Observe que são duas classes extremamente simples, ainda sem nenhuma lógica de negócio associada e também sem as informações de persistência. Vamos incrementá-las no futuro, entretanto!
Estrutura Geral da API
Vamos agora fazer nossa primeira API funcional. Vamos iniciar analisando a pasta api. Observe o arquivo base.rb. Ele é extremamente simples, pois serve apenas para agrupar TODAS as versões que estamos disponibilizando da nossa API. É óbvio, entretanto, que normalmente liberamos apenas duas versões por vez. Mas, caso seja necessário, esta estrutura nos permite disponibilizar quantas versões acharmos necessárias.
require 'api/v1/base' require 'api/v2/base' module API class Base < Grape::API mount API::V1::Base mount API::V2::Base end end
Este arquivo tem um módulo chamado API e dentro dele há uma classe chamada Base que estende de Grape::API. Logo em seguida, montamos as APIs que queremos exibir. No nosso caso serão API::V1::Base e API::V2::Base. Como você deve estar imaginando, essas classes estão definidas nos arquivos /app/api/v1/base.rb e /app/api/v2/base.rb. São duas versões da mesma API!
Agora, vamos bisbilhotar o arquivo /app/api/v1/base.rb. Ele tem um pouco mais de informações. Inicialmente, continuamos criando o módulo API, mas agora temos outro módulo dentro dele, chamado V1. Depois, definimos a classe Base, que monta as APIs de Cervejas e Tipos. Essas duas APIs estão definidas nos arquivos api/v1/cervejas.rb e api/v1/tipos.rb.
Também definimos algumas informações importantes sobre essa API. Definimos que a versão da API será obtida através do cabeçalho Accept do HTTP. Para que esta versão da API seja invocada, o cabeçalho Accept deverá estar escrito assim: application/vnd.alienlabz-v1+json. Isto é um padrão, não se preocupe em entender os motivos de ele estar definido assim. Obviamente, caso queira acessar outra versão da API, basta trocar o v1 por v2, por exemplo.
Não entraremos em detalhes da estrutura do diretório v2, pois ele está exatamente da mesma forma que o v1, já que ainda não temos nenhuma intenção de lançar uma versão 2.0 da API.
API de Tipos de Cervejas
Analisemos agora o arquivo /api/v1/tipos.rb. Ele inicia, como deveria ser, com a definição dos módulos API e V1. Logo em seguida, cria a classe Tipos herdando de Grape::API. Lembre-se, toda classe que representa uma API deve herdar desta classe do Grape. Agora a mágica começa a acontecer. Observe a definição do bloco resources. Ele serve para definir um namespace, dentro do qual estaremos servindo dados sobre um determinado recurso que estará disponível através de nossa API. No nosso caso, temos um recurso chamado Tipos, certo? Portanto, usamos o símbolo :tipos para criar o bloco de recursos referentes ao recurso tipos. Trocando em miúdos, isto significa que teremos uma URL do tipo http://localhost:port/tipos. Seguindo, definimos outro bloco, agora chamado de get.
module API module V1 class Tipos < Grape::API resources :tipos do # Obter uma lista de Tipos de Cervejas get do tipo = Models::Tipo.new tipo.id = 1 tipo.nome = 'Pilsen' [tipo] end end end end end
Observe atentamente esse método e tenha em mente que o Grape é uma DSL (Domain Specific Language). O que estamos fazendo nesta linha é chamar o método get (definido em Grape::API) passando como parâmetro a String ‘:id’ e um bloco de código que será chamado futuramente. Parece confuso? Mas é mais simples do que você pensa e é por isso que eu amo Ruby! O que estamos fazendo é informando ao Grape que temos uma rota ‘http://dominio/tipos/id’, acessível através do método GET do HTTP. Dentro do bloco de código, você escreverá o código que tratará toda requisição que chegar a essa rota através de um GET. Simples, certo? Lógico que é!
Nossa primeira API RESTful com Grape está quase pronta!
Configurando o config.ru
Ainda precisamos configurar o arquivo config.ru para conseguirmos rodar nosso projeto. Este arquivo contém os requires mais genéricos, necessários para rodar nosso projeto, como o grape, rubygems e rack. Depois, usamos o CORS para liberar as requisições cross-origin para todos os métodos HTTP (GET, POST,…). No final, rodamos a API com run API::Base. Observe que só precisamos de um require de módulos de nosso projeto: require ‘api/base.rb’.
$:.unshift "./app" require 'rack/cors' require 'rubygems' require 'grape' require 'rack' require 'grape-entity' require 'api/base.rb' use Rack::Cors do allow do origins '*' resource '*', headers: :any, methods: [:get, :post, :put, :delete, :options, :patch] end end run API::Base
Feito isto, agora vá no seu console e digite rackup. Sugiro instalar o Chrome junto com o plugin Postman. É um excelente plugin para executar chamadas a APIs RESTful. Veja abaixo como chamar nossa API na versão 1.
Pronto, meu caro, já temos nossa primeira versão da API executando! Não acredita? Testa aí! Nos próximos artigos, vamos fuçar mais o Grape, usando mais features dele. O objetivo deste primeiro artigo foi criar a estrutura e colocar uma primeira API simples executando!