CWI Software
Published in

CWI Software

Qual API você está criando: RESTful, baseada em REST ou RPC com HTTP?

Muitos desenvolvedores assumem que uma API RESTful¹ se resume em usar os métodos POST, DELETE, PUT e GET com o retorno de códigos HTTP. Mas será que uma API assim pode ser considerada RESTful?

Quem cunhou o termo REST (Representational State Transfer) foi Roy Feilding que, dentre as várias características apontadas que definem o que é REST, a que considero uma das mais importantes é a de interface uniforme.

O que é bem comum de se observar em APIs pela Internet é que boa parte dos sistemas criam, na verdade, uma API RPC (Remote Procedure Call) em cima do HTTP. Em suma, uma API desta natureza faz requisições síncronas que não seguem um padrão observável de interface. Ou seja, o simples fato de enviar um Json de um lado para outro não faz sua API seguir o padrão REST.

Focando então nesta necessidade de ter uma interface uniforme em uma API, os aspectos mais importantes deste assunto que gostaria de abordar são três: métodos HTTP, códigos HTTP e organização dos recursos.

Vamos falar de cada um deles.

Métodos HTTP

Creio que este seja o ponto onde existe menos divergência.

Ao invés de resumirmos tudo em GET e POST, como ocorria antigamente, temos também no nosso leque de principais métodos o PUT, DELETE e PATCH.

De certa forma, é simples de entender:

  • GET: para consultas;
  • POST: para criação de recursos;
  • DELETE: para remoção de recursos.

Já a atualização de um recurso pode envolver um pouco de confusão, pois temos o PUT e o PATCH para isto. Mas resumindo, o PUT serve para atualização do recurso inteiro enquanto o PATCH é uma atualização de um ou mais campos daquele recurso.

Códigos HTTP

Nesta parte, entendo que a confusão começa a aumentar. Embora existam muitos códigos HTTP, existem as escolhas mais comuns e óbvias para alguns casos. Para outros, nem tanto.

Primeiro, vamos analisar os códigos de casos de sucesso:

  • 200: requisição feita com sucesso. Comumente usado com o método GET, POST e PUT.
  • 201: recurso criado com sucesso. Comumente usado em métodos POST.
  • 204: requisição feita com sucesso, mas não retorna conteúdo. Comumente usado com os métodos DELETE, PUT ou POST.

Para os casos de falha do cliente, podemos listar:

  • 400: requisição mal formada pelo cliente. Pode ocorrer quando algum campo obrigatório está faltando, foi enviado com formato incorreto, etc.
  • 401: usuário não está autenticado.
  • 403: usuário não tem permissão para acessar o recurso
  • 404: recurso não encontrado. Pode ser usado em um GET/PUT/DELETE no qual o recurso informado não existe. Pode ser usado dentro do POST quando está referenciando algum recurso no body que não existe.
  • 409: conflito. Pode ser usado quando uma requisição está sendo criada com uma informação que deve ser única no sistema, mas já tem um recurso que a utiliza. Por exemplo, cadastrar dois usuários com o mesmo e-mail.
  • 412/422: para problemas de validação, onde a requisição em si está correta mas alguma validação interna do sistema recusou a requisição. Já usei 412 nas minhas APIs, mas atualmente o consenso é usar o 422.

E, finalmente, temos os casos de erro no servidor:

  • 500: erro interno do servidor. O sistema enfrentou alguma condição inesperada.

Existem muitos códigos HTTP disponíveis e você pode estender o uso deles o quanto quiser, conforme for identificando cenários claros de uso para cada um deles. Mas, em vários momentos, você irá perceber que não tem um código HTTP exatamente para o que precisa.

Organização dos recursos

É aqui que concentra-se o principal problema que observo nas APIs.

Em uma API, nós estamos trabalhando com os recursos, que podem variar dependendo da sua API: podem ser pedidos, contratos, pessoas, pagamentos, endereços, etc. Estes recursos também podem ter parentescos, como: pessoas terem endereços, pedidos terem pagamentos, pagamentos terem endereços, etc.

Assim, a criação dos endpoints que atenderão estes recursos devem observar esta organização.

Importante também usar de forma correta os métodos HTTP ao trabalhar com os recursos e criação dos seus endpoints. Não raro vejo APIs que usam verbos nos seus endpoints sem necessidade: /pedidos/listar-pedidos, /pedidos/criar, etc.

Vamos aos exemplos. Se queremos listar os pagamentos disponíveis ou filtrar os pagamentos por cartão, podemos criar nossos endpoints desta maneira:

GET /pagamentos/
GET /pagamentos?tipo=cartao

Se queremos listar todas as pessoas ou buscar a pessoa com determinado CPF:

GET /pessoas
GET /pessoas/12333356733

Perceba que nossos recursos estão todos nos plural e é preferível mantê-los desta maneira.

A criação, atualização ou remoção de recursos se dá pelo próprio método HTTP também, respectivamente:

POST /pessoas
POST /pedidos

PUT/pessoas/12333356733
PUT /pedidos/88333

DELETE /pedidos/88333

O parentesco entre recursos, mencionado no início, também pode ser contemplado e combinado com filtros:

GET /pessoas/12333356733/enderecos?rua=benjamim
POST /pessoas/12333356733/enderecos

E agora, posso chamar minha API de RESTful?

De acordo com Roy, não:

if the engine of application state (and hence the API) is not being driven by hypertext, then it cannot be RESTful and cannot be a REST API. Period.

O que ele está dizendo acima de forma bem categórica é que, basicamente, uma API REST precisa implementar o que conhecemos hoje por HATEOAS (Hypertext As The Engine Of Application State) para ser considerada REST.

Por diversos motivos, o HATEOAS não se popularizou até hoje. Então, por definição, temos muito mais APIs baseadas em REST do que RESTful. Como poucas pessoas conhecem esta definição, é comum entender que uma API é RESTful mesmo não tendo HATEOAS.

Esta discussão, inclusive, acabou originando o conceito de níveis de maturidade de uma API ao implementar REST.

Conclusão

O conceito base de criação de uma API RESTful (ou baseada em REST :) ) segue um conjunto inicial de padrões que são simples de entender e seguir.

Porém, certamente você enfrentará vários casos onde ficará em dúvida de como irá criar seu endpoint:

  • Se eu precisar fazer operações (criar, atualizar ou remover) em lote? Como informar ao usuário os que foram processados com sucesso ou erro? Qual método e código HTTP usarei?
  • Se eu precisar chamar uma API só de validação, como evitar o uso de um verbo no endpoint?
  • Se a identidade do meu recurso usa chave composta, como faço um GET/PUT/DELETE dela?

Existem diversas maneiras para solucionar os problemas acima. Apenas tenha em mente que o ideal é que quem consuma este endpoint consiga facilmente entender o que ele faz apenas olhando para a assinatura dele. A organização apresentada no texto é uma forma de agilizar este entendimento pois favorece a auto-documentação da própria API.

Para finalizar, meu recado final é: seja consistente na sua API. Faça seu estudo, faça suas escolhas e mantenha a consistência destas decisões por toda ela. Pior que um padrão “ruim” é não ter padrão algum.

[1]. Um serviço RESTful é simplesmente aquele que realiza a implementação do padrão REST.

--

--

--

Desenvolvemos soluções e sistemas de TI com base nas necessidades específicas de empresa de médio e grande porte em âmbito global, desde 1991.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Dherik Barison

Dherik Barison

Java developer, Tech Lead, Stack Overflow enthusiast and contributor: https://dherik.com

More from Medium

DARTH

INTENTIONALITY

Bridgeswap

Collaborative Unit 2: Second Skin