APIs descomplicadas no Rails 5 com Rails API

em Desenvolvimento, Ruby.

Uma das grandes novidades no Rails 5 é que o Rails API teve seu pull request aceito.
Como você já deve imaginar, agora o Rails API faz parte do core do Rails e isso fará com que o projeto ganhe mais mantenabilidade e visibilidade, uma vez que toda a comunidade que mantém o framework passará a olhar para ele.

A grande vantagem de se usar o Rails API é sua aplicação, que terá apenas os elementos que ela precisa para funcionar, se tratando de uma API. Basicamente você terá uma aplicação “leve”, contando somente com os middlewares que sua API precisará, sendo totalmente customizável. Isso significa também, que caso sua aplicação evolua e você precise de elementos de front end ou do assets pipeline do Rails, será bem simples de colocá-los de volta.

Visto suas vantagens, vamos então criar nossa primeira API com Rails API?
Para começar, vou assumir que você tem instalado ruby 2.2+ e o logicamente o Rails 5. Tendo os pré-requisitos em mãos, de acordo com a documentação, só o que precisamos fazer para criar nossa API é rodar o seguinte comando:

$ rails new pet_api --api

Eu não vou entrar em detalhes sobre como a diretiva –api impacta na criação da nossa aplicação Rails, mas é ela que vai fazer com que a nossa aplicação fique mais “leve”, como eu mencionei anteriormente. Basicamente, sua aplicação não incluirá os middlewares que são úteis para aplicações que utilizam o navegador (que não é o caso de uma aplicação em modo API).

Continuando nossa jornada, agora que já temos a aplicação criada, vamos então baixar nossas gems e configurar o nosso banco padrão da aplicação:

$ cd pet_api
$ rails db:setup db:migrate

Note que como estamos no Rails 5, podemos substituir o comando rake por rails.

Uma vez configurado o banco, podemos rodar nossa aplicação para testar se está tudo certo.

$ rails server

Se tudo deu certo, você verá a imagem abaixo:

Agora que já conseguimos criar e configurar a nossa aplicação em modo API, vamos utilizar os geradores automáticos do rails (scaffold) para gerar o código necessário para nossa API.

$ bundle exec rails g scaffold pet name kind

A saída para esse comando será a seguinte:

      invoke  active_record
      create    db/migrate/20170112232027_create_pets.rb
      create    app/models/pet.rb
      invoke    test_unit
      create      test/models/pet_test.rb
      create      test/fixtures/pets.yml
      invoke  resource_route
       route    resources :pets
      invoke  scaffold_controller
      create    app/controllers/pets_controller.rb
      invoke    test_unit
      create      test/controllers/pets_controller_test.rb

Como vocês podem perceber, uma vez que estamos em modo API nenhuma view é criada pois não teremos a necessidade delas na aplicação. Feito isso, precisamos rodar a migração de banco para o nosso novo modelo:

$ bundle exec rails db:migrate

Vamos analisar o código que foi gerado para podermos fazer alguns testes na nossa API. O nosso modelo é bem simples e não temos muito o que fazer aqui:

# app/models/pet.rb
class Pet < ApplicationRecord
end

No controller, podemos ver que temos as actions para inserir, atualizar, mostrar e excluir um registro (resource) em nosso banco:

#app/controllers/pets_controller.rb
class PetsController < ApplicationController
  before_action :set_pet, only: [:show, :update, :destroy]

  # GET /pets
  def index
    @pets = Pet.all

    render json: @pets
  end

  # GET /pets/1
  def show
    render json: @pet
  end

  # POST /pets
  def create
    @pet = Pet.new(pet_params)

    if @pet.save
      render json: @pet, status: :created, location: @pet
    else
      render json: @pet.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /pets/1
  def update
    if @pet.update(pet_params)
      render json: @pet
    else
      render json: @pet.errors, status: :unprocessable_entity
    end
  end

  # DELETE /pets/1
  def destroy
    @pet.destroy
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_pet
      @pet = Pet.find(params[:id])
    end

    # Only allow a trusted parameter "white list" through.
    def pet_params
      params.require(:pet).permit(:name, :kind)
    end
end

Outro arquivo importante para nós é o routes.rb onde são definidas quais serão as rotas da nossa API. Como podemos ver

# config/routes.rb
Rails.application.routes.draw do
  resources :pets
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

temos somente nossa resource pets o que já é suficiente para podermos realizar todas nossas requisições básicas. Podemos listar nossas rotas com:

$ rails routes

Prefix Verb   URI Pattern         Controller#Action
  pets GET    /pets(.:format)     pets#index
       POST   /pets(.:format)     pets#create
   pet GET    /pets/:id(.:format) pets#show
       PATCH  /pets/:id(.:format) pets#update
       PUT    /pets/:id(.:format) pets#update
       DELETE /pets/:id(.:format) pets#destroy

Por último, ainda temos que arrumar uma maneira de serializar o que nossa API irá servir, porque em condições normais, geralmente, não iremos querer que nossa resposta JSON seja a representação de cada coluna do nosso banco de dados. Para isso, vamos utilizar o Active Model Serializer do próprio rails-api. Para isso adicione a seguinte linha ao seu Gemfile:

# Gemfile
gem 'active_model_serializers', '~> 0.10.0'

Basicamente, o que o Active Model Serializer faz é permitir que criemos um serializer para formatar como será nossa resposta JSON, e uma vez que ele cria uma camada entre o nosso model e o nosso controller, não vamos precisar alterar nada neste último, isto é, poderemos continuar chamando o método to_json com nosso objeto ActiveRecord normalmente.

Vamos atualizar o nosso bundle

$ bundle

E como sempre utilizando dos artifícios do rails, vamos usar nosso gerador automático para criar nosso serializer

$ bundle exec rails g serializer pet

Com isso temos nosso serializer

# app/serializers/pet_serializer.rb
class PetSerializer < ActiveModel::Serializer
  attributes :id
end

Como vocês podem ver, só o atributo id foi gerado. Queremos retornar também o nome e o tipo do nosso animalzinho e então precisamos adicionar esses dados no serializer

# app/serializers/pet_serializer.rb
class PetSerializer < ActiveModel::Serializer
  attributes :id, :name, :kind
end

Agora sim já estamos prontos e podemos testar nossa API. Vamos criar um pet. Eu vou utilizar o postman mas você pode fazer um simples curl se preferir. Vamos iniciar o servidor

$ bundle exec rails s

Se você estiver utilizando o postman também, crie uma nova requisição POST com os seguintes dados:

Endereço: http://localhost:3000/pets
Headers: Content-Type: application/json
Body: {“name”:”totó”,”kind”:”cão”}

e envie a requisição. A sua resposta deve ser a seguinte

{
“id”: 1,
“name”: “totó”,
“kind”: “cão”
}

Isso quer dizer que eu criei um pet com o nome totó e ele é do tipo cão e a id pela qual podemos fazer operações sobre ele é a 1. Podemos fazer todas as operações que criamos no nosso controller, mas eu vou deixar como exercício para vocês testarem.

Existem outras operações mais avançadas como versionamento e autenticação que não fazem parte do escopo deste artigo, mas que eu voltarei a falar em breve em outra postagem.
Como vocês puderam perceber, criar uma API com Rails 5 é relativamente simples, lembrando que utilizando o rails em modo API diminui e muito a stack da nossa aplicação. Isso faz com que poupemos recursos e ela seja mais leve e limpa.

Espero que tenha sido útil para vocês e sintam-se livres para fazer perguntas por meio dos comentários. Até a próxima!

Você também pode gostar