Crie uma solicitação com o POST, que codifica resposta 200 ou 201 e conteúdo

125

Suponha que eu escreva um serviço REST cuja intenção seja adicionar um novo item de dados a um sistema.

Eu pretendo postar para

http://myhost/serviceX/someResources

Suponha que funcione, que código de resposta devo usar? E que conteúdo devo retornar?

Estou olhando para as definições dos códigos de resposta HTTP e veja estas possibilidades:

200: Retorna uma entidade que descreve ou contém o resultado da ação;

201: o que significa CREATED. Significado * A solicitação foi atendida e resultou na criação de um novo recurso. O recurso recém-criado pode ser referenciado pelos URIs retornados na entidade da resposta, com o URI mais específico para o recurso fornecido por um campo de cabeçalho Local. A resposta DEVE incluir uma entidade que contenha uma lista de características de recursos e localizações a partir das quais o usuário ou agente de usuário possa escolher o mais apropriado. O formato da entidade é especificado pelo tipo de mídia fornecido no campo de cabeçalho Content-Type. *

O último parece mais de acordo com as especificações Http, mas não estou claro o que

A resposta DEVE incluir uma entidade que contenha uma lista de características e localizações de recursos

significa.

Recomendações? Interpretações?

djna
fonte

Respostas:

77

A idéia é que o corpo da resposta forneça uma página que o vincule à coisa:

201 Criado

O código de status 201 (criado) indica que a solicitação foi atendida e resultou na criação de um ou mais novos recursos. O recurso principal criado pela solicitação é identificado por um campo de cabeçalho Local na resposta ou, se nenhum campo Localização for recebido, pelo URI da solicitação efetiva.

Isso significa que você incluiria um Locationno cabeçalho de resposta que fornece a URL de onde você pode encontrar a coisa recém-criada :

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597

Corpo de resposta

Depois, eles mencionam o que você deve incluir no corpo da resposta :

A carga útil da resposta 201 normalmente descreve e vincula os recursos criados.

Para os humanos que usam o navegador, dê a eles algo que eles possam ver e clique para acessar o recurso recém-criado:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: text/html

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

Se a página for usada apenas por um robô, faz sentido que a resposta seja legível por computador:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/xml

<createdResources>
   <questionID>1860645</questionID>
   <answerID>36373586</answerID>
   <primary>/a/36373586/12597</primary>
   <additional>
      <resource>http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586</resource>
      <resource>http://stackoverflow.com/a/1962757/12597</resource>
   </additional>
</createdResource>

Ou, se você preferir:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/json

{ 
   "questionID": 1860645, 
   "answerID": 36373586,
   "primary": "/a/36373586/12597",
   "additional": [
      "http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586",
      "http://stackoverflow.com/a/36373586/12597"
   ]
}

A resposta é inteiramente sua; é arbitrariamente o que você gostaria.

Compatível com cache

Finalmente, há a otimização de que eu posso pré-armazenar em cache o recurso criado (porque eu já tenho o conteúdo; acabei de carregá-lo). O servidor pode retornar uma data ou ETag que eu possa armazenar com o conteúdo que acabei de enviar:

Consulte a Seção 7.2 para obter uma discussão sobre o significado e a finalidade dos campos de cabeçalho do validador, como ETag e Last-Modified, em uma resposta 201.

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/23704283/12597
Content-Type: text/html
ETag: JF2CA53BOMQGU5LTOQQGC3RAMV4GC3LQNRSS4
Last-Modified: Sat, 02 Apr 2016 12:22:39 GMT 

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

E ETags são valores puramente arbitrários. Tê-los diferentes quando um recurso é alterado (e os caches precisam ser atualizados) é o que importa. O ETag é geralmente um hash (por exemplo, SHA2). Mas pode ser um banco de dados rowversionou um número de revisão incremental. Qualquer coisa que mudará quando a coisa mudar.

