Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Uma implementação de API da Web RESTful é uma API da Web que emprega princípios de arquitetura REST (Representational State Transfer) para obter uma interface sem estado e de ligação frouxa entre um cliente e um serviço. Uma API da Web que é RESTful suporta o protocolo HTTP padrão para executar operações em recursos e retornar representações de recursos que contêm links de hipermídia e códigos de status de operação HTTP.
Uma API Web RESTful deve estar alinhada com os seguintes princípios:
Independência da plataforma, o que significa que os clientes podem chamar a API da Web independentemente da implementação interna. Para alcançar a independência da plataforma, a API da Web usa HTTP como um protocolo padrão, fornece documentação clara e suporta um formato familiar de troca de dados, como JSON ou XML.
Acoplamento flexível, o que significa que o cliente e o serviço Web podem evoluir de forma independente. O cliente não precisa saber a implementação interna do serviço Web, e o serviço Web não precisa saber a implementação interna do cliente. Para obter acoplamento flexível em uma API da Web RESTful, use apenas protocolos padrão e implemente um mecanismo que permita que o cliente e o serviço Web concordem sobre o formato dos dados a serem trocados.
Este artigo descreve as práticas recomendadas para projetar APIs da Web RESTful. Ele também abrange padrões de design comuns e considerações para a criação de APIs da Web que são fáceis de entender, flexíveis e fáceis de manter.
Conceitos de design de API Web RESTful
Para implementar uma API da Web RESTful, você precisa entender os conceitos a seguir.
URI (Uniform Resource Identifier): As APIs REST são projetadas em torno de recursos, que são qualquer tipo de objeto, dados ou serviço que o cliente pode acessar. Cada recurso é representado por um URI que identifica exclusivamente esse recurso. Por exemplo, o URI de um pedido de cliente específico pode ser:
https://api.contoso.com/orders/1A representação de recursos define como um recurso identificado por seu URI é codificado e transportado pelo protocolo HTTP em um formato específico, como XML ou JSON. Os clientes que desejam recuperar um recurso específico devem usar o URI do recurso na solicitação para a API. A API retorna uma representação de recurso dos dados que o URI indica. Por exemplo, um cliente pode fazer uma solicitação GET para o identificador
https://api.contoso.com/orders/1URI para receber o seguinte corpo JSON:{"orderId":1,"orderValue":99.9,"productId":1,"quantity":1}Interface uniforme é como as APIs RESTful conseguem acoplamento flexível entre implementações de cliente e serviço. Para APIs REST criadas em HTTP, a interface uniforme inclui o uso de verbos HTTP padrão para executar operações como
GET,POST,PUT,PATCHeDELETEem recursos.Modelo de solicitação sem estado: As APIs RESTful usam um modelo de solicitação sem monitoração de estado, o que significa que as solicitações HTTP são independentes e podem ocorrer em qualquer ordem. Por esse motivo, manter informações de estado transitórias entre solicitações não é viável. O único local onde as informações são armazenadas é nos próprios recursos, e cada solicitação deve ser uma operação atômica. Um modelo de solicitação sem estado oferece suporte à alta escalabilidade porque não precisa manter nenhuma afinidade entre clientes e servidores específicos. No entanto, o modelo sem estado também pode limitar a escalabilidade devido aos desafios de escalabilidade do armazenamento no back-end dos serviços web. Para obter mais informações sobre estratégias para dimensionar um armazenamento de dados, consulte Particionamento de dados.
Hipermedia links: As APIs REST podem ser orientadas por links de hipermídia contidos em cada representação de recurso. Por exemplo, o bloco de código a seguir mostra uma representação JSON de uma ordem. Ele contém links para obter ou atualizar o cliente associado ao pedido.
{ "orderID":3, "productID":2, "quantity":4, "orderValue":16.60, "links": [ {"rel":"product","href":"https://api.contoso.com/customers/3", "action":"GET" }, {"rel":"product","href":"https://api.contoso.com/customers/3", "action":"PUT" } ] }
Definir URIs de recursos da API da Web RESTful
Uma API da Web RESTful é organizada em torno de recursos. Para organizar o seu design da API em torno de recursos, defina URIs de recursos que correspondam às entidades empresariais. Quando possível, baseie os URIs de recursos em substantivos (o recurso) e não em verbos (as operações no recurso).
Por exemplo, em um sistema de comércio eletrônico, as principais entidades comerciais podem ser clientes e pedidos. Para criar um pedido, um cliente envia as informações do pedido em uma solicitação HTTP POST para o URI do recurso. A resposta HTTP à solicitação indica se a criação do pedido foi bem-sucedida.
A URL para criar o recurso de pedido pode ser algo como:
https://api.contoso.com/orders // Good
Evite usar verbos em URIs para representar operações. Por exemplo, o seguinte URI não é recomendado:
https://api.contoso.com/create-order // Avoid
As entidades são frequentemente agrupadas em coleções, como clientes ou encomendas. Uma coleção é um recurso separado dos itens dentro da coleção, portanto, deve ter seu próprio URI. Por exemplo, o seguinte URI pode representar a coleção de ordens:
https://api.contoso.com/orders
Depois que o cliente recupera a coleção, ele pode fazer uma solicitação GET para o URI de cada item. Por exemplo, para receber informações sobre uma ordem específica, o cliente executa uma solicitação HTTP GET no URI https://api.contoso.com/orders/1 para receber o seguinte corpo JSON como uma representação de recurso dos dados da ordem interna:
{"orderId":1,"orderValue":99.9,"productId":1,"quantity":1}
Convenções de nomenclatura de URI de recursos
Ao criar uma API Web RESTful, é importante usar as convenções de nomenclatura e relacionamento corretas para recursos:
Use substantivos para nomes de recursos. Use substantivos para representar recursos. Por exemplo, use
/ordersem vez de/create-order. Os métodos HTTP GET, POST, PUT, PATCH e DELETE já implicam a ação verbal.Use substantivos no plural para nomear URIs de coleção. Em geral, ajuda a usar substantivos no plural para URIs que fazem referência a coleções. É uma boa prática organizar URIs para coleções e itens em uma hierarquia. Por exemplo,
/customersé o caminho para a coleção do cliente e/customers/5é o caminho para o cliente com um ID igual a 5. Essa abordagem ajuda a manter a API da Web intuitiva. Além disso, muitas estruturas de API da Web podem rotear solicitações com base em caminhos de URI parametrizados, para que você possa definir uma rota para o caminho/customers/{id}.Considere as relações entre diferentes tipos de recursos e como você pode expor essas associações. Por exemplo, o
/customers/5/orderspode representar todos os pedidos para o cliente 5. Você também pode abordar o relacionamento na outra direção, representando a associação de um pedido para um cliente. Nesse cenário, o URI pode ser/orders/99/customer. No entanto, estender este modelo demasiado longe pode tornar-se complicado de implementar. Uma abordagem melhor é incluir links no corpo da mensagem de resposta HTTP para que os clientes possam acessar facilmente os recursos relacionados. Use Hypertext as the Engine of Application State (HATEOAS) para habilitar a navegação para recursos relacionados descreve esse mecanismo com mais detalhes.Mantenha relações simples e flexíveis. Em sistemas mais complexos, você pode estar inclinado a fornecer URIs que permitem que o cliente navegue por vários níveis de relacionamentos, como
/customers/1/orders/99/products. No entanto, este nível de complexidade pode ser difícil de manter e é inflexível se as relações entre os recursos mudarem no futuro. Em vez disso, tente manter os URIs relativamente simples. Depois que um aplicativo tiver uma referência a um recurso, você deverá ser capaz de usar essa referência para localizar itens relacionados a esse recurso. Você pode substituir a consulta anterior pelo URI/customers/1/orderspara localizar todos os pedidos do cliente 1 e, em seguida, usar/orders/99/productspara localizar os produtos nessa ordem.Sugestão
Evite exigir URIs de recursos que sejam mais complexos do que coleção/item/coleção.
Evite um grande número de pequenos recursos. Todas as solicitações da Web impõem uma carga no servidor da Web. Quanto mais solicitações, maior a carga. As APIs da Web que expõem um grande número de pequenos recursos são conhecidas como APIs da Web verbosas. Tente evitar essas APIs porque elas exigem que um aplicativo cliente envie várias solicitações para localizar todos os dados necessários. Em vez disso, considere desnormalizar os dados e combinar informações relacionadas em recursos maiores que podem ser recuperados por meio de uma única solicitação. No entanto, você ainda precisa equilibrar essa abordagem com a sobrecarga de buscar dados de que o cliente não precisa. A recuperação de objetos grandes pode aumentar a latência de uma solicitação e incorrer em mais custos de largura de banda. Para obter mais informações sobre esses antipadrões de desempenho, consulte E/S excessiva e busca desnecessária.
Evite criar APIs que espelhem a estrutura interna de um banco de dados. O objetivo do REST é modelar entidades de negócios e as operações que um aplicativo pode executar nessas entidades. Um cliente não deve ser exposto à implementação interna. Por exemplo, se seus dados estiverem armazenados em um banco de dados relacional, a API da Web não precisará expor cada tabela como uma coleção de recursos. Essa abordagem aumenta a superfície de ataque e pode resultar em vazamento de dados. Em vez disso, pense na API da Web como uma abstração do banco de dados. Se necessário, introduza uma camada de mapeamento entre o banco de dados e a API da Web. Essa camada garante que os aplicativos cliente sejam isolados das alterações no esquema de banco de dados subjacente.
Sugestão
Talvez não seja possível mapear todas as operações implementadas por uma API da Web para um recurso específico. Você pode manipular esses cenários sem recursos por meio de solicitações HTTP que invocam uma função e retornam os resultados como uma mensagem de resposta HTTP.
Por exemplo, uma API da Web que implementa operações simples de calculadora, como adicionar e subtrair, pode fornecer URIs que expõem essas operações como pseudorecursos e usam a cadeia de caracteres de consulta para especificar os parâmetros necessários. Uma solicitação GET para o URI /add?operand1=99&operand2=1 retorna uma mensagem de resposta com o corpo contendo o valor 100.
No entanto, você deve usar essas formas de URIs com moderação.
Definir métodos de API Web RESTful
Os métodos da API da Web RESTful se alinham com os métodos de solicitação e os tipos de mídia definidos pelo protocolo HTTP. Esta seção descreve os métodos de solicitação mais comuns e os tipos de mídia usados em APIs da Web RESTful.
Métodos de solicitação HTTP
O protocolo HTTP define muitos métodos de solicitação que indicam a ação que você deseja executar em um recurso. Os métodos mais comuns usados em APIs da Web RESTful são GET, POST, PUT,PATCH e DELETE. Cada método corresponde a uma operação específica. Ao projetar uma API da Web RESTful, use esses métodos de forma consistente com a definição de protocolo, o recurso que está sendo acessado e a ação que está sendo executada.
É importante lembrar que o efeito de um método de solicitação específico deve depender se o recurso é uma coleção ou um item individual. A tabela a seguir inclui algumas convenções que a maioria das implementações RESTful usa.
Importante
A tabela a seguir usa um exemplo de entidade de comércio customer eletrônico. Uma API da Web não precisa implementar todos os métodos de solicitação. Os métodos que implementa dependem do cenário específico.
| Recurso | PUBLICAR | OBTER | COLOCAR | SUPRIMIR |
|---|---|---|---|---|
| /clientes | Criar um novo cliente | Recuperar todos os clientes | Atualização em massa de clientes | Remover todos os clientes |
| /clientes/1 | Erro | Obter os detalhes do cliente 1 | Atualize os detalhes do cliente 1, se ele existir | Remover cliente 1 |
| /clientes/1/encomendas | Criar um novo pedido para o cliente 1 | Recuperar todos os pedidos para o cliente 1 | Atualização em massa de pedidos para o cliente 1 | Remover todas as encomendas para o cliente 1 |
Solicitações GET
Uma solicitação GET recupera uma representação do recurso no URI especificado. O corpo da mensagem de resposta contém os detalhes do recurso solicitado.
Uma solicitação GET deve retornar um dos seguintes códigos de status HTTP:
| Código de estado de HTTP | Motivo |
|---|---|
| 200 (OK) | O método retornou com êxito o recurso. |
| 204 (Sem conteúdo) | O corpo da resposta não contém nenhum conteúdo, como quando uma solicitação de pesquisa não retorna nenhuma correspondência na resposta HTTP. |
| 404 (Não encontrado) | O recurso solicitado não pode ser encontrado. |
Solicitações POST
Uma solicitação POST deve criar um recurso. O servidor atribui um URI para o novo recurso e retorna esse URI para o cliente.
Importante
Para solicitações POST, um cliente não deve tentar criar seu próprio URI. O cliente deve enviar a solicitação para o URI da coleção e o servidor deve atribuir um URI ao novo recurso. Se um cliente tentar criar seu próprio URI e emitir uma solicitação POST para um URI específico, o servidor retornará o código de status HTTP 400 (BAD REQUEST) para indicar que o método não é suportado.
Em um modelo RESTful, as solicitações POST são usadas para adicionar um novo recurso à coleção que o URI identifica. No entanto, uma solicitação POST também pode ser usada para enviar dados para processamento a um recurso existente, sem a criação de qualquer novo recurso.
Uma solicitação POST deve retornar um dos seguintes códigos de status HTTP:
| Código de estado de HTTP | Motivo |
|---|---|
| 200 (OK) | O método fez algum processamento, mas não cria um novo recurso. O resultado da operação pode ser incluído no corpo da resposta. |
| 201 (Criado) | O recurso foi criado com êxito. O URI do novo recurso é incluído no cabeçalho Location da resposta. O corpo da resposta contém uma representação do recurso. |
| 204 (Sem conteúdo) | O corpo da resposta não contém conteúdo. |
| 400 (Pedido Incorreto) | O cliente colocou dados inválidos no pedido. O corpo da resposta pode conter mais informações sobre o erro ou um link para um URI que fornece mais detalhes. |
| 405 (Método não permitido) | O cliente tentou fazer uma solicitação POST para um URI que não suporta solicitações POST. |
Pedido PUT
Uma solicitação PUT deve atualizar um recurso existente, se ele existir, ou, em alguns casos, criar um novo recurso, se ele não existir. Para fazer uma solicitação PUT:
- O cliente especifica o URI para o recurso e inclui um corpo de solicitação que contém uma representação completa do recurso.
- O cliente faz o pedido.
- Se um recurso que tem esse URI já existir, ele será substituído. Caso contrário, um novo recurso será criado, se a rota oferecer suporte a ele.
Os métodos PUT são aplicados a recursos que são itens individuais, como um cliente específico, em vez de coleções. Um servidor pode suportar atualizações, mas não a criação via PUT. O suporte à criação via PUT depende se o cliente pode atribuir um URI a um recurso de forma significativa e confiável antes que ele exista. Se não for possível, use o POST para criar recursos e fazer com que o servidor atribua o URI. Em seguida, use PUT ou PATCH para atualizar o URI.
Importante
As solicitações PUT devem ser idempotentes, o que significa que enviar a mesma solicitação várias vezes sempre resulta na modificação do mesmo recurso com os mesmos valores. Se um cliente reenviar uma solicitação PUT, os resultados devem permanecer inalterados. Por outro lado, não é garantido que as solicitações POST e PATCH sejam idempotentes.
Uma solicitação PUT deve retornar um dos seguintes códigos de status HTTP:
| Código de estado de HTTP | Motivo |
|---|---|
| 200 (OK) | O recurso foi atualizado com êxito. |
| 201 (Criado) | O recurso foi criado com êxito. O corpo da resposta pode conter uma representação do recurso. |
| 204 (Sem conteúdo) | O recurso foi atualizado com êxito, mas o corpo da resposta não contém nenhum conteúdo. |
| 409 (Conflito) | A solicitação não pôde ser concluída devido a um conflito com o estado atual do recurso. |
Sugestão
Considere a implementação de operações HTTP PUT em massa que podem enviar atualizações em lote para vários recursos em uma coleção. A solicitação PUT deve especificar o URI da coleção. O órgão solicitante deve especificar os detalhes dos recursos a serem modificados. Essa abordagem pode ajudar a reduzir a tagarelice e melhorar o desempenho.
Pedidos de PATCH
Uma solicitação PATCH executa uma atualização parcial para um recurso existente. O cliente especifica o URI para o recurso. O corpo da solicitação especifica um conjunto de alterações a serem aplicadas ao recurso. Esse método pode ser mais eficiente do que usar solicitações PUT porque o cliente envia apenas as alterações e não toda a representação do recurso. PATCH também pode criar um novo recurso especificando um conjunto de atualizações para um recurso vazio ou nulo se o servidor suportar essa ação.
Com uma solicitação PATCH, o cliente envia um conjunto de atualizações para um recurso existente na forma de um documento de patch. O servidor processa o documento de patch para executar a atualização. O documento de patch especifica apenas um conjunto de alterações a serem aplicadas em vez de descrever todo o recurso. A especificação para o método PATCH, RFC 5789, não define um formato específico para documentos de patch. O formato deve ser inferido a partir do tipo de mídia na solicitação.
JSON é um dos formatos de dados mais comuns para APIs da Web. Os dois principais formatos de patch baseados em JSON são JSON patch e JSON merge patch.
O JSON Merge Patch é mais simples do que o JSON Patch. O documento de patch tem a mesma estrutura do recurso JSON original, mas inclui apenas o subconjunto de campos que devem ser alterados ou adicionados. Além disso, um campo pode ser excluído especificando null o valor do campo no documento do patch. Essa especificação significa que o patch de mesclagem não é adequado se o recurso original puder ter valores nulos explícitos.
Por exemplo, suponha que o recurso original tenha a seguinte representação JSON:
{
"name":"gizmo",
"category":"widgets",
"color":"blue",
"price":10
}
Aqui está um possível patch de mesclagem JSON para este recurso:
{
"price":12,
"color":null,
"size":"small"
}
Este patch de mesclagem informa ao servidor para atualizar price, excluir color e adicionar size. Os valores para name e category não são modificados. Para obter mais informações sobre o patch de mesclagem JSON, consulte RFC 7396. O tipo de mídia para o patch de mesclagem JSON é application/merge-patch+json.
O patch de mesclagem não é adequado se o recurso original puder conter valores nulos explícitos, devido ao significado especial de null no documento do patch. O documento de patch também não especifica a ordem em que o servidor deve aplicar as atualizações. Se essa ordem é importante depende dos dados e do domínio. O patch JSON, definido na RFC 6902, é mais flexível porque especifica as alterações como uma sequência de operações a serem aplicadas, incluindo adicionar, remover, substituir, copiar e testar para validar valores. O tipo de mídia para o patch JSON é application/json-patch+json.
Uma solicitação PATCH deve retornar um dos seguintes códigos de status HTTP:
| Código de estado de HTTP | Motivo |
|---|---|
| 200 (OK) | O recurso foi atualizado com êxito. |
| 400 (Pedido Incorreto) | Documento de correção malformado. |
| 409 (Conflito) | O documento de patch é válido, mas as alterações não podem ser aplicadas ao recurso em seu estado atual. |
| 415 (Tipo de mídia não suportado) | O formato de documento de patch não é suportado. |
EXCLUIR solicitações
Uma solicitação DELETE remove o recurso no URI especificado. Uma solicitação DELETE deve retornar um dos seguintes códigos de status HTTP:
| Código de estado de HTTP | Motivo |
|---|---|
| 204 (SEM CONTEÚDO) | O recurso foi excluído com êxito. O processo foi tratado com êxito e o organismo de resposta não contém mais informações. |
| 404 (NÃO ENCONTRADO) | O recurso não existe. |
Tipos MIME de recursos
Representação de recurso é como um recurso identificado por URI é codificado e transportado pelo protocolo HTTP em um formato específico, como XML ou JSON. Os clientes que desejam recuperar um recurso específico devem usar o URI na solicitação para a API. A API responde retornando uma representação de recurso dos dados indicados pelo URI.
No protocolo HTTP, os formatos de representação de recursos são especificados usando tipos de mídia, também chamados de tipos MIME. Para dados não binários, a maioria das APIs da Web suporta JSON (tipo de mídia = application/json) e possivelmente XML (tipo de mídia = application/xml).
O cabeçalho Content-Type em uma solicitação ou resposta especifica o formato de representação do recurso. O exemplo a seguir demonstra uma solicitação POST que inclui dados JSON:
POST https://api.contoso.com/orders
Content-Type: application/json; charset=utf-8
Content-Length: 57
{"Id":1,"Name":"Gizmo","Category":"Widgets","Price":1.99}
Se o servidor não suportar o tipo de mídia, ele deverá retornar o código de status HTTP 415 (Tipo de mídia não suportado).
Uma solicitação de cliente pode incluir um cabeçalho Accept que contém uma lista de tipos de mídia que o cliente aceita do servidor na mensagem de resposta. Por exemplo:
GET https://api.contoso.com/orders/2
Accept: application/json, application/xml
Se o servidor não puder corresponder a nenhum dos tipos de mídia listados, ele deverá retornar o código de status HTTP 406 (Não Aceitável).
Implementar métodos assíncronos
Às vezes, um método POST, PUT, PATCH ou DELETE pode exigir um processamento que leva tempo para ser concluído. Se você aguardar a conclusão antes de enviar uma resposta ao cliente, isso pode causar latência inaceitável. Nesse cenário, considere tornar o método assíncrono. Um método assíncrono deve retornar o código de status HTTP 202 (Aceito) para indicar que a solicitação foi aceita para processamento, mas está incompleta.
Exponha um ponto de extremidade que retorne o estado de uma solicitação assíncrona, para permitir que o cliente monitore o estado interrogando o ponto de extremidade de estado. Inclua o URI do ponto de extremidade de status no cabeçalho Location da resposta 202. Por exemplo:
HTTP/1.1 202 Accepted
Location: /api/status/12345
Se o cliente enviar uma solicitação GET para esse ponto de extremidade, a resposta deverá conter o status atual da solicitação. Opcionalmente, pode incluir um tempo estimado para a conclusão ou um link para cancelar a operação.
HTTP/1.1 200 OK
Content-Type: application/json
{
"status":"In progress",
"link": { "rel":"cancel", "method":"delete", "href":"/api/status/12345" }
}
Se a operação assíncrona criar um novo recurso, o endpoint de estado deverá retornar o código de status 303 (Ver Outro) após a conclusão da operação. Na resposta 303, inclua um cabeçalho Location que forneça o URI do novo recurso:
HTTP/1.1 303 See Other
Location: /api/orders/12345
Para obter mais informações, consulte Fornecer suporte assíncrono para solicitações de longa execução e Padrão de Request-Reply assíncrono.
Implementar paginação e filtragem de dados
Para otimizar a recuperação de dados e reduzir o tamanho da carga útil, implemente a paginação de dados e a filtragem baseada em consultas em seu design de API. Essas técnicas permitem que os clientes solicitem apenas o subconjunto de dados de que precisam, o que pode melhorar o desempenho e reduzir o uso de largura de banda.
A paginação divide grandes conjuntos de dados em partes menores e gerenciáveis. Use parâmetros de consulta como
limitespecificar o número de itens a serem retornados eoffsetespecificar o ponto de partida. Certifique-se também de fornecer padrões significativos paralimiteoffset, comolimit=25eoffset=0. Por exemplo:GET /orders?limit=25&offset=50limit: Especifica o número máximo de itens a serem devolvidos.Sugestão
Para ajudar a evitar ataques de negação de serviço, considere impor um limite máximo para o número de itens devolvidos. Por exemplo, se o serviço definir
max-limit=25e um cliente solicitarlimit=1000, o serviço poderá retornar 25 itens ou um erro de BAD-REQUEST HTTP, dependendo da documentação da API.offset: Especifica o índice inicial para os dados.
A filtragem permite que os clientes refinem o conjunto de dados aplicando condições. A API pode permitir que o cliente passe o filtro na cadeia de caracteres de consulta do URI:
GET /orders?minCost=100&status=shipped-
minCost: Filtra pedidos que têm um custo mínimo de 100. -
status: Filtra ordens que têm um status específico.
-
Considere as seguintes práticas recomendadas:
A classificação permite que os clientes classifiquem os dados usando um
sortparâmetro comosort=price.Importante
A abordagem de classificação pode ter um efeito negativo no cache porque os parâmetros da cadeia de caracteres de consulta fazem parte do identificador de recurso que muitas implementações de cache usam como a chave para os dados armazenados em cache.
A seleção de campos para projeções definidas pelo cliente permite que os clientes especifiquem apenas os campos de que precisam usando um
fieldsparâmetro comofields=id,name. Por exemplo, você pode usar um parâmetro de cadeia de caracteres de consulta que aceite uma lista delimitada por vírgulas de campos, como /orders?fields=ProductID,Quantity.
Sua API deve validar os campos solicitados para garantir que o cliente tenha permissão para acessá-los e não exponha campos que normalmente não estão disponíveis por meio da API.
Apoio a respostas parciais
Alguns recursos contêm campos binários grandes, como arquivos ou imagens. Para superar problemas causados por conexões não confiáveis e intermitentes e melhorar os tempos de resposta, considere apoiar a recuperação parcial de grandes recursos binários.
Para oferecer suporte a respostas parciais, a API da Web deve suportar o cabeçalho Accept-Ranges para solicitações GET para grandes recursos. Esse cabeçalho indica que a operação GET oferece suporte a solicitações parciais. O aplicativo cliente pode enviar solicitações GET que retornam um subconjunto de um recurso, especificado como um intervalo de bytes.
Além disso, considere a implementação de solicitações HTTP HEAD para esses recursos. Uma solicitação HEAD é semelhante a uma solicitação GET, exceto que ela retorna apenas os cabeçalhos HTTP que descrevem o recurso, com um corpo de mensagem vazio. Um aplicativo cliente pode emitir uma solicitação HEAD para determinar se deseja buscar um recurso usando solicitações GET parciais. Por exemplo:
HEAD https://api.contoso.com/products/10?fields=productImage
Aqui está um exemplo de mensagem de resposta:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 4580
O cabeçalho Content-Length fornece o tamanho total do recurso e o cabeçalho Accept-Ranges indica que a operação GET correspondente suporta resultados parciais. O aplicativo cliente pode usar essas informações para recuperar a imagem em partes menores. A primeira solicitação busca os primeiros 2.500 bytes usando o cabeçalho Range:
GET https://api.contoso.com/products/10?fields=productImage
Range: bytes=0-2499
A mensagem de resposta indica que essa resposta é parcial retornando o código de status HTTP 206. O cabeçalho Content-Length especifica o número real de bytes retornados no corpo da mensagem e não o tamanho do recurso. O cabeçalho Content-Range indica qual parte do recurso é retornada (bytes 0-2499 de 4580):
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 2500
Content-Range: bytes 0-2499/4580
[...]
Uma solicitação subsequente do aplicativo cliente pode recuperar o restante do recurso.
Implementar HATEOAS
Uma das principais razões para usar REST é a capacidade de navegar por todo o conjunto de recursos sem conhecimento prévio do esquema URI. Cada solicitação HTTP GET deve retornar as informações necessárias para encontrar os recursos relacionados diretamente ao objeto solicitado por meio de hiperlinks incluídos na resposta. O pedido deve também receber informações que descrevam as operações disponíveis em cada um destes recursos. Este princípio é conhecido como HATEOAS, ou Hipertexto como o Motor do Estado da Aplicação. O sistema é efetivamente uma máquina de estado finito, e a resposta a cada solicitação contém as informações necessárias para se mover de um estado para outro. Nenhuma outra informação deve ser necessária.
Observação
Não existem normas de uso geral que definam como modelar o princípio HATEOAS. Os exemplos nesta seção ilustram uma possível solução proprietária.
Por exemplo, para lidar com a relação entre um pedido e um cliente, a representação de um pedido pode incluir links que identifiquem as operações disponíveis para o cliente do pedido. O bloco de código a seguir é uma representação possível:
{
"orderID":3,
"productID":2,
"quantity":4,
"orderValue":16.60,
"links":[
{
"rel":"customer",
"href":"https://api.contoso.com/customers/3",
"action":"GET",
"types":["text/xml","application/json"]
},
{
"rel":"customer",
"href":"https://api.contoso.com/customers/3",
"action":"PUT",
"types":["application/x-www-form-urlencoded"]
},
{
"rel":"customer",
"href":"https://api.contoso.com/customers/3",
"action":"DELETE",
"types":[]
},
{
"rel":"self",
"href":"https://api.contoso.com/orders/3",
"action":"GET",
"types":["text/xml","application/json"]
},
{
"rel":"self",
"href":"https://api.contoso.com/orders/3",
"action":"PUT",
"types":["application/x-www-form-urlencoded"]
},
{
"rel":"self",
"href":"https://api.contoso.com/orders/3",
"action":"DELETE",
"types":[]
}]
}
Neste exemplo, a links matriz tem um conjunto de links. Cada link representa uma operação em uma entidade relacionada. Os dados para cada link incluem o relacionamento ("cliente"), o URI (https://api.contoso.com/customers/3), o método HTTP e os tipos MIME suportados. O aplicativo cliente precisa dessas informações para invocar a operação.
A links matriz também inclui informações de autorreferência sobre o recurso recuperado. Estes elos têm a relação self.
O conjunto de links retornados pode mudar dependendo do estado do recurso. A ideia de que o hipertexto é o mecanismo do estado do aplicativo descreve esse cenário.
Implementar controle de versão
Uma API da Web não permanece estática. À medida que os requisitos de negócios mudam, novas coleções de recursos são adicionadas. À medida que novos recursos são adicionados, as relações entre os recursos podem mudar e a estrutura dos dados nos recursos pode ser alterada. Atualizar uma API da Web para lidar com requisitos novos ou diferentes é um processo simples, mas você deve considerar os efeitos que essas alterações têm nos aplicativos cliente que consomem a API da Web. O desenvolvedor que projeta e implementa uma API da Web tem controle total sobre essa API, mas não tem o mesmo grau de controle sobre os aplicativos cliente criados por organizações parceiras. É importante continuar a dar apoio às aplicações cliente existentes, permitindo que novas aplicações cliente utilizem novas funcionalidades e recursos.
Uma API da Web que implementa o controle de versão pode indicar os recursos e recursos que expõe, e um aplicativo cliente pode enviar solicitações direcionadas a uma versão específica de um recurso ou recurso. As seções a seguir descrevem várias abordagens diferentes, cada uma com seus próprios benefícios e compensações.
Sem versionamento
Essa abordagem é a mais simples e pode funcionar para algumas APIs internas. Mudanças significativas podem ser representadas como novos recursos ou novos links. Adicionar conteúdo a recursos existentes pode não apresentar uma alteração significativa porque os aplicativos cliente que não esperam ver esse conteúdo o ignoram.
Por exemplo, uma solicitação para o URI https://api.contoso.com/customers/3 deve retornar os detalhes de um único cliente que contém os idcampos , namee address que o aplicativo cliente espera:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","address":"1 Microsoft Way Redmond WA 98053"}
Observação
Para simplificar, as respostas de exemplo mostradas nesta seção não incluem links HATEOAS.
Se o DateCreated campo for adicionado ao esquema do recurso do cliente, a resposta será semelhante a:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","dateCreated":"2025-03-22T12:11:38.0376089Z","address":"1 Microsoft Way Redmond WA 98053"}
Os aplicativos cliente existentes podem continuar a funcionar corretamente se puderem ignorar campos não reconhecidos. Enquanto isso, novos aplicativos cliente podem ser projetados para lidar com esse novo campo. No entanto, podem ocorrer modificações mais drásticas no esquema de recursos, incluindo a remoção ou alteração de nome de campos. Ou as relações entre recursos podem mudar. Essas atualizações podem constituir alterações significativas que impedem que os aplicativos cliente existentes funcionem corretamente. Nesses cenários, considere uma das seguintes abordagens:
- Controle de versão de URI
- Versionamento de string de consulta
- Versionamento de cabeçalho
- Versionamento de tipos de mídia
Controle de versão de URI
Sempre que você modifica a API da Web ou altera o esquema de recursos, adiciona um número de versão ao URI de cada recurso. Os URIs existentes anteriormente devem continuar a operar normalmente, retornando recursos que estejam em conformidade com seu esquema original.
Por exemplo, o address campo no exemplo anterior é reestruturado em subcampos que contêm cada parte constituinte do endereço, como streetAddress, city, statee zipCode. Esta versão do recurso pode ser exposta através de um URI que contém um número de versão, como https://api.contoso.com/v2/customers/3:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","dateCreated":"2025-03-22T12:11:38.0376089Z","address":{"streetAddress":"1 Microsoft Way","city":"Redmond","state":"WA","zipCode":98053}}
Esse mecanismo de controle de versão é simples, mas depende do servidor para rotear a solicitação para o ponto de extremidade apropriado. No entanto, ele pode se tornar pesado à medida que a API da Web amadurece através de várias iterações e o servidor tem que suportar muitas versões diferentes. Do ponto de vista de um purista, em todos os casos, os aplicativos cliente buscam os mesmos dados (cliente 3), portanto, o URI não deve diferir de acordo com a versão. Esse esquema também complica a implementação do HATEOAS porque todos os links precisam incluir o número da versão em seus URIs.
Versionamento de string de consulta
Em vez de fornecer vários URIs, você pode especificar a versão do recurso usando um parâmetro dentro da cadeia de caracteres de consulta anexada à solicitação HTTP, como https://api.contoso.com/customers/3?version=2. O parâmetro version deve usar como padrão um valor significativo, como 1, se aplicativos cliente mais antigos o omitirem.
Essa abordagem tem a vantagem semântica de que o mesmo recurso é sempre recuperado do mesmo URI. No entanto, esse método depende do código que manipula a solicitação para analisar a cadeia de caracteres de consulta e enviar de volta a resposta HTTP apropriada. Esta abordagem também complica a implementação de HATEOAS da mesma forma que o mecanismo de versionamento de URI.
Observação
Alguns navegadores e proxies da Web mais antigos não armazenam em cache respostas para solicitações que incluem uma cadeia de caracteres de consulta no URI. As respostas não armazenadas em cache podem degradar o desempenho de aplicativos da Web que usam uma API da Web e são executados a partir de um navegador da Web mais antigo.
Versionamento de Cabeçalho
Em vez de acrescentar o número da versão como um parâmetro de cadeia de caracteres de consulta, você pode implementar um cabeçalho personalizado que indica a versão do recurso. Essa abordagem requer que o aplicativo cliente adicione o cabeçalho apropriado a todas as solicitações. No entanto, o código que manipula a solicitação do cliente pode usar um valor padrão, como a versão 1, se o cabeçalho da versão for omitido.
Os exemplos a seguir usam um cabeçalho personalizado chamado Custom-Header. O valor desse cabeçalho indica a versão da API da Web.
Versão 1:
GET https://api.contoso.com/customers/3
Custom-Header: api-version=1
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","address":"1 Microsoft Way Redmond WA 98053"}
Versão 2:
GET https://api.contoso.com/customers/3
Custom-Header: api-version=2
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","dateCreated":"2025-03-22T12:11:38.0376089Z","address":{"streetAddress":"1 Microsoft Way","city":"Redmond","state":"WA","zipCode":98053}}
Semelhante ao versionamento de URI e ao versionamento de string de consulta, deve-se incluir o cabeçalho personalizado em todos os links para implementar HATEOAS.
Controle de versão de tipo de mídia
Quando um aplicativo cliente envia uma solicitação HTTP GET para um servidor Web, ele deve usar um cabeçalho Accept para especificar o formato do conteúdo que ele pode manipular. Normalmente, o objetivo do cabeçalho Accept é permitir que o aplicativo cliente especifique se o corpo da resposta deve ser XML, JSON ou algum outro formato comum que o cliente possa analisar. No entanto, é possível definir tipos de mídia personalizados que incluem informações que permitem que o aplicativo cliente indique qual versão de um recurso ele espera.
O exemplo a seguir mostra uma solicitação que especifica um cabeçalho Accept com o valor application/vnd.contoso.v1+json. O vnd.contoso.v1 elemento indica ao servidor Web que ele deve retornar a versão 1 do recurso. O json elemento especifica que o formato do corpo da resposta deve ser JSON:
GET https://api.contoso.com/customers/3
Accept: application/vnd.contoso.v1+json
O código que lida com a solicitação é responsável por processar o cabeçalho Aceitar e honrá-lo tanto quanto possível. O aplicativo cliente pode especificar vários formatos no cabeçalho Accept, o que permite que o servidor Web escolha o formato mais apropriado para o corpo da resposta. O servidor Web confirma o formato dos dados no corpo da resposta usando o cabeçalho Content-Type:
HTTP/1.1 200 OK
Content-Type: application/vnd.contoso.v1+json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","address":"1 Microsoft Way Redmond WA 98053"}
Se o cabeçalho Aceitar não especificar nenhum tipo de mídia conhecido, o servidor Web poderá gerar uma mensagem de resposta HTTP 406 (Não Aceitável) ou retornar uma mensagem com um tipo de mídia padrão.
Este mecanismo de versionamento é simples e adequado para HATEOAS, que pode incluir o tipo MIME de dados relacionados em links de recursos.
Observação
Quando se seleciona uma estratégia de versionamento, é importante considerar as implicações, especialmente em relação ao cache do servidor web. Os esquemas de controlo de versão de URI e de sequência de consulta são amigáveis para cache porque a mesma combinação de URI ou sequência de consulta refere-se aos mesmos dados todas as vezes.
Os mecanismos de controle de versão de cabeçalho e de tipo de mídia normalmente exigem mais lógica para examinar os valores no cabeçalho personalizado ou no cabeçalho Accept. Em um ambiente de grande escala, muitos clientes que usam versões diferentes de uma API da Web podem resultar em uma quantidade significativa de dados duplicados em um cache do lado do servidor. Esse problema pode se tornar agudo se um aplicativo cliente se comunicar com um servidor Web por meio de um proxy que implementa o cache e só encaminha uma solicitação para o servidor Web se ele não contiver atualmente uma cópia dos dados solicitados em seu cache.
APIs da Web multilocatárias
Uma solução de API da Web multilocatária é compartilhada por vários locatários, como organizações distintas que têm seus próprios grupos de usuários.
A arquitetura multitenant afeta significativamente o design da web API porque dita como os recursos são acessados e descobertos entre múltiplos locatários dentro de uma única web API. Conceba uma API tendo em mente a multilocação para ajudar a evitar a necessidade de refatoração futura para implementar isolamento, escalabilidade ou personalizações específicas do inquilino.
Uma API bem arquitetada deve definir claramente como os locatários são identificados nas solicitações, seja por meio de subdomínios, caminhos, cabeçalhos ou tokens. Essa estrutura garante uma experiência consistente e flexível para todos os usuários dentro do sistema. Para obter mais informações, consulte Mapear solicitações para locatários em uma solução multilocatário.
A multilocação afeta a estrutura do ponto final, o tratamento de solicitações, a autenticação e a autorização. Essa abordagem também influencia como gateways de API, balanceadores de carga e serviços de back-end roteiam e processam solicitações. As estratégias a seguir são maneiras comuns de alcançar a multilocação em uma API da Web.
Utilizar isolamento baseado em subdomínio ou domínio (tenência ao nível DNS)
Essa abordagem roteia solicitações usando domínios específicos do locatário. Os domínios universais utilizam subdomínios para flexibilidade e simplicidade. Os domínios personalizados, que permitem que os locatários usem seus próprios domínios, fornecem maior controle e podem ser adaptados para atender a necessidades específicas. Ambos os métodos dependem da configuração adequada de DNS, incluindo A e CNAME registros, para direcionar o tráfego para a infraestrutura apropriada. Os domínios curinga simplificam a configuração, mas os domínios personalizados fornecem uma experiência de marca melhor.
Preserve o nome do host entre o proxy reverso e os serviços de back-end para ajudar a evitar problemas como redirecionamento de URL e prevenir a divulgação de URLs internas. Esse método garante o roteamento correto do tráfego específico do locatário e ajuda a proteger a infraestrutura interna. A resolução de DNS é crucial para alcançar a residência de dados e garantir a conformidade regulamentar.
GET https://adventureworks.api.contoso.com/orders/3
Encaminhar cabeçalhos HTTP específicos do locatário
As informações do locatário podem ser passadas através de cabeçalhos HTTP personalizados, como X-Tenant-ID ou X-Organization-ID ou através de cabeçalhos baseados em host, como Host ou X-Forwarded-Host, ou podem ser extraídas de declarações JSON Web Token (JWT). A escolha depende das capacidades de roteamento do seu gateway de API ou proxy reverso, com soluções baseadas em cabeçalho que exigem um gateway de Camada 7 (L7) para inspecionar cada pedido. Esse requisito adiciona sobrecarga de processamento, o que aumenta os custos de computação quando o tráfego aumenta. No entanto, o isolamento baseado em cabeçalho oferece benefícios importantes. Ele permite a autenticação centralizada, o que simplifica o gerenciamento de segurança em APIs multilocatário. Usando SDKs ou clientes de API, o contexto do inquilino é gerido de forma dinâmica durante a execução, o que reduz a complexidade da configuração do lado do cliente. Além disso, manter o contexto do locatário nos cabeçalhos resulta em um design de API mais limpo e RESTful, evitando dados específicos do locatário no URI.
Uma consideração importante para o roteamento baseado em cabeçalho é que ele complica o cache, particularmente quando as camadas de cache dependem apenas de chaves baseadas em URI e não levam em conta cabeçalhos. Como a maioria dos mecanismos de cache otimiza pesquisas de URI, confiar em cabeçalhos pode levar a entradas de cache fragmentadas. As entradas fragmentadas reduzem os acessos ao cache e aumentam a carga de back-end. Mais importante, se uma camada de cache não diferenciar respostas por cabeçalhos, ela poderá fornecer dados armazenados em cache destinados a um locatário para outro e criar um risco de vazamento de dados.
GET https://api.contoso.com/orders/3
X-Tenant-ID: adventureworks
ou
GET https://api.contoso.com/orders/3
Host: adventureworks
ou
GET https://api.contoso.com/orders/3
Authorization: Bearer <JWT-token including a tenant-id: adventureworks claim>
Transmitir informações específicas do locatário através do caminho URI
Esta abordagem acrescenta identificadores de inquilino na hierarquia de recursos e depende do gateway de API ou proxy reverso para determinar o inquilino apropriado com base no segmento de caminho. O isolamento baseado em caminho é eficaz, mas compromete o design RESTful da API da Web e introduz uma lógica de roteamento mais complexa. Muitas vezes, requer correspondência de padrões ou expressões regulares para analisar e canonizar o caminho URI.
Por outro lado, o isolamento baseado em cabeçalho transmite informações do inquilino por meio de cabeçalhos HTTP sob a forma de pares chave-valor. Ambas as abordagens permitem o compartilhamento eficiente de infraestrutura para reduzir os custos operacionais e melhorar o desempenho em APIs da Web multilocatárias de grande escala.
GET https://api.contoso.com/tenants/adventureworks/orders/3
Habilitar o rastreamento distribuído e o contexto de rastreamento em APIs
À medida que os sistemas distribuídos e as arquiteturas de microsserviços se tornam o padrão, a complexidade das arquiteturas modernas aumenta. Usar cabeçalhos, como Correlation-ID, X-Request-IDou X-Trace-ID, para propagar o contexto de rastreamento em solicitações de API é uma prática recomendada para obter visibilidade de ponta a ponta. Essa abordagem permite o rastreamento de solicitações à medida que elas fluem do cliente para os serviços de back-end. Ele facilita a rápida identificação de falhas, monitora a latência e mapeia as dependências da API entre serviços.
As APIs que suportam a inclusão de informações de rastreamento e contexto aprimoram seu nível de observabilidade e recursos de depuração. Ao habilitar o rastreamento distribuído, essas APIs permitem uma compreensão mais granular do comportamento do sistema e facilitam o rastreamento, o diagnóstico e a resolução de problemas em ambientes complexos de vários serviços.
GET https://api.contoso.com/orders/3
Correlation-ID: aaaa0000-bb11-2222-33cc-444444dddddd
HTTP/1.1 200 OK
...
Correlation-ID: aaaa0000-bb11-2222-33cc-444444dddddd
{...}
Modelo de maturidade da API Web
Em 2008, Leonard Richardson propôs o que agora é conhecido como o Modelo de Maturidade de Richardson (RMM) para APIs da web. O RMM define quatro níveis de maturidade para APIs da Web e é baseado nos princípios do REST como uma abordagem arquitetônica para projetar serviços da Web. No RMM, à medida que o nível de maturidade aumenta, a API torna-se mais RESTful e segue mais de perto os princípios do REST.
Os níveis são:
- Nível 0: Defina um URI e todas as operações são solicitações POST para esse URI. Os serviços Web do Simple Object Access Protocol normalmente estão nesse nível.
- Nível 1: Crie URIs separados para recursos individuais. Este nível ainda não é RESTful, mas começa a alinhar-se com o design RESTful.
- Nível 2: Use métodos HTTP para definir operações em recursos. Na prática, muitas APIs da Web publicadas se alinham aproximadamente a esse nível.
- Nível 3: Use hipermídia (HATEOAS). Este nível é realmente uma API RESTful, de acordo com a definição de Fielding.
Iniciativa OpenAPI
A OpenAPI Initiative foi criada por um consórcio do setor para padronizar as descrições da API REST entre fornecedores. A especificação de padronização foi chamada Swagger antes de ser trazida para a OpenAPI Initiative e renomeada para OpenAPI Specification (OAS).
Você pode querer adotar OpenAPI para suas APIs da Web RESTful. Considere os seguintes pontos:
A OEA vem com um conjunto de diretrizes opinativas para o design da API REST. As diretrizes são vantajosas para a interoperabilidade, mas exigem que você garanta que seu projeto esteja em conformidade com as especificações.
O OpenAPI promove uma abordagem de contrato-primeiro em vez de uma abordagem de implementação-primeiro. Contract-first significa que você projeta o contrato de API (a interface) primeiro e, em seguida, escreve o código que implementa o contrato.
Ferramentas como Swagger (OpenAPI) podem gerar bibliotecas de clientes ou documentação a partir de contratos de API. Para obter um exemplo, consulte documentação da API web do ASP.NET Core com Swagger/OpenAPI.
Próximos passos
- Consulte recomendações detalhadas para projetar APIs REST no Azure.
- Veja uma lista de verificação de itens a serem considerados ao projetar e implementar uma API da Web.
- Crie software como serviço e arquiteturas de solução multilocatária no Azure.