Skip to content

1. Padrões para uma API REST

Filipe Tristão edited this page Nov 3, 2018 · 2 revisions

Introdução

A Arquitetura SOA (Service Oriented Architecture ou Arquitetura Orientada a Serviço) nos dias atuais é um padrão que tem muita adesão e cada vez mais aplicações são desenvolvidas sob esse conceito. Nesse pattern de desenvolvimento, um conjunto de serviços garante a integração entre negócio e tecnologia por meio de interfaces e comunicação acoplada.

O que é um Service/API?

Trata-se de uma interface utilizada para promover a comunicação entre componentes ou softwares. Um webservice é um subtipo de serviço/api que sempre irá operar a partir do protocólo HTTP.

O que é REST?

A grosso modo significa Representational State Transfer. É uma forma simples de fazer a comunicação entre um cliente e um servidor, geralmente utilizando JSON.

Como deve funcionar um bom webservice?

E quais os principais requisitos para desenvolver uma boa api REST?

Menos abstrata e mais concreta possível

Os pontos de entrada para a api devem ser simples e refletir a lógica do sistema para o client que está consumindo. Então quanto mais concreto e mais representar a realidade, melhor será. Tipicamente a API pode representar o banco de dados da aplicação, onde caso você pussua uma tabela books (como no exemplo desse repositório) você terá um ponto de entrada na sua aplicação que se parecerá com: http://myapp/books

Exemplo

Possuir as operações CRUD

Assim como o banco de dados tem as opções SELECT, INSERT, UPDATE e DELETE para realizar as operações CRUD no banco, a API também terá para realizar as operações CRUD da aplicação. As operações CRUD na API devem se dar no mesmo ponto de entrada (http://myapp.com/books no exemplo anterior) e a operação a ser executada deve ser determinada pelo método HTTP. Abaixo uma tabela que compara como as operações que seriam realizadas em um banco de dados e como devem ser realizadas na api.

Operação no banco de dados URL a ser chamada na API Verbo HTTP a ser chamado na API Ação
SELECT * FROM books http://myapp.com/books GET Listar todos os livros
INSERT INTO books http://myapp.com/books POST Inserir um novo livro
UPDATE books http://myapp.com/books PUT ou PATCH Atualizar todos os livros
DELETE FROM books http://myapp.com/books DELETE Excluir todos os livro
SELECT * FROM books WHERE id=123 http://myapp.com/books/123 GET Listar o livro com o ID 123
UPDATE books WHERE id=123 http://myapp.com/books/123 PUT ou PATCH Atualizar o livro com o ID 123
DELETE FROM books WHERE id=123 http://myapp/books DELETE Excluir o livro com o ID 123

Controle de Erros

O gerenciamento de erro é uma parte importante da API, pois é por meio deles que um cliente poderá garantir que uma operação foi executada ou não. Uma boa resposta de erro para a API se pareceria como abaixo:

{
   "status": 401,
   "error_code": 2005,
   "error_message": "Authentication token has expired",
   "more_info": "http://myapp.com/doc/token_error"
}

É importante que os erros respeitem os códigos HTTP. Por exemplo quando uma URL não for encontrada, a resposta HTTP é 404, quando há um erro na API, a resposta é 500 e assim por diante. Uma descrição de todos os códigos HTTP pode ser vista aqui

Versionamento da API

A api pode ser versionada de diversas formas e você pode encontrar a opinião de muitos desenvolvedores na internet. O padrão atualmente utilizado na Eloverde se da seguinte forma. Para a api de versão 1, é colocado um V1 antes da url, ficando assim:

http://myapp.com/v1/books

É importante que esse versionamento é referente a API e não ao seu código fonte!. O versionamento dessa forma permite que o cliente que consome a sua API, possa trocar de versão sem quebrar a lógica de sua aplicação. Você geralmente irá trocar a versão da API quando alterar os parâmetros de input ou output de um de seus pontos de entrada. Por exemplo, vamos supor que o seu webservice de livros, o método POST de criação deveria receber apenas o parâmetro name, mas agora o parâmetro category_id também é obrigatório. Então para não quebrar as aplicações dos diversos clientes conectadas a sua api, você deveria manter duas versões, a V1 que aceita a entrada sem o campo category_id, e a V2 que não aceita a entrada se o category_id não estiver presente.

Filtrando os dados

Assim como no banco de dados, o client deve ser capaz de efetuar filtros na api para trazer apenas os registros que lhe são pertinentes. Usando o nosso exemplo, se no ponto de entrada do nosso livro, desejássemos filtrar pela propriedade name, isso deveria ser feito com uma chamada da seguinte forma:

http://myapp.com/books?name=First%20Blood

E é claro que recursos como paginação também devem ser aplicados para evitar sobrecarga da api. Utilizando o Laravel, se quiséssemos acessar a página 2 dos nossos registros, a url deveria ficar assim:

http://myapp.com/books?page=2

Segurança

Sempre é bom cuidar da segurança de nossas aplicações, abaixo algumas recomendações do que usar para a api:

  • Usar HTTPS para as requisições;
  • Usar timestamps e fazer log de todas as requisições, dessa forma em caso de disputa judicial, você tem os registros armazenados para validação;
  • Usar tokens de acesso para verificar se a api está sendo invocada por um client confiável. Nesse exemplo estamos utilizando autenticação via JWT.

Documentação

A documentação da api é a forma que nossos clients saberão como consumir a mesma. É muito fácil manter uma api quando os desenvolvedores do client tem acesso ao código fonte e podem ver como cada uma das coisas funciona. Porém a partir do momento que a equipe que desenvolve o client não tiver mais acesso aos fonts da api, a sua única maneira de debugar e descobrir como interagir com a mesma será a partir da documentação. Por isso é muito importante a existência de uma documentação consistente para nossos clients não terem problemas.

Concluindo sobre a API

Esses são os passos básicos para ter rodando uma boa e consistente API REST rodando no seu ambiente. Apesar de não ser um ambiente nada não muito complexo e que você não terá muitos problemas para configurar, tal estrutura trará muita flexibilidade e escalabilidade para as suas aplicações.