Ian Boyd
fonte
Até agora, sua resposta parece mais sensata. Estou um pouco ansioso com a ontologia da resposta, mas, além disso, parece a interpretação mais madura das especificações. Estou curioso para saber se existe algum meio leve e "responsivo" de lidar com a saída humana / máquina. mas, principalmente, estou intrigado com a sugestão de "colocar em cache sua própria entrada". A maioria dos aplicativos da web que conheço não criará uma versão 1: 1 do recurso. Mesmo que seja algo trivial como normalizar a capitalização de uma string. Não é um pouco complicado tratar sua versão enviada como a versão em que a etag foi criada?
Anthony
1
@ Anthony, cache: poderia ser um tipo de aplicativo de armazenamento de arquivos 1: 1. Compare, por exemplo, WebDAV PUT & POST. Arquivos enormes a serem manipulados.
Kxr
@ Anthony Depende de você se você deseja devolver uma ETag de volta ao cliente. Se o conteúdo que o cliente acabou de enviar não for o que você salvou, não retorne o ETag. É sua flexibilidade e sua escolha.
22617 Ian Boyd
Por que suas respostas estão ausentes do comprimento do conteúdo?
Vinnie Falco
1
@VinnieFalco Esta é uma resposta sobre o código de resposta 201. O comprimento do conteúdo foi escolhido para fins expositivos.
11268 Ian Boyd
91

Eu acho que a API REST atompub é um ótimo exemplo de serviço repousante. Veja o snippet abaixo na especificação atompub:

POST /edit/ HTTP/1.1
Host: example.org
User-Agent: Thingio/1.0
Authorization: Basic ZGFmZnk6c2VjZXJldA==
Content-Type: application/atom+xml;type=entry
Content-Length: nnn
Slug: First Post

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
</entry>

O servidor sinaliza uma criação bem-sucedida com um código de status 201. A resposta inclui um cabeçalho Location indicando o URI da Entrada de Membro da Atom Atom e uma representação dessa Entrada no corpo da resposta.

HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content-Length: nnn
Content-Type: application/atom+xml;type=entry;charset="utf-8"
Location: http://example.org/edit/first-post.atom
ETag: "c180de84f991g8"  

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
  <link rel="edit"
      href="http://example.org/edit/first-post.atom"/>
</entry>

A Entrada criada e retornada pela Coleção pode não corresponder à Entrada POSTADA pelo cliente. Um servidor PODE alterar os valores de vários elementos da Entrada, como os valores atom: id, atom: updated e atom: author, e PODE optar por remover ou adicionar outros elementos e atributos, ou alterar o conteúdo e os valores dos atributos.

Chandra Patni
fonte
9
Retornando o recurso criado pode ser um pouco demais, se o recurso está na magnitude gigabytes ...
Tor Valamo
10
Acordado! Essa é a otimização da necessidade - mas você não deseja fazê-lo prematuramente. É importante projetar com espírito tranqüilo e fazer exceções somente quando forem necessárias.
Chandra Patni
3
@ChandraPatni, Atom está morto . Precisa de melhores exemplos.
Pacerier
16
Atom pode estar morto, mas o espírito do exemplo ainda está presente.
Ashimema 27/10/2015
2
Minha interpretação original da resposta 201 foi mais como "ei, você queria criar um recurso, mas com base no contexto, você não estava interessado no resultado final ou tem acesso de gravação, mas não acesso de leitura a esse recurso. Nesse caso, tudo o que você precisa antes de retornar à coleção principal é a URL do recurso criado. Como evidência, ele foi criado. " Qualquer coisa além disso parece uma resposta de 200, essencialmente. A menos que a RFC tivesse outra coisa em mente.
Anthony
50

Em poucas palavras:

  • 200 quando um objeto é criado e retornado
  • 201 quando um objeto é criado, mas apenas sua referência é retornada (como um ID ou um link)
