DEV Community

Vinícius Carregosa
Vinícius Carregosa

Posted on

API REST: princípios arquiteturais e comunicação entre sistemas

A comunicação entre diferentes aplicações é um dos fundamentos da engenharia de software moderna. Sistemas precisam compartilhar informações, executar operações e integrar funcionalidades, muitas vezes utilizando tecnologias e linguagens completamente diferentes.

Nesse cenário, as APIs desempenham um papel fundamental, oferecendo interfaces padronizadas para que diferentes aplicações possam se comunicar.

Entre os estilos arquiteturais utilizados para construir essas interfaces, um dos mais conhecidos é o REST (Representational State Transfer).

Embora seja frequentemente associado ao desenvolvimento de APIs HTTP, REST é mais do que um conjunto de convenções para criar endpoints. Trata-se de um estilo arquitetural que estabelece princípios para a construção de sistemas distribuídos, buscando promover escalabilidade, independência entre componentes e uma comunicação uniforme.

Compreender esses princípios permite desenvolver APIs mais consistentes, previsíveis e fáceis de manter.

1. O que é REST?

REST é um estilo arquitetural apresentado por Roy Fielding em sua tese de doutorado, publicada em 2000, intitulada Architectural Styles and the Design of Network-based Software Architectures.

O conceito surgiu a partir da análise de diferentes estilos arquiteturais utilizados na construção de sistemas distribuídos e da identificação de princípios que contribuíram para a evolução da arquitetura da Web.

Seu objetivo é estabelecer restrições arquiteturais que favoreçam características como escalabilidade, simplicidade, visibilidade das interações e independência entre componentes.

Uma aplicação construída seguindo os princípios REST é frequentemente chamada de aplicação RESTful.

É importante estabelecer uma distinção: REST não é um protocolo, uma linguagem de programação ou uma tecnologia específica. É um estilo arquitetural que pode ser aplicado a sistemas distribuídos.

No desenvolvimento de aplicações modernas, sua utilização está fortemente associada ao HTTP, que fornece os mecanismos necessários para a comunicação entre cliente e servidor.

2. Recursos: o elemento central de uma API REST

Um dos conceitos fundamentais do REST é o recurso (resource).

Em vez de organizar a interface da aplicação exclusivamente em torno de operações ou funções, REST propõe que os elementos de interesse do sistema sejam identificados como recursos.

Imagine um sistema de gerenciamento de usuários.

Nesse contexto, podemos identificar diferentes recursos:

  • Usuários;
  • Produtos;
  • Pedidos;
  • Departamentos;
  • Pagamentos.

Cada recurso pode ser identificado por meio de um endereço, geralmente uma URI (Uniform Resource Identifier).

Por exemplo:

GET /users
GET /users/42
GET /products
GET /orders/15
Enter fullscreen mode Exit fullscreen mode

Esses endereços identificam recursos disponíveis na API.

Observe que /users representa uma coleção de usuários, enquanto /users/42 identifica um usuário específico.

Essa organização permite que os clientes interajam com os recursos utilizando uma interface uniforme.

Recursos não são representações

É importante diferenciar o recurso de sua representação.

Um recurso é o elemento conceitual identificado pela API. Sua representação corresponde à maneira como suas informações são transmitidas ao cliente.

Por exemplo, um usuário pode ser representado em JSON:

{
    "id": 42,
    "name": "Vinicius",
    "email": "vinicius@example.com"
}
Enter fullscreen mode Exit fullscreen mode

O mesmo recurso poderia, em determinadas arquiteturas, possuir representações em outros formatos.

Portanto, o recurso não é o próprio JSON. O JSON é apenas uma representação dos dados associados àquele recurso.

Essa distinção é importante porque o REST não determina que os recursos precisem ser armazenados ou transmitidos em um formato específico.

3. Identificação e organização dos recursos

A identificação dos recursos deve seguir uma organização coerente, permitindo que os clientes compreendam a estrutura da API.

Uma convenção bastante utilizada é representar coleções com substantivos no plural.

Exemplo:

GET /users
GET /users/42
GET /users/42/orders
GET /products
Enter fullscreen mode Exit fullscreen mode

Essa estrutura permite representar relações entre recursos.

No exemplo /users/42/orders, estamos identificando os pedidos associados ao usuário de identificador 42.

Algumas boas práticas incluem:

  • Utilizar substantivos para identificar recursos;
  • Manter uma nomenclatura consistente;
  • Evitar representar operações diretamente nos endereços;
  • Organizar recursos relacionados de maneira compreensível;
  • Utilizar identificadores para acessar recursos específicos.

Uma diferença importante pode ser observada nos exemplos abaixo:

GET /getUsers
GET /createUser
GET /deleteUser/42
Enter fullscreen mode Exit fullscreen mode

Esses endereços representam uma abordagem orientada a operações.

Uma organização mais alinhada ao estilo REST seria:

GET /users
POST /users
DELETE /users/42
Enter fullscreen mode Exit fullscreen mode

Nesse segundo exemplo, o recurso permanece identificado pelo endereço, enquanto o método HTTP determina a operação desejada.

Isso contribui para uma interface mais uniforme e previsível.

4. Os métodos HTTP e suas responsabilidades

Os métodos HTTP definem a intenção da operação realizada sobre determinado recurso.

Em uma API RESTful, eles são utilizados para expressar ações como consultar, criar, atualizar e remover informações.

Os principais métodos são:

Método Finalidade Exemplo
GET Consultar recursos GET /users/42
POST Criar recursos ou submeter dados para processamento POST /users
PUT Substituir a representação de um recurso PUT /users/42
PATCH Aplicar alterações parciais em um recurso PATCH /users/42
DELETE Remover um recurso DELETE /users/42

Esses métodos possuem propriedades semânticas importantes.

GET

Utilizado para recuperar informações de um recurso.

GET /users/42
Enter fullscreen mode Exit fullscreen mode

O servidor retorna a representação correspondente ao usuário solicitado.

GET é considerado um método seguro, pois sua semântica não prevê alterações no estado do recurso.

Também é idempotente: realizar a mesma requisição várias vezes produz o mesmo efeito pretendido no servidor.

POST

Utilizado para submeter dados a um recurso, frequentemente resultando na criação de um novo recurso.

POST /users
Content-Type: application/json

{
    "name": "Maria",
    "email": "maria@example.com"
}
Enter fullscreen mode Exit fullscreen mode

O servidor processa os dados recebidos e pode criar um novo usuário.

Diferentemente de GET, POST não é considerado idempotente por padrão. Repetir a mesma requisição pode resultar na criação de múltiplos recursos.

PUT

Utilizado para criar ou substituir o estado de um recurso identificado pela URI.

PUT /users/42
Content-Type: application/json

{
    "name": "Maria",
    "email": "maria@example.com"
}
Enter fullscreen mode Exit fullscreen mode

Nesse cenário, o cliente envia uma representação para substituir a representação atual do recurso.

PUT é considerado idempotente.

PATCH

Utilizado para aplicar modificações parciais em um recurso.

PATCH /users/42
Content-Type: application/json

{
    "name": "Maria"
}
Enter fullscreen mode Exit fullscreen mode

Nesse exemplo, a intenção é modificar apenas o nome do usuário.

Diferentemente de PUT, PATCH não possui garantia de idempotência por padrão. Isso depende da semântica das modificações implementadas.

DELETE

Utilizado para solicitar a remoção de um recurso.

DELETE /users/42
Enter fullscreen mode Exit fullscreen mode

DELETE é considerado idempotente em relação ao efeito pretendido no servidor.

Isso não significa que todas as respostas de requisições repetidas serão necessariamente iguais. A primeira pode retornar 204, enquanto uma tentativa posterior pode retornar 404.

A propriedade de idempotência está relacionada ao efeito da operação, não à igualdade das respostas.

5. Os princípios arquiteturais do REST

A principal característica do REST é que ele não se limita à utilização de métodos HTTP e endereços organizados.

Sua definição estabelece seis restrições arquiteturais.

Essas restrições orientam a organização dos componentes e a maneira como eles interagem.

5.1. Client-Server

O princípio de cliente-servidor estabelece uma separação de responsabilidades entre os componentes.

O cliente é responsável pela interface e pela interação com o usuário, enquanto o servidor concentra o processamento dos dados e as regras relacionadas aos recursos disponibilizados.

Essa separação permite que ambos evoluam de maneira independente, desde que o contrato de comunicação seja preservado.

Por exemplo, uma aplicação frontend desenvolvida em Angular pode consumir uma API construída em Java com Spring Boot.

O frontend não precisa conhecer os detalhes internos da implementação do backend. Precisa apenas compreender como utilizar a interface disponibilizada.

Essa independência facilita a manutenção, a substituição de componentes e a evolução tecnológica.

5.2. Stateless

Stateless é uma das restrições mais importantes do REST.

Significa que cada requisição deve conter todas as informações necessárias para que o servidor consiga compreendê-la e processá-la.

O servidor não deve depender de um contexto de sessão armazenado entre requisições para interpretar a solicitação atual.

Imagine um usuário autenticado que realiza uma consulta:

GET /users/42
Authorization: Bearer eyJhbGciOi...
Enter fullscreen mode Exit fullscreen mode

Em uma arquitetura stateless, as informações necessárias para identificar e autorizar a requisição são transmitidas a cada interação.

Isso não significa que o servidor não possa armazenar dados.

Ele pode possuir bancos de dados, caches, registros de auditoria e outras formas de persistência.

A restrição diz respeito ao estado da comunicação entre cliente e servidor, não à ausência de estado na aplicação como um todo.

Entre os benefícios desse princípio estão:

  • Maior facilidade para distribuir requisições entre diferentes instâncias;
  • Redução da dependência de sessões armazenadas no servidor;
  • Maior previsibilidade das interações;
  • Facilidade para escalar horizontalmente a aplicação.

5.3. Cache

A restrição de cache estabelece que as respostas devem indicar se podem ou não ser armazenadas em cache.

Isso permite que clientes e componentes intermediários reutilizem respostas anteriores quando apropriado.

Imagine uma API que disponibiliza uma lista de categorias de produtos, cujas informações raramente mudam.

Em vez de consultar o servidor a cada acesso, o cliente pode utilizar uma representação armazenada em cache durante determinado período.

O HTTP oferece mecanismos para controlar esse comportamento, como:

  • Cache-Control;
  • ETag;
  • Last-Modified;
  • If-None-Match;
  • If-Modified-Since.

Um exemplo:

HTTP/1.1 200 OK
Cache-Control: public, max-age=3600
ETag: "abc123"
Content-Type: application/json
Enter fullscreen mode Exit fullscreen mode

Nesse caso, a resposta pode ser armazenada em cache por até uma hora, considerando as demais regras aplicáveis.

O uso adequado de cache reduz requisições desnecessárias, diminui a latência e contribui para a eficiência dos sistemas.

5.4. Uniform Interface

A interface uniforme estabelece uma maneira padronizada de interação entre os componentes.

É uma das características que mais influenciam a organização de APIs RESTful.

Sua definição envolve quatro aspectos:

Identificação dos recursos: cada recurso deve possuir uma identificação própria, geralmente por meio de URIs.

Manipulação dos recursos por meio de representações: o cliente interage com os recursos utilizando representações transmitidas nas requisições e respostas.

Mensagens autodescritivas: as mensagens devem conter informações suficientes para que sejam interpretadas adequadamente, considerando elementos como métodos, status codes e headers.

HATEOAS: as respostas podem incluir controles hipermídia que indicam ações e transições disponíveis a partir do estado atual da aplicação.

O último aspecto merece atenção especial.

HATEOAS significa Hypermedia as the Engine of Application State.

A ideia é permitir que o cliente descubra possibilidades de navegação e interação por meio de links fornecidos nas próprias respostas.

Por exemplo:

{
    "id": 42,
    "name": "Vinicius",
    "_links": {
        "self": {
            "href": "/users/42"
        },
        "orders": {
            "href": "/users/42/orders"
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Nesse exemplo, a resposta apresenta links relacionados ao recurso, indicando caminhos disponíveis para continuar a interação.

Isso reduz a necessidade de o cliente conhecer previamente todos os endereços e transições possíveis da aplicação.

HATEOAS é um aspecto frequentemente negligenciado em implementações que se apresentam como RESTful.

5.5. Layered System

O princípio de sistema em camadas estabelece que a arquitetura pode ser organizada em diferentes componentes intermediários.

O cliente não precisa conhecer todos os elementos existentes entre ele e o servidor responsável pelo recurso.

Uma requisição pode atravessar:

  • API Gateway;
  • Load Balancer;
  • Proxy reverso;
  • Camada de autenticação;
  • Serviços internos.

Por exemplo:

Cliente
   |
   v
API Gateway
   |
   v
Serviço de autenticação
   |
   v
Backend
   |
   v
Banco de dados
Enter fullscreen mode Exit fullscreen mode

Cada componente pode desempenhar uma responsabilidade específica, sem que o cliente precise conhecer os detalhes internos dessa organização.

Essa restrição favorece a evolução arquitetural e permite introduzir mecanismos como segurança, balanceamento de carga e monitoramento.

5.6. Code on Demand (opcional)

A última restrição é opcional.

Code on Demand permite que o servidor envie código executável ao cliente, ampliando temporariamente suas funcionalidades.

Um exemplo histórico é o envio de scripts JavaScript para serem executados pelo navegador.

Diferentemente das outras cinco restrições, essa característica não é obrigatória para que uma arquitetura seja considerada RESTful.


6. REST e HTTP: qual é a relação?

Uma confusão bastante comum é considerar REST e HTTP como sinônimos.

Embora estejam fortemente relacionados, são conceitos diferentes.

HTTP é um protocolo de comunicação que define como requisições e respostas são estruturadas e transmitidas.

REST, por sua vez, é um estilo arquitetural que estabelece restrições para a organização de sistemas distribuídos.

O HTTP fornece mecanismos que podem ser utilizados para implementar uma arquitetura RESTful, como:

  • Métodos HTTP;
  • URIs;
  • Headers;
  • Status Codes;
  • Mecanismos de cache;
  • Negociação de conteúdo.

Entretanto, simplesmente utilizar esses mecanismos não garante que uma API siga os princípios REST.

Uma API pode utilizar HTTP, JSON e métodos como GET e POST sem implementar todas as restrições arquiteturais definidas pelo REST.

Por isso, é importante diferenciar uma API HTTP de uma API efetivamente RESTful.

7. REST e RESTful: existe diferença?

Os termos REST e RESTful estão relacionados, mas possuem aplicações diferentes.

REST é o estilo arquitetural definido por Roy Fielding.

RESTful é uma expressão utilizada para descrever sistemas ou APIs que seguem os princípios desse estilo arquitetural.

Na prática, muitas APIs são chamadas de RESTful mesmo quando não implementam integralmente todas as restrições, especialmente HATEOAS.

Isso não significa que sejam necessariamente mal projetadas. Significa apenas que existe uma diferença entre utilizar convenções inspiradas no REST e implementar integralmente seu modelo arquitetural.

Essa distinção é importante para evitar que o termo REST seja utilizado apenas como sinônimo de API HTTP.

8. Versionamento de APIs

À medida que uma aplicação evolui, seu contrato de comunicação também pode precisar mudar.

Imagine uma API que disponibiliza informações de usuários:

{
    "id": 42,
    "name": "Vinicius"
}
Enter fullscreen mode Exit fullscreen mode

Posteriormente, uma alteração estrutural pode modificar os campos disponibilizados, introduzir novas regras ou remover funcionalidades anteriores.

Se essas mudanças quebrarem a compatibilidade com clientes existentes, será necessário estabelecer uma estratégia de evolução do contrato.

Uma abordagem bastante utilizada é o versionamento por URI:

GET /api/v1/users
GET /api/v2/users
Enter fullscreen mode Exit fullscreen mode

Assim, diferentes versões podem coexistir durante um período de transição.

Outras estratégias incluem versionamento por headers e negociação de conteúdo.

É importante observar que o versionamento não é uma restrição do REST. Trata-se de uma decisão de projeto relacionada à evolução e à compatibilidade da API.

O objetivo é permitir que a aplicação evolua sem interromper desnecessariamente os consumidores existentes.

9. Documentação e contrato de uma API REST

Uma API não é consumida apenas por quem a desenvolveu.

Outras equipes, aplicações e serviços podem depender de sua interface. Por isso, é fundamental documentar seu funcionamento.

Uma boa documentação deve apresentar:

  • Recursos disponíveis;
  • Endpoints;
  • Métodos HTTP suportados;
  • Parâmetros de entrada;
  • Estrutura das requisições;
  • Estrutura das respostas;
  • Códigos de status;
  • Requisitos de autenticação e autorização.

Uma ferramenta bastante utilizada nesse contexto é o OpenAPI.

OpenAPI é uma especificação independente de linguagem que permite descrever interfaces de APIs HTTP de maneira estruturada.

Com ela, é possível documentar endpoints, parâmetros, schemas, respostas e mecanismos de autenticação.

Ferramentas como Swagger UI podem utilizar essas especificações para disponibilizar uma documentação interativa.

Esse assunto será aprofundado no próximo artigo, dedicado a JSON, YAML e OpenAPI.


Conclusão

REST representa uma maneira de organizar sistemas distribuídos a partir de princípios que favorecem a independência entre componentes, a escalabilidade e a padronização da comunicação.

Seu funcionamento não depende apenas da escolha de métodos HTTP ou da organização dos endpoints. É necessário compreender conceitos como recursos, representações, statelessness, cache, interface uniforme e sistemas em camadas.

Esses princípios ajudam a construir APIs mais previsíveis, permitindo que diferentes aplicações interajam sem precisar conhecer os detalhes internos umas das outras.

Na engenharia de software, compreender REST significa entender que uma API não é simplesmente um conjunto de rotas disponíveis para o frontend consumir. Ela representa uma interface arquitetural, responsável por estabelecer como diferentes componentes de um sistema se comunicam.

Uma boa API não é definida apenas pelas operações que disponibiliza, mas também pela consistência e pelos princípios que orientam sua interface.

Referências

Top comments (0)