O conceito de REST é popular há mais de 10 anos e ainda assim é difícil achar duas pessoas que concordem com o que é RESTful ou não. Para piorar a situação, uma busca rápida vai retornar montanhas de conteúdos conflitantes ou simplesmente errados. Depois de passar por inúmeras discussões a esse respeito, resolvi me envolver na conversa, fazendo o máximo para não causar ainda mais desentendimento. Por isso, escolhi o formato de perguntas frequentes e vou tentar ser o mais objetivo possível.
1. O que é REST?
Uma olhada rápida na Wikipedia pode enganar:
Representational state transfer (REST) or RESTful Web services are one way of providing interoperability between computer systems on the Internet. REST-compliant Web services allow requesting systems to access and manipulate textual representations of Web resources using a uniform and predefined set of stateless operations.
Em uma grosseira tradução para o português, isso ficaria mais ou menos assim:
Representational state transfer (Transferência representational de estado - REST) ou serviços RESTful são uma maneira de prover interoperabilidade entre sistemas de computadores na internet. Serviços que seguem o padrão REST permitem que sistemas requisitantes acessem e manipulem representações textuais de recursos web, usando um conjunto uniforme e pré definido de operações desprovidas de estado.
A tradução aqui realizada chega a exigir uma tradução da tradução, mais isso não importa! O que conta aqui é que enquanto essa definição está correta, ela descreve um serviço REST não o padrão REST em si. O mais correto seria uma definição parecida com:
REST é um padrão arquitetural que impõe um conjunto de orientações e restrições, focado em garantir escalabilidade e extensibilidade, entre outras características.
2. O que torna REST diferente?
O ponto central do padrão REST veio da conclusão de que protocolos de rede existentes (HTTP é um deles) já forneciam toda a funcionalidade básica para integração, sem a necessidade de construção de protocolos complexos como o SOAP. Numa época dominada pela famosa "estrela da morte WS (WS*)" (mais detalhesabaixo), essa proposta foi um grande caso de simplificação.
Sendo assim, se você estiver criando uma API REST sobre HTTP, os conceitos básicos a serem usados são:
- verbos HTTP (GET, POST, PUT, PATCH, DELETE, etc): são usados para expressar a intenção por trás de um comando;
- recursos HTTP: estão no coração das interações e são endereçáveis através de URLs claras e significativas;
- caching se torna possível e simples através de e-tags;
- media types informam que tipo de formato deve ser usada para representative uma informação. Por exemplo: um mesmo endpoint pode aceitar texto puro ou JSON como entrada.
3. Então REST é JSON sobre HTTP, correto?
Na verdade, não.
Conforme a resposta anterior, JSON é uma das várias representações possíveis para um recurso. XML, formatos binários ou qualquer outro formato de serialização podem, em princípio, ser usados por um serviço RESTful.
Em teoria, é possível criar um serviço RESTful usando um formato diferente de HTTP como base. Mas é difícil achar achar exemplos reais por aí.
4. Mas REST é SOA ou anti-SOA?
Bom, os dois tem uma coisa em comum: ambos padrões sofrem com interpretações exageradas e são motivos de discussões infinitas na internet.
A arquitetura orientada a serviço se tornou um tabu para muitos, mas na realidade prega princípios que podem ser vistos em muitos microservices modernos. O problema, e a grande causa de confusão, não é sobre o porquê de SOA, mas o como (SOAP).
No fim das contas, os dois conceitos são ortogonais: você pode implementar SOA através de serviços RESTful (uma abordagem bastante comum) ou ter várias APIs RESTful sem adotar SOA.
5. REST é CRUD puro? Se não, como implemento operações não CRUD?
Não. E confesso que eu estava torcendo para você não fazer a segunda pergunta. De toda forma, vamos à resposta: o engano de equiparar REST e CRUD é muito comum e provavelmente vem da grande quantidade de exemplos que seguem essa linha.
Para tornar as coisas ainda mais confusas, vários autores propõe o mapeamento de comandos (ex: o cancelamento de um pedido) numa operação de update (normalmente um PATCH) sobre um recurso.
Enquanto isso pode ser ok e até mesmo RESTful, essa abordagem não apresenta intencionalidade (um update pode ser qualquer coisa, enquanto um cancelamento é uma ação bastante específica) e pode tornar coisas como validação de permissões (ex: esse usuário pode faturar um pedido, mas não cancelar) e auditoria, questões muito mais complexas.
O raciocínio imediato após o parágrafo anterior, em muitos casos, é: "No exemplo de cancelamento, um exemplo de operação REST significativa seria criar um recurso de cancelamento e permitir que clientes façam um POST contra /order/123cancellation, correto?"
Enquanto essa pode ser uma boa saída em vários cenários, é sempre ter em mente uma importante ressalva: se levada ao extremo, essa abordagem pode gerar uma explosão de recursos que representam operações, o que pode tornar a API muito mais complexa.
6. E o que é esse papo sobre REST e idempotência?
REST e idempotência são conceitos completamente diferentes, mas o protocolo HTTP tem especificações sobre idempotência. Como REST é fiel ao princípio de usar os pontos fortes do protocolo de base, ele acaba herdando os mesmos conceitos. Se esse papo de idempotência for novo para você, recomendo esse link. A leitura vale a pena!
Os verbos GET, PUT, PATCH e DELETE devem ser idempotents. Isso quer dizer que apesar de que apenas GET é uma operação "segura", todas essas operações deveriam apresentar o mesmo comportamento se repetidas com o mesmo input, exceto por uma potencial diferença na mensagem de resposta, como um 404 no caso de um segundo DELETE. Vale a pena salientar que o estado interno do serviço se mantém constante.
Entre outras coisas, isso quer dizer que comandos PATCH e PUT deveriam evitar operações stateful, como por exemplo incrementar um contador num recurso. Geralmente, POST não é idempotente, mas uma violação de constraint (ex: adicionar duas vezes uma pessoa com o mesmo CPF) podem mudar esse comportamento.
7. Mas então o que não é REST?
Essa pergunta é mais fácil de ser respondida com exemplos. Confira:
WS* (também conhecido como WS Star ou WS Death Star)
Um conjunto de padrões da indústria (leia-se grandes corporações, comitês, etc) para web services que dominaram o espaço corporativo nos anos 90 e no princípio dos 00. Sucumbiu sob o peso da própria complexidade, mas ainda pode ser visto em muitos sistemas legados ou em ferramentas corporativas que acham que REST é só um modismo.
A maior divergência consiste no uso de um protocolo sobre a camada de transporte, focado em abstraí-la ao máximo. Seguindo nessa linha, permite muito mais flexibilidade sobre como desenhar uma API (não necessariamente algo bom nesse caso), já que não é necessário seguir a semântica do protocolo de base. Em linguagem humana, isso quer dizer que serviços WS podem não ser orientados a recurso.
RPC (Remote Procedure Call)
Outro grande ponto de confusão, já que só usar HTTP e JSON não garante aderência a REST. Uma RPC torna as operações, não os recursos, o elemento central. Por exemplo, um cancelamento poderia ser feito usando /cancelOrder ou, mais sutilmente, /orders/123/cancel. Note a diferença com relação ao exemplo REST.
GraphQL
Uma das novas tecnologias em voga no mercado, GraphQL é uma linguagem (não um padrão arquitetônico), focada em entregar suas queries e mutations (ao invés de operações) numa única URL (ao invés de um endereço por recurso), usando exclusivamente HTTP (REST não se limita a isso).
Uma atitude sensata é ignorar os posts no estilo "Por que GraphQL é melhor que REST?" e entender as principais diferenças entre as duas abordagens. Para uma visão mais detalhada sobre essas diferenças, recomendo esse post.
8. Ok, mas o que é esse tal de HATEOAS?
Quando REST parece um conceito tão abstrato, vem alguém falar dessa terrível sigla. O padrão Hypermedia As The Engine of Application State (Hipermídia Como Modelo de Estado de Aplicativos, não que a tradução ajude no entendimento) é o santo graal do REST e tem como base um conceito simples: da mesma maneira como uma pessoa pode usar hiperlinks para navegar na web, uma app pode usar hiperlinks para navegar uma API.
Parece muita loucura? Aqui vai um exemplo: digamos que uma app faz um GET em orders{:id} para buscar detalhes de um pedido. Agora ela deve buscar detalhes do cliente que o colocou. Para fazer isso, o payload contém uma URL que aponta para esse recurso específico (ex: /customers/{:id}).
Esse design permite a descoberta de relacionamentos entre entidades (recursos) de uma API e pode ser estendida para contemplar inclusão de múltiplos recursos relacionados (ex: GET /order/{id}/?include=customer) numa única chamada HTTP. Note que é possível usar URLs que pertencem a outros domínios, o que teoricamente permite uma navegação sem nenhum tipo de fronteira.
9. REST é uma bala de prata? Tudo bem se eu não usar esse padrão?
Perguntando desse jeito, a resposta óbvia para a primeira pergunta é não. Como em qualquer escolha técnica, existem pontos fracos no padrão.
Quanto a alternativas, divergir de REST pode ser perfeitamente aceitável (o pessoal do GraphQL, por exemplo, traz pontos bem interessantes pra mesa), desde que seja uma decisão bem embasada.