Stéphane Bruckert
fonte
Fonte para isso?
alma sudo
3
Isto é o que eu entendo de w3.org/Protocols/rfc2616/rfc2616-sec10.html e httpstatuses.com/201
Stéphane Bruckert
3
Depois de ler tools.ietf.org/html/rfc7231#section-6.3.1 , concordo com esse entendimento - suponho que estava perguntando mais sobre como você chegou a isso. Mas agora, no meu entendimento ... 200 = recurso criado e retornado | 201 = recurso criado e referência é retornada | 204 = recurso criado e nenhuma carga retornada
sudo soul
34

Confira HTTP: Definições de Método: POST .

A ação executada pelo método POST pode não resultar em um recurso que pode ser identificado por um URI. Nesse caso, 200 (OK) ou 204 (Sem conteúdo) é o status de resposta apropriado, dependendo de a resposta incluir ou não uma entidade que descreve o resultado.

Se um recurso foi criado no servidor de origem, a resposta DEVE ser 201 (criada) e conter uma entidade que descreva o status da solicitação e se refira ao novo recurso e um cabeçalho de localização (consulte a seção 14.30).

ma11hew28
fonte
18

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19

É apenas um valor-chave delimitado por dois pontos.

ETag: "xyzzy"

Pode ser qualquer tipo de dado de texto - geralmente incluo uma string JSON com o identificador do item criado. Só a facilidade de testar faz com que valha a pena incluir.

ETag: "{ id: 1234, uri: 'http://domain.com/comments/1234', type: 'comment' }"

Neste exemplo, o identificador, a URI e o tipo do item criado são as "características e localização do recurso".

tempire
fonte
3
Você está dizendo que um ETag corresponde a uma entidade que contém uma lista de características e localizações de recursos . Percebo que sua sugestão é boa, concordo muito com o seu ponto de vista sobre o teste. No entanto, não vejo como isso se encaixa com "uma lista de características e locais de recursos".
22412 djna
A "lista de características e locais de recursos" seria o conteúdo de qualquer estrutura de dados fornecida. Uma implementação mais estrita seria que a estrutura JSON incluísse a uri do recurso e talvez o tipo de recurso que foi criado. Vou ajustar a resposta como tal.
tempire
7
Especifique os problemas, para que as pessoas possam aprender. Caso contrário, o comentário é apenas um aceno manual.
tempire
@SimonGibbs What Issues?
MEMark
2
Embora seja estritamente correto de acordo com as especificações, recomenda uma opção de implementação altamente incomum. Além disso, na verdade, ele não responde à pergunta no topo da página (ou o faz misturando as palavras ETag e entidade). A resposta com 43 votos é provavelmente melhor.
Simon Gibbs
1

A saída é realmente dependente do tipo de conteúdo que está sendo solicitado. No entanto, no mínimo, você deve colocar o recurso criado em Local. Assim como o padrão Pós-Redirecionar-Obter.

No meu caso, deixo em branco até que seja solicitado o contrário. Como esse é o comportamento do JAX-RS ao usar o Response.created ().

No entanto, observe que navegadores e estruturas como o Angular não seguem os 201 automaticamente. Observei o comportamento em http://www.trajano.net/2013/05/201-created-with-angular-resource/

Archimedes Trajano
fonte
-2

Outra resposta que eu teria para isso seria adotar uma abordagem pragmática e manter seu contrato de API REST simples. No meu caso, refatorei minha API REST para tornar as coisas mais testáveis ​​sem recorrer a JavaScript ou XHR, apenas formulários e links HTML simples.

Para ser mais específico na sua pergunta acima, eu usaria o código de retorno 200e a mensagem retornada conteria uma mensagem JSON que seu aplicativo pode entender. Dependendo das suas necessidades, pode ser necessário o ID do objeto recém-criado, para que o aplicativo Web possa obter os dados em outra chamada.

Uma observação: no meu contrato de API refatorado, as respostas POST não devem conter dados armazenáveis ​​em cache, pois os POSTs não são realmente editáveis; portanto, limite-os aos IDs que podem ser solicitados e armazenados em cache usando uma solicitação GET.

Archimedes Trajano
fonte