PUT vs. POST em REST

5373

De acordo com a especificação HTTP / 1.1:

O POSTmétodo é usado para solicitar que o servidor de origem aceite a entidade incluída na solicitação como um novo subordinado do recurso identificado pelo Request-URInoRequest-Line

Em outras palavras, POSTé usado para criar .

O PUTmétodo solicita que a entidade fechada seja armazenada sob o fornecido Request-URI. Se o Request-URIrefere-se a um recurso já existente, a entidade fechada deve ser considerada como uma versão modificada do que reside no servidor de origem. Se Request-URInão apontar para um recurso existente e esse URI puder ser definido como um novo recurso pelo agente solicitante, o servidor de origem poderá criar o recurso com esse URI. "

Ou seja, PUTé usado para criar ou substituir .

Então, qual deles deve ser usado para criar um recurso? Ou é preciso apoiar os dois?

alex
fonte
56
Pode ser útil usar as definições em HTTPbis - Roy dedicando bastante trabalho para esclarecê-las. Veja: tools.ietf.org/html/…
Mark Nottingham
16
Apenas para trazer o comentário de @ MarkNottingham para a revisão mais recente, aqui estão POST e PUT , conforme definido em HTTPbis.
Marius Butuc
37
Parece-me que esse debate surgiu da prática comum de simplificar demais o REST, descrevendo os métodos HTTP em termos de operações CRUD.
Stuporman
5
Infelizmente, as primeiras respostas estão erradas sobre o POST. Verifique minha resposta para uma melhor explicação das diferenças: stackoverflow.com/a/18243587/2458234
7hi4g0
23
PUT e POST são métodos não seguros. No entanto, PUT é idempotente, enquanto POST não. - Veja mais em: restcookbook.com/HTTP%20Methods/put-vs-post/…
Dinesh Saini

Respostas:

4239

No geral:

PUT e POST podem ser usados ​​para criar.

Você precisa perguntar "para o que você está executando a ação?" para distinguir o que você deve usar. Vamos supor que você esteja criando uma API para fazer perguntas. Se você deseja usar o POST, faça isso com uma lista de perguntas. Se você quiser usar o PUT, faça isso com uma pergunta específica.

Podem ser usados ​​ótimos, portanto, qual deles devo usar no meu design RESTful:

Você não precisa oferecer suporte a PUT e POST.

O que é usado fica a seu critério. Mas lembre-se de usar o correto, dependendo do objeto que você está referenciando na solicitação.

Algumas considerações:

  • Você nomeia seus objetos de URL que você cria explicitamente ou deixa o servidor decidir? Se você os nomear, use PUT. Se você deixar o servidor decidir, use o POST.
  • PUT é idempotente; portanto, se você colocar um objeto duas vezes, ele não terá efeito. Esta é uma boa propriedade, então eu usaria PUT quando possível.
  • Você pode atualizar ou criar um recurso com PUT com o mesmo URL de objeto
  • Com o POST, você pode receber 2 solicitações ao mesmo tempo, fazendo modificações em uma URL, e elas podem atualizar diferentes partes do objeto.

Um exemplo:

Escrevi o seguinte como parte de outra resposta no SO sobre isso :

POSTAR:

Usado para modificar e atualizar um recurso

POST /questions/<existing_question> HTTP/1.1
Host: www.example.com/

Observe que o seguinte é um erro:

POST /questions/<new_question> HTTP/1.1
Host: www.example.com/

Se o URL ainda não estiver criado, você não deve usar o POST para criá-lo enquanto especifica o nome. Isso deve resultar em um erro 'recurso não encontrado', porque <new_question>ainda não existe. Você deve COLOCAR o <new_question> recurso no servidor primeiro.

Você pode fazer algo assim para criar recursos usando o POST:

POST /questions HTTP/1.1
Host: www.example.com/

Observe que, nesse caso, o nome do recurso não é especificado, o novo caminho da URL dos objetos será retornado a você.

COLOCAR:

Usado para criar um recurso ou substituí-lo. Enquanto você especifica os recursos, novo URL.

Para um novo recurso:

PUT /questions/<new_question> HTTP/1.1
Host: www.example.com/

Para substituir um recurso existente:

PUT /questions/<existing_question> HTTP/1.1
Host: www.example.com/

Além disso, e de forma um pouco mais concisa, a Seção 4.3.4 da RFC 7231 PUT afirma (grifo nosso),

4.3.4 COLOCAR

O método PUT solicita que o estado do recurso de destino seja createdou replacedcom o estado definido pela representação incluída na carga útil da mensagem de solicitação.

Brian R. Bondy
fonte
1026
Eu acho que não se pode enfatizar o suficiente o fato de que o PUT é idempotente: se a rede estiver danificada e o cliente não tiver certeza se sua solicitação foi atendida, basta enviar uma segunda (ou 100ª) vez, e isso é garantido pelo Especificação HTTP de que isso tem exatamente o mesmo efeito que o envio uma vez.
Jörg W Mittag
77
@ Jörg W Mittag: Não é necessário. A segunda vez pode retornar 409 Conflict ou algo assim, se a solicitação tiver sido modificada nesse meio tempo (por outro usuário ou pela primeira solicitação em si).
Mitar 27/11
632
Se não me engano, o que devemos enfatizar é que o PUT é definido como idempotente. Você ainda precisa escrever seu servidor de forma que o PUT se comporte corretamente, sim? Talvez seja melhor dizer "PUT faz com que o transporte assuma a idempotência, o que pode afetar o comportamento do transporte, por exemplo, armazenamento em cache".
Ian Ni-Lewis
150
@ JörgWMittag Idempotence slogan? Que tal "Enviar e enviar e enviar meu amigo, não faz diferença no final."
precisa saber é o seguinte
39
Pensa neles como: PUT = inserir ou atualizar; POST = inserção. Então, quando você faz dois PUT - você obtém um novo registro, quando você faz dois POSTs - você obtém dois novos registros.
Eugen Konkov
2218

Você pode encontrar afirmações na web que dizem

Nenhum dos dois está certo.


Melhor é escolher entre PUT e POST com base na idempotência da ação.

PUT implica colocar um recurso - substituindo completamente o que estiver disponível no URL fornecido por algo diferente. Por definição, um PUT é idempotente. Faça quantas vezes quiser e o resultado será o mesmo. x=5é idempotente. Você pode COLOCAR um recurso se ele existe anteriormente ou não (por exemplo, para Criar ou Atualizar)!

O POST atualiza um recurso, adiciona um recurso subsidiário ou causa uma alteração. Um POST não é idempotente, da maneira que x++não é idempotente.


Por esse argumento, PUT é para criar quando você souber o URL da coisa que criará. O POST pode ser usado para criar quando você souber o URL da "fábrica" ​​ou gerente da categoria de itens que deseja criar.

tão:

POST /expense-report

ou:

PUT  /expense-report/10929
Cheeso
fonte
72
Concordo que, no que diz respeito à idempotência, ela deve superar outras preocupações, já que errar pode causar muitos bugs inesperados.
Josh
16
Se o POST pode atualizar um recurso, como isso não é idempotente? Se eu mudar a idade dos alunos usando o PUT e fizer isso 10 vezes mais, a idade dos alunos será a mesma se eu fizesse uma vez.
Jack Ukleja
28
@ Schneider, nesse caso, o servidor está fazendo um esforço extra para garantir a idempotência, mas não está anunciando. Os navegadores ainda alertam o usuário se tentarem recarregar uma solicitação POST.
Tobu
47
O @Schneider POST pode criar um recurso subsidiário; portanto, você pode POST para coleta, como POST / relatórios de despesas, e criaria no seu servidor tantas entidades (relatórios de despesas) quanto a quantidade de solicitações enviadas, mesmo que sejam completamente semelhantes. Pense nisso como inserir a mesma linha na tabela do banco de dados (/ gasto-reports) com chave primária incrementada automaticamente. Os dados permanecem os mesmos, a chave (nesse caso, URI) é gerada pelo servidor e é diferente para todas as outras inserções (solicitação). Portanto, o efeito POST pode ser idempotente, mas também não pode . Portanto, o POST não é idempotente.
Snifff
11
Digamos que temos entidades que podem ter duas propriedades - namee date. Se tivermos uma entidade com uma existente namee date, mas fizermos solicitações especificando apenas a name, o comportamento adequado de PUT seria obliterar o dateda entidade, enquanto o POST pode atualizar apenas as propriedades especificadas, deixando as propriedades não especificadas como estavam. antes da solicitação ser feita. Isso parece correto / razoável ou é um uso inadequado do PUT (vi referências ao PATCH , que parece ser mais apropriado, mas ainda não existe)?
Jon z
707
  • POST para uma URL cria um recurso filho em uma URL definida pelo servidor .
  • COLOCAR em uma URL cria / substitui o recurso por inteiro na URL definida pelo cliente .
  • PATCH para um URL atualiza parte do recurso naquele URL definido pelo cliente.

A especificação relevante para PUT e POST é RFC 2616 §9.5ff.

O POST cria um recurso filho ; portanto, o POST /itemscria recursos que residem no /itemsrecurso. Por exemplo. /items/1. Enviar o mesmo pacote de postagem duas vezes criará dois recursos.

PUT é para criar ou substituir um recurso em uma URL conhecida pelo cliente .

Portanto: PUT é apenas um candidato para CREATE onde o cliente já conhece o URL antes que o recurso seja criado. Por exemplo. /blogs/nigel/entry/when_to_use_post_vs_putcomo o título é usado como a chave do recurso

PUT substitui o recurso no URL conhecido, se ele já existir, portanto, enviar a mesma solicitação duas vezes não terá efeito. Em outras palavras, as chamadas para PUT são idempotentes .

O RFC é assim:

A diferença fundamental entre as solicitações POST e PUT é refletida no significado diferente do Request-URI. O URI em uma solicitação POST identifica o recurso que manipulará a entidade fechada. Esse recurso pode ser um processo de aceitação de dados, um gateway para outro protocolo ou uma entidade separada que aceita anotações. Por outro lado, o URI em uma solicitação PUT identifica a entidade anexada à solicitação - o agente do usuário sabe qual URI se destina e o servidor NÃO DEVE tentar aplicar a solicitação a algum outro recurso. Se o servidor desejar que a solicitação seja aplicada a um URI diferente,

Nota: PUT tem sido usado principalmente para atualizar recursos (substituindo-os por inteiro), mas recentemente há um movimento no sentido de usar PATCH para atualizar recursos existentes, pois PUT especifica que ele substitui todo o recurso. RFC 5789.

Atualização 2018 : Existe um caso que pode ser feito para evitar o PUT. Consulte "REST sem PUT"

Com a técnica "REST sem PUT", a idéia é que os consumidores sejam forçados a postar novos recursos de solicitação 'substantivo'. Conforme discutido anteriormente, alterar o endereço de correspondência de um cliente é um POST para um novo recurso "ChangeOfAddress", não uma PUT de um recurso de "Cliente" com um valor de campo de endereço de correspondência diferente.

extraído do REST API Design - Modelagem de Recursos por Prakash Subramaniam do Thoughtworks

Isso força a API a evitar problemas de transição de estado com vários clientes que atualizam um único recurso e corresponde melhor à fonte de eventos e ao CQRS. Quando o trabalho é concluído de forma assíncrona, POST a transformação e aguardando sua aplicação parece apropriada.

Nigel Thorne
fonte
53
Ou do outro lado da barreira: PUT se o cliente determinar o endereço do recurso resultante, POST se o servidor o fizer.
22412 DanMan
3
Penso que esta resposta deve ser editada para tornar mais claro o que o @DanMan apontou de uma maneira muito simples. O que acho mais valioso aqui é a nota no final, afirmando que um PUT deve ser usado apenas para substituir todo o recurso.
Hermes
3
PATCH não é uma opção realista por pelo menos alguns anos, mas eu concordo com a ideologia.
esmagar
4
Estou tentando entender, mas usar PUT para criar algo só faria sentido se o cliente souber com certeza que o recurso ainda não existe, certo? Seguindo o exemplo do blog, digamos que você tenha criado centenas de postagens em alguns anos e, acidentalmente, escolha o mesmo título que criou para uma postagem há dois anos. Agora você substituiu a publicação, que não era intencional. Portanto, usar PUT para criar exigiria que o cliente rastreias o que é pego e o que não é, e pode levar a acidentes e efeitos colaterais indesejados, além de ter rotas que fazem duas coisas totalmente diferentes?
usar o seguinte código
5
Você está certo. Colocar uma postagem de blog no mesmo URL que uma existente causaria uma atualização nessa postagem existente (embora você possa obviamente verificar primeiro com um GET). Isso indica por que seria uma má idéia usar apenas o título como URL. No entanto, funcionaria em qualquer lugar onde houvesse uma chave natural nos dados ... o que, na minha experiência, é raro. Ou se você usou GUIDs
Nigel Thorne
221

Resumo:

Crio:

Pode ser realizado com PUT ou POST da seguinte maneira:

COLOCAR

Cria O novo recurso com newResourceId como o identificador, sob os recursos / URI, ou coleta .

PUT /resources/<newResourceId> HTTP/1.1 

POSTAR

Cria um novo recurso no URI / resources ou coleção . Normalmente, o identificador é retornado pelo servidor.

POST /resources HTTP/1.1

Atualizar:

pode ser executado com PUT da seguinte maneira:

COLOCAR

Atualiza o recurso com o existenteResourceId como o identificador, no / resources URI, ou coleção .

PUT /resources/<existingResourceId> HTTP/1.1

Explicação:

Ao lidar com REST e URI como geral, você tem genérico à esquerda e específico à direita . Os genéricos geralmente são chamados de coleções e os itens mais específicos podem ser chamados de recurso . Observe que um recurso pode conter uma coleção .

Exemplos:

<- genérico - específico ->

URI: website.com/users/john
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource

URI:website.com/users/john/posts/23
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource
posts        - collection of posts from john
23           - post from john with identifier 23, also a resource

Quando você usa o POST, está sempre se referindo a uma coleção ; portanto, sempre que você diz:

POST /users HTTP/1.1

você está postando um novo usuário na coleção de usuários .

Se você continuar e tentar algo como isto:

POST /users/john HTTP/1.1

ele vai trabalhar, mas semanticamente você está dizendo que você deseja adicionar um recurso para o john coleção sob a usuários coleção .

Depois de usar o PUT, você está se referindo a um recurso ou item único, possivelmente dentro de uma coleção . Então, quando você diz:

PUT /users/john HTTP/1.1

você está informando à atualização do servidor ou cria, se não existir, o recurso john na coleção de usuários .

Especificação:

Deixe-me destacar algumas partes importantes das especificações:

POSTAR

O método POST é usado para solicitar que o servidor de origem aceite a entidade incluída na solicitação como um novo subordinado do recurso identificado pelo Request-URI na linha de solicitação

Portanto, cria um novo recurso em uma coleção .

COLOCAR

O método PUT solicita que a entidade fechada seja armazenada no URI de solicitação fornecido. Se o pedido de URI refere-se a um recurso já existente , a entidade fechada deve ser considerada como uma versão modificada do que reside no servidor de origem. Se o Request-URI não apontar para um recurso existente e esse URI puder ser definido como um novo recurso pelo agente solicitante, o servidor de origem poderá criar o recurso com esse URI. "

Portanto, crie ou atualize com base na existência do recurso .

Referência:

7hi4g0
fonte
11
Esta postagem me ajudou a entender que o POST adiciona "algo" quando criança à coleção fornecida (URI), enquanto o PUT define explicitamente o "algo" no local especificado do URI.
Kwah
3
Esta é a melhor resposta, aqui, eu acho: nada disso absurdo "POST pode atualizar um recurso". Gostei da sua afirmação: "A atualização só pode ser realizada com PUT".
Thomas
4
Não, PUT não é para atualização ou criação. É para substituir. Observe que você não pode substituir nada por algo para o efeito de criar.
Thecoshman
2
@ 7hi4g0 PUT é para atualização com uma substituição completa, ou seja, substitui. Você não substitui nada por algo, ou algo por algo completamente novo. PUT não é para fazer uma pequena alteração (a menos que o cliente faça essa pequena alteração e forneça a nova versão inteira, mesmo que permaneça a mesma). Para modificação parcial, PATCH é o método de escolha.
Thecoshman
1
@thecoshman Você poderia, mas não seria muito claro que a criação também é abordada lá. Nesse caso, é melhor ser explícito.
7hi4g0
175

POST significa "criar novo", como em "Aqui está a entrada para criar um usuário, crie para mim".

PUT significa "inserir, substituir se já existir", como em "Aqui estão os dados para o usuário 5".

Você POSTpode acessar example.com/users, como ainda não conhece URLo usuário, deseja que o servidor o crie.

Você PUTpode example.com/users/id desde que deseja substituir / criar um usuário específico .

POSTAR duas vezes com os mesmos dados significa criar dois usuários idênticos com IDs diferentes. Colocar duas vezes com os mesmos dados cria o usuário primeiro e atualiza-o para o mesmo estado na segunda vez (sem alterações). Como você termina com o mesmo estado depois de PUTnão importa quantas vezes você o executa, diz-se que é "igualmente potente" todas as vezes - idempotente. Isso é útil para tentar novamente solicitações automaticamente. Chega de 'você tem certeza de que deseja reenviar' ao pressionar o botão Voltar no navegador.

Um conselho geral é usar POSTquando você precisar que o servidor esteja no controle da URLgeração de seus recursos. Use de PUToutra forma. Prefere PUT mais POST.

Alexander Torstling
fonte
12
A negligência pode fazer com que seja comum ensinar que existem apenas dois verbos que você precisa: GET e POST. GET para obter, POST para alterar. Até PUT e DELETE foram realizados usando POST. Perguntar o que PUT realmente significa 25 anos depois, talvez seja um sinal de que aprendemos errado de início. A popularidade do REST levou as pessoas de volta ao básico, onde agora devemos desaprender os erros do passado. O POST foi usado em excesso e agora normalmente é ensinado incorretamente. Melhor parte: "POSTAR duas vezes com os mesmos dados significa criar dois [recursos] idênticos". Ótimo ponto!
Maxpolk 01/09
1
Como você pode usar PUT para criar um registro pelo ID, como no seu exemplo, user 5se ele ainda não existir? Você não quer dizer update, replace if already exists? ou algo assim
Lucas
@Coulton: eu quis dizer o que escrevi. Você insere o usuário 5 se COLOCAR em / users / 5 e # 5 ainda não existir.
Alexander Torstling
@Coulton: E PUTtambém pode ser usado para substituir o valor de um recurso existente na sua totalidade.
DavidRR
1
"Prefere PUT sobre POST" ... gostaria de justificar isso?
Thecoshman
173

Eu gostaria de adicionar meu conselho "pragmático". Use PUT quando souber o "id" pelo qual o objeto que você está salvando pode ser recuperado. O uso de PUT não funcionará muito bem se você precisar, digamos, de um ID gerado pelo banco de dados a ser retornado para que você faça pesquisas ou atualizações futuras.

Portanto: para salvar um usuário existente ou aquele em que o cliente gera o ID e foi verificado que o ID é exclusivo:

PUT /user/12345 HTTP/1.1  <-- create the user providing the id 12345
Host: mydomain.com

GET /user/12345 HTTP/1.1  <-- return that user
Host: mydomain.com

Caso contrário, use POST para criar inicialmente o objeto e PUT para atualizar o objeto:

POST /user HTTP/1.1   <--- create the user, server returns 12345
Host: mydomain.com

PUT /user/12345 HTTP/1.1  <--- update the user
Host: mydomain.com
ThaDon
fonte
17
Na verdade, deveria ser POST /users. (Observe o /usersplural.) Isso tem o efeito de criar um novo usuário e torná-lo um recurso filho da /userscoleção.
DavidRR
6
@DavidRR para ser justo, como lidar com grupos é outro debate. GET /usersfaz sentido, ele lê como você deseja, mas eu ficaria bem com GET /user/<id>ou POST /user(com carga útil para o novo usuário), porque ele lê corretamente 'me chame de usuário 5' é estranho, mas 'me chame de usuário 5' é mais natural. Eu provavelmente ainda cair no lado da pluralização embora :)
thecoshman
126

Use POST para criar e PUT para atualizar. É assim que Ruby on Rails está fazendo isso, de qualquer maneira.

PUT    /items/1      #=> update
POST   /items        #=> create
Tim Sullivan
fonte
4
POST /itemsadiciona um novo item a um recurso já definido ('item'). Como a resposta diz, não cria "um grupo". Eu não entendo por que isso tem 12 votos.
David J.
Fora da caixa, o Rails não suporta 'criar um grupo' via REST. Para 'criar um grupo' com o qual quero dizer 'criar um recurso', você deve fazê-lo através do código fonte.
David J.
8
Esta é uma orientação justa, mas uma simplificação excessiva. Como as outras respostas mencionam, qualquer um dos métodos pode ser usado para criar e atualizar.
Brad Koch
2
Eu concordo com a resposta com uma pequena modificação. Use POST para criar e PUT para atualizar completamente o recurso. Para atualizações parciais, podemos usar PUT ou PATCH. Digamos que queremos atualizar o status de um grupo. Podemos usar PUT / grupos / 1 / status com o estado é a carga útil do pedido ou PATCH / grupos / 1 com os detalhes sobre a ação na carga útil
java_geek
2
Também deve ficar claro que PUT /items/42também é válido para a criação de um recurso, mas apenas se o cliente tiver o privilégio de nomear o recurso . (O Rails permitir que um cliente este privilégio de nomenclatura?)
DavidRR
123

Ambos são usados ​​para transmissão de dados entre cliente e servidor, mas há diferenças sutis entre eles, que são:

Digite a descrição da imagem aqui

Analogia:

  • PUT, ou seja, pegue e coloque onde estava.
  • POST como correio enviar no pós escritório.

insira a descrição da imagem aqui

Mídia Social / Analogia de Rede:

  • Postar nas mídias sociais: quando postamos uma mensagem, ela cria uma nova postagem.
  • Coloque (ou seja, edite) a mensagem que já publicamos.
Premraj
fonte
21
@MobileMon Não, os métodos REST não são CRUD.
JLR
1
Eu diria PUT para UPSERTS
Hola Soy Edu Feliz Navidad
@ MobileMon não: POST quando você cria um novo recurso e não conhece o ponto final final para obtê-lo. PUT para outros casos.
Portekoi
67

REST é um muito conceito de alto nível. De fato, nem sequer menciona HTTP!

Se você tiver alguma dúvida sobre como implementar o REST no HTTP, sempre poderá dar uma olhada na especificação do Atom Publication Protocol (AtomPub) . O AtomPub é um padrão para a criação de serviços da Web RESTful com HTTP, desenvolvido por muitos especialistas em HTTP e REST, com algumas informações de Roy Fielding, o inventor do REST e (co) inventor do próprio HTTP.

De fato, você pode até usar o AtomPub diretamente. Embora tenha saído da comunidade de blogs, não é de forma alguma restrito aos blogs: é um protocolo genérico para interagir RESTfully com coleções arbitrárias (aninhadas) de recursos arbitrários via HTTP. Se você puder representar seu aplicativo como uma coleção aninhada de recursos, poderá usar o AtomPub e não se preocupar em usar PUT ou POST, quais códigos de status HTTP retornar e todos esses detalhes.

Isto é o que AtomPub tem a dizer sobre criação de recursos (seção 9.2):

Para adicionar membros a uma coleção, os clientes enviam solicitações POST ao URI da coleção.

Jörg W Mittag
fonte
8
Não há nada errado em permitir que o PUT crie recursos. Esteja ciente de que isso significa que o cliente fornece a URL.
Julian Reschke
5
Há algo muito errado em permitir que o PUT crie recursos: o cliente fornece a URL. Esse é o trabalho do servidor!
Joshcodes
@ Joshcodes Nem sempre é o trabalho do servidor criar IDs de clientes. Eu tenho visto cada vez mais designs que permitem que os clientes gerem algum tipo de UUID como o ID do recurso. Esse design se presta especialmente para aumentar a escala.
Justin Ohms
@JustinOhms Concordo com o seu ponto de vista sobre os IDs gerados pelo cliente (observação: todos os sistemas criados por mim desde cerca de 2008 exigem que o cliente crie o ID como um UUID / Guid). Isso não significa que o cliente deve especificar o URL.
Joshcodes
1
Sim, se o recurso já existir, use PUT. No entanto, em quase todos os casos, os recursos devem ser criados com o POST e o cliente não deve fornecer a URL. Roy Fielding concorda com esta FWIW declaração: roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
Joshcodes
61

A decisão de usar PUT ou POST para criar um recurso em um servidor com uma API HTTP + REST é baseada em quem possui a estrutura de URL. Tendo o cliente conhecido ou participando da definição, a estrutura da URL é um acoplamento desnecessário semelhante aos acoplamentos indesejáveis ​​que surgiram da SOA. Escapar de tipos de acoplamentos é o motivo pelo qual o REST é tão popular. Portanto, o método adequado a ser usado é o POST. Há exceções a essa regra e elas ocorrem quando o cliente deseja manter o controle sobre a estrutura de localização dos recursos que implanta. Isso é raro e provavelmente significa que algo mais está errado.

Neste ponto, algumas pessoas argumentam que, se URLs RESTful são usadas, o cliente conhece a URL do recurso e, portanto, uma PUT é aceitável. Afinal, é por isso que os URLs canônicos, normalizados, do Ruby on Rails e do Django são importantes, veja a API do Twitter ... blá blá blá. Essas pessoas precisam entender que não existe um URL repousante e que o próprio Roy Fielding afirma que :

Uma API REST não deve definir nomes ou hierarquias de recursos fixos (um acoplamento óbvio de cliente e servidor). Os servidores devem ter liberdade para controlar seu próprio espaço para nome. Em vez disso, permita que os servidores instruam os clientes sobre como criar URIs apropriados, como é feito em formulários HTML e modelos de URI, definindo essas instruções nos tipos de mídia e nas relações de vínculo. [Falha aqui implica que os clientes estão assumindo uma estrutura de recursos devido a informações fora da banda, como um padrão específico de domínio, que é o equivalente orientado a dados ao acoplamento funcional da RPC].

http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

A idéia de um URL RESTful é na verdade uma violação do REST, pois o servidor é responsável pela estrutura da URL e deve estar livre para decidir como usá-lo para evitar o acoplamento. Se isso confunde você lê sobre o significado da autodescoberta no design da API.

O uso do POST para criar recursos vem com uma consideração de design, porque o POST não é idempotente. Isso significa que repetir um POST várias vezes não garante o mesmo comportamento todas as vezes. Isso assusta as pessoas a usar o PUT para criar recursos quando não deveriam. Eles sabem que está errado (POST é para CREATE), mas o fazem de qualquer maneira porque não sabem como resolver esse problema. Essa preocupação é demonstrada na seguinte situação:

  1. O cliente POST um novo recurso para o servidor.
  2. O servidor processa a solicitação e envia uma resposta.
  3. O cliente nunca recebe a resposta.
  4. O servidor não sabe que o cliente não recebeu a resposta.
  5. O cliente não possui uma URL para o recurso (portanto, PUT não é uma opção) e repete o POST.
  6. O POST não é idempotente e o servidor…

O passo 6 é onde as pessoas geralmente ficam confusas sobre o que fazer. No entanto, não há razão para criar um kludge para resolver esse problema. Em vez disso, o HTTP pode ser usado conforme especificado na RFC 2616 e o servidor responde:

10.4.10 409 Conflito

A solicitação não pôde ser concluída devido a um conflito com o estado atual do recurso. Esse código é permitido apenas em situações em que se espera que o usuário possa resolver o conflito e reenviar a solicitação. O corpo da resposta DEVE incluir o suficiente

informações para o usuário reconhecer a origem do conflito. Idealmente, a entidade de resposta incluiria informações suficientes para que o usuário ou agente do usuário corrija o problema; no entanto, isso pode não ser possível e não é necessário.

É provável que os conflitos ocorram em resposta a uma solicitação PUT. Por exemplo, se o controle de versão estava sendo usado e a entidade que estava sendo PUT incluía alterações em um recurso que entra em conflito com aquelas feitas por uma solicitação anterior (de terceiros), o servidor pode usar a resposta 409 para indicar que não pode concluir a solicitação . Nesse caso, a entidade de resposta provavelmente conteria uma lista das diferenças entre as duas versões em um formato definido pela resposta Content-Type.

Responder com um código de status 409 Conflict é o recurso correto porque :

  • Executar um POST de dados com um ID que corresponda a um recurso já existente no sistema é "um conflito com o estado atual do recurso".
  • Como a parte importante é que o cliente entenda que o servidor possui o recurso e tome as medidas apropriadas. Essa é uma "situação (s) em que se espera que o usuário consiga resolver o conflito e reenviar a solicitação".
  • Uma resposta que contenha a URL do recurso com o ID conflitante e as pré-condições apropriadas para o recurso forneceria "informações suficientes para que o usuário ou o agente do usuário corrija o problema", que é o caso ideal para a RFC 2616.

Atualização baseada no lançamento do RFC 7231 para substituir 2616

O RFC 7231 foi projetado para substituir 2616 e na Seção 4.3.3 descreve a seguinte resposta possível para um POST

Se o resultado do processamento de um POST seria equivalente a uma representação de um recurso existente, um servidor de origem PODE redirecionar o agente do usuário para esse recurso enviando uma resposta 303 (Consulte Outros) com o identificador do recurso existente no campo Localização. Isso tem os benefícios de fornecer ao agente do usuário um identificador de recurso e transferir a representação por meio de um método mais passível de armazenamento em cache compartilhado, embora ao custo de uma solicitação extra se o agente do usuário ainda não tiver a representação em cache.

Agora pode ser tentador simplesmente retornar um 303 no caso de um POST ser repetido. No entanto, o oposto é verdadeiro. Retornar um 303 só faria sentido se várias solicitações de criação (criando recursos diferentes) retornassem o mesmo conteúdo. Um exemplo seria um "obrigado por enviar sua mensagem de solicitação" que o cliente não precisa baixar novamente a cada vez. A RFC 7231 ainda mantém na seção 4.2.2 que o POST não deve ser idempotente e continua mantendo que o POST deve ser usado para criação.

Para mais informações sobre isso, leia este artigo .

Joshcodes
fonte
Uma resposta 409 Conflict seria o código apropriado para algo como tentar criar uma nova conta com um nome de usuário que já exista? Eu tenho usado o 409 para conflitos de versão especificamente, mas depois de ler sua resposta, pergunto-me se ela não deve ser usada para solicitações "duplicadas".
Eric B.
@EricB. Sim, na situação que você descreve "devido a um conflito com o estado atual do recurso", a operação falha. Além disso, é razoável esperar que o usuário possa resolver o conflito e o corpo da mensagem apenas precise informar ao usuário que o nome de usuário já existe.
Joshcodes
@ Joshcodes, você pode falar mais sobre o processo de resolução de conflitos? Nesse caso, se o nome de usuário já existir, o cliente deverá solicitar ao usuário final um nome de usuário diferente? E se o cliente estiver realmente tentando usar o POST para alterar o nome de usuário? As solicitações PUT ainda devem ser usadas para atualizar parâmetros, enquanto o POST é usado para criar objetos, seja um de cada vez ou vários? Obrigado.
BFAR
@ BFar2 se o nome de usuário já existir, o cliente deverá solicitar ao usuário. Para alterar o nome de usuário, assumindo que o nome de usuário faça parte de um recurso já criado que precise ser modificado, PUT seria usado porque você está correto, POST é usado para criar, sempre e PUT para atualizações.
precisa saber é
explicar as coisas usando linguagem curta e eficaz é também uma habilidade desejável
Junchen Liu
53

Eu gosto deste conselho, da definição de PUT da RFC 2616 :

A diferença fundamental entre as solicitações POST e PUT é refletida no significado diferente do Request-URI. O URI em uma solicitação POST identifica o recurso que manipulará a entidade fechada. Esse recurso pode ser um processo de aceitação de dados, um gateway para outro protocolo ou uma entidade separada que aceita anotações. Por outro lado, o URI em uma solicitação PUT identifica a entidade incluída na solicitação - o agente do usuário sabe qual URI se destina e o servidor NÃO DEVE tentar aplicar a solicitação a algum outro recurso.

Isso combina com os outros conselhos aqui, que PUT é melhor aplicado a recursos que já têm um nome e POST é bom para criar um novo objeto em um recurso existente (e deixar que o servidor o nomeie).

Eu interpreto isso e os requisitos de idempotência no PUT, para dizer que:

  • POST é bom para criar novos objetos em uma coleção (e create não precisa ser idempotente)
  • PUT é bom para atualizar objetos existentes (e a atualização precisa ser idempotente)
  • O POST também pode ser usado para atualizações não idempotentes de objetos existentes (especialmente, alterar parte de um objeto sem especificar a coisa toda - se você pensar sobre isso, criar um novo membro de uma coleção é realmente um caso especial desse tipo de atualização, da perspectiva da coleção)
  • PUT também pode ser usado para criar se e somente se você permitir que o cliente nomeie o recurso. Mas como os clientes REST não devem fazer suposições sobre a estrutura da URL, isso é menos no espírito das coisas.
metamatt
fonte
3
"POST também pode ser usado para atualizações não-idempotentes para objetos existentes (especialmente, mudando parte de um objeto sem especificar a coisa toda" Isso é o que PATCH é para
Snuggs
48

Em resumo:

PUT é idempotente, onde o estado do recurso será o mesmo se a mesma operação for executada uma vez ou várias vezes.

POST não é idempotente, onde o estado do recurso pode se tornar diferente se a operação for executada várias vezes em comparação com a execução de uma única vez.

Analogia com consulta ao banco de dados

PUT Você pode pensar em algo semelhante a "UPDATE STUDENT SET address =" abc "onde id =" 123 ";

POST Você pode pensar em algo como "INSERIR NO ALUNO (nome, endereço) VALORES (" abc "," xyzzz ");

O ID do aluno é gerado automaticamente.

Com PUT, se a mesma consulta for executada várias vezes ou uma vez, o estado da tabela STUDENT permanecerá o mesmo.

No caso do POST, se a mesma consulta for executada várias vezes, vários registros de Alunos serão criados no banco de dados e o estado do banco de dados será alterado a cada execução de uma consulta "INSERT".

NOTA: O PUT precisa de um local de recurso (já recurso) no qual a atualização precisa ocorrer, enquanto o POST não exige isso. Portanto, intuitivamente, o POST é destinado à criação de um novo recurso, enquanto o PUT é necessário para atualizar o recurso já existente.

Alguns podem sugerir que as atualizações possam ser realizadas com o POST. Não existe uma regra rígida qual usar para atualizações ou qual criar para criar. Novamente, essas são convenções e, intuitivamente, estou inclinado ao raciocínio acima mencionado e o sigo.

bharatj
fonte
6
para PUT é semelhante ao INSERT ou UPDATE consulta
Eugen Konkov
1
realmente PUT Você pode pensar em algo semelhante a "UPDATE STUDENT SET address =" abc ", onde id =" 123 "; seria uma instrução para PATCH." UPDATE STUDENT SET address = "abc", nome = "newname", onde id = " 123" seria uma analogia correta para PUT
MKO
Put também pode ser usado para INSERT. Por exemplo, se o seu servidor detectou que estava tentando fazer upload do mesmo arquivo várias vezes, a solicitação seria idempotente. (Nenhum novo upload de arquivo é feito).
precisa saber é o seguinte
43

O POST é como postar uma carta em uma caixa de correio ou postar um email em uma fila de emails. PUT é como quando você coloca um objeto em um cubículo ou em um local em uma prateleira (ele tem um endereço conhecido).

Com o POST, você está postando no endereço da QUEUE ou COLLECTION. Com PUT, você está colocando no endereço do ITEM.

PUT é idempotente. Você pode enviar a solicitação 100 vezes e isso não importa. O POST não é idempotente. Se você enviar a solicitação 100 vezes, receberá 100 e-mails ou 100 cartas na sua caixa postal.

Uma regra geral: se você souber o ID ou nome do item, use PUT. Se você deseja que o ID ou nome do item seja atribuído pela parte receptora, use POST.

POST versus PUT

Homer6
fonte
1
Não, PUT implica que você conhece o URL. Se você conhece apenas o ID, faça o POST com esse ID para obter o URL.
21713 Joshcodes
6
O ID faz parte do URL; portanto, use PUT se você souber o URL (que inclui o ID).
Homer6
Não, o URL é determinado pelo servidor e o ID não é necessariamente parte do URL. Roy Fielding diria o mesmo ou você poderia apenas ler sua tese .
Joshcodes
@ Joshcodes, isso está assumindo o REST? Em uma arquitetura RESTful, o ID do item definitivamente faz parte da URL, como em: / people / 123. Eu gosto deste site para REST: microformats.org/wiki/rest/urls
Beez
1
@Beez o link mircoformats sugere uma boa maneira para os servidores estruturarem seus URLs, mas o servidor determina o URL. O cliente quase nunca. Veja minha resposta ou artigo associado, se você não entender isso.
Joshcodes
39

Nova resposta (agora que eu entendo melhor o REST):

PUT é apenas uma declaração de qual conteúdo o serviço deve, a partir de agora, usar para renderizar representações do recurso identificado pelo cliente; O POST é uma declaração de qual conteúdo o serviço deve, a partir de agora, conter (possivelmente duplicado), mas cabe ao servidor como identificar esse conteúdo.

PUT x(se xidentifica um recurso ): "Substitua o conteúdo do recurso identificado por xpelo meu conteúdo".

PUT x(se xnão identificar um recurso): "Crie um novo recurso contendo meu conteúdo e usex para identificá-lo."

POST x: "Armazene meu conteúdo e me forneça um identificador que eu possa usar para identificar um recurso (antigo ou novo) que contém esse conteúdo (possivelmente misturado com outro conteúdo). O referido recurso deve ser idêntico ou subordinado ao que é xidentificado". " o recurso de y é subordinado ao recurso de x " é tipicamente, mas não necessariamente implementado, tornando y um subcaminho de x (por exemplo, x = /fooe y = /foo/bar) e modificando a (s) representação (ões) do de x recurso para refletir a existência de um novo recurso, por exemplo, com um hiperlink para yrecurso e alguns metadados. Somente o último é realmente essencial para um bom design, pois os URLs são opacos no REST - você deve usar a hipermídia em em vez da construção de URL do lado do cliente para atravessar o serviço de qualquer maneira.

No REST, não existe um recurso que contenha "conteúdo". Refiro-me como "conteúdo" aos dados que o serviço usa para renderizar representações de forma consistente. Geralmente consiste em algumas linhas relacionadas em um banco de dados ou arquivo (por exemplo, um arquivo de imagem). Cabe ao serviço converter o conteúdo do usuário em algo que o serviço possa usar, por exemplo, converter uma carga JSON em instruções SQL.

Resposta original (pode ser mais fácil de ler) :

PUT /something(se /somethingjá existir): "Pegue o que tiver em/something e substitua pelo que eu lhe der."

PUT /something(se /somethingainda não existir): "Pegue o que eu lhe dou e coloque-o no /something".

POST /something: "Pegue o que eu lhe der e coloque-o em qualquer lugar que desejar /something, desde que você me dê o URL quando terminar."

Jordânia
fonte
Mas como você pode usar o PUT para criar um novo recurso, se ele não existir, enquanto o seu método de geração de ID estiver no Incremento automático? Normalmente, os ORMs geram automaticamente o ID para você, da maneira que você deseja que seja em um POST, por exemplo. Isso significa que, se você deseja implementar o PUT da maneira certa, precisa alterar sua geração automática de ID? Isso é estranho se a resposta for sim.
Roni Axelrad 16/09
1
@RoniAxelrad: PUT é como uma instrução "INSERIR OU ATUALIZAR" do banco de dados, onde você está incluindo a chave na instrução, aplicável apenas onde você não pode garantir colisões. por exemplo. seu domínio tem uma 'chave natural' ou você usa um guia. O POST é como inserir em uma tabela com uma chave de incremento automático. Você deve ser informado pelo banco de dados que ID obteve após ter sido inserido. Observe que "INSERIR OU ATUALIZAR" substituirá os dados anteriores, se existirem.
Nigel Thorne
@NigelThorne Obrigado pela sua resposta. Portanto, se, por exemplo, estou tentando colocar um ID de livro 10 com um URI: PUT books / 10. Se o código do livro 10 não existir, eu devo criar um livro com o código 10, certo? mas não consigo controlar o numerador do ID da criação, porque é incremento automático. o que devo fazer nessa situação?
Roni Axelrad 27/11
1
@RoniAxelrad REST PUT para um ID que não existe é uma solicitação ao servidor para criar um recurso. Ainda depende do servidor decidir se deseja permitir isso. O servidor está no comando. Pode responder com "Não. Não vou fazer isso". Você já faz isso se o usuário não tiver permissões suficientes ... etc. Não há problema em o servidor dizer "Não". REST é uma convenção que nos permite definir o significado de vários tipos de solicitação ... seu servidor decide o que fazer com essas solicitações com base na lógica de negócios :) Mesmo que diga "não", ainda está seguindo REST :)
Nigel Thorne
38

Resposta curta:

Regra simples: use o POST para criar, use PUT para atualizar.

Resposta longa:

POSTAR:

  • POST é usado para enviar dados ao servidor.
  • Útil quando o URL do recurso é desconhecido

COLOCAR:

  • PUT é usado para transferir o estado para o servidor
  • Útil quando o URL de um recurso é conhecido

Resposta mais longa:

Para entendê-lo, precisamos questionar por que o PUT foi necessário, quais foram os problemas que o PUT estava tentando resolver que o POST não conseguiu.

Do ponto de vista da arquitetura REST, não há nada que importe. Poderíamos ter vivido sem o PUT também. Mas, do ponto de vista de um desenvolvedor de cliente, ele tornou sua vida muito mais simples.

Antes da PUT, os clientes não podiam saber diretamente a URL que o servidor gerou ou se tudo isso gerou alguma ou se os dados a serem enviados ao servidor já estão atualizados ou não. O PUT aliviou o desenvolvedor de todas essas dores de cabeça. PUT é idempotente, PUT lida com as condições da corrida e PUT permite que o cliente escolha o URL.

ishandutta2007
fonte
3
Sua resposta curta pode estar MUITO errada. HTTP PUT é livre para ser repetido por proxies HTTP. E assim, se PUT está realmente fazendo SQL INSERT pode falhar segunda vez, o que significa que voltaria resultado diferente e por isso não seria idempotente (que é a diferença entre PUT e POST)
Kamil Tomšík
36

O Ruby on Rails 4.0 usará o método 'PATCH' em vez de PUT para fazer atualizações parciais.

A RFC 5789 diz sobre PATCH (desde 1995):

É necessário um novo método para melhorar a interoperabilidade e evitar erros. O método PUT já está definido para substituir um recurso por um novo corpo completo e não pode ser reutilizado para fazer alterações parciais. Caso contrário, proxies e caches, e até mesmo clientes e servidores, poderão ficar confusos quanto ao resultado da operação. O POST já está sendo usado, mas sem ampla interoperabilidade (por exemplo, não há uma maneira padrão de descobrir o suporte ao formato de patch). PATCH foi mencionado nas especificações HTTP anteriores, mas não completamente definido.

" Edge Rails: PATCH é o novo método HTTP primário para atualizações ", explica.

germanlinux
fonte
27

Correndo o risco de reafirmar o que já foi dito, parece importante lembrar que PUT implica que o cliente controla o que a URL acabará sendo ao criar um recurso. Portanto, parte da escolha entre PUT e POST será sobre o quanto você pode confiar no cliente para fornecer URL normalizada e correta, coerente com o esquema de URL.

Quando você não pode confiar totalmente no cliente para fazer a coisa certa, seria mais apropriado usar o POST para criar um novo item e, em seguida, enviar a URL de volta ao cliente na resposta.

ladrão de frigideira
fonte
2
Estou um pouco atrasado para isso - mas alguém dizendo algo semelhante em outro site conseguiu clicar para mim. Se você estiver criando um recurso e usando um ID incrementado automaticamente como "identificador" em vez de um nome atribuído pelo usuário, ele deve ser um POST.
Ixmatus
2
Isso não está certo - PUT ainda pode criar um recurso, referindo-se a ele com um nome não-canônico, enquanto na resposta, o servidor retorna um Locationcabeçalho que não contêm o nome do recurso canônico.
Éter
1
@ Joshcodes não se esqueça que você pode ter muitos URIs referenciando o mesmo recurso subjacente. Portanto, o que o Ether disse é um bom conselho, o cliente pode COLOCAR em uma URL (que pode ser mais semântica, como PUT /X-files/series/4/episodes/max) e o servidor responder com um URI que fornece um link exclusivo canônico curto para esse novo recurso (ou seja /X-Ffiles/episodes/91)
thecoshman
@ thecoshman o problema é que a estrutura da URL não pertence ao cliente. Ler sobre a autodescoberta (também parte do REST) ​​pode ajudar a deixar isso claro.
Joshcodes
@ Joshcodes então, por essa lógica, um cliente nunca deve usar PUT para criar, pois não deve se preocupar em fornecer o URL. Bem ... a menos que o servidor forneça um URL para o PUT, se o cliente quiser colocá-lo ... algo como "PUT / comments / new" e o servidor possa responder "204 / comments / 234532", mas isso parece um pouco RPC para mim, o cliente deve apenas POST para / comentários ...
thecoshman
24

De uma maneira muito simples, estou tomando o exemplo da linha do tempo do Facebook.

Caso 1: quando você publica algo em sua linha do tempo, é uma nova entrada. Portanto, nesse caso, eles usam o método POST porque o método POST é não-idempotente.

Caso 2: se seu amigo comentar sua postagem pela primeira vez, isso também criará uma nova entrada no banco de dados para que o método POST seja usado.

Caso 3: se o seu amigo editar o comentário dele, nesse caso, ele possui um ID de comentário, para atualizar um comentário existente em vez de criar uma nova entrada no banco de dados. Portanto, para esse tipo de operação, use o método PUT porque é idempotente. *

Em uma única linha, use o POST para adicionar uma nova entrada no banco de dados e PUT para atualizar algo no banco de dados.

UniCoder
fonte
4
Se o comentário for um objeto com propriedade como ID do usuário, data de criação, mensagem de comentário etc. e, no momento da edição, apenas a mensagem de comentário estiver sendo atualizada, PATCH deve ser feito aqui?
precisa saber é o seguinte
O PUT é usado pelo FB para atualizar o comentário porque um recurso existente está sendo atualizado, e é isso que o PUT faz (atualiza um recurso). PUT é idempotente, ao contrário do POST. Um verbo HTTP sendo idempotente afeta o tratamento de erros, mas não determina o uso. Veja a minha resposta para um maior detalhe explicação: stackoverflow.com/questions/630453/put-vs-post-in-rest/...
Joshcodes
21

A consideração mais importante é a confiabilidade . Se uma mensagem POST for perdida, o estado do sistema é indefinido. A recuperação automática é impossível. Para mensagens PUT, o estado é indefinido apenas até a primeira tentativa bem-sucedida.

Por exemplo, pode não ser uma boa ideia criar transações com cartão de crédito com o POST.

Se você tiver URIs gerados automaticamente em seu recurso, ainda poderá usar PUT passando um URI gerado (apontando para um recurso vazio) para o cliente.

Algumas outras considerações:

  • O POST invalida cópias em cache de todo o recurso que contém (melhor consistência)
  • As respostas PUT não são armazenáveis ​​em cache, enquanto as respostas POST são (Exigir local de conteúdo e expiração)
  • O PUT é menos suportado, por exemplo, Java ME, navegadores mais antigos, firewalls
Hans Malherbe
fonte
Isto está incorreto. Para o POST, o estado também é indefinido apenas até a primeira nova tentativa bem-sucedida. Em seguida, o servidor aceita o POST (a mensagem nunca chegou), gera um conflito 409 para um ID duplicado (mensagem chegou, a resposta foi perdida) ou qualquer outra resposta válida.
precisa saber é o seguinte
Em geral, um agente do usuário não seria capaz de repetir com segurança a operação POST, pois a operação POST não garante que duas operações tenham o mesmo efeito que uma. O termo "ID" não tem nada a ver com HTTP. O URI identifica o recurso.
Hans Malherbe
Um agente do usuário pode "seguramente" tentar novamente uma operação POST quantas vezes quiser. Ele receberá apenas um erro de ID duplicado (supondo que o recurso tenha um ID) ou um erro de dados duplicados (supondo que seja um problema e que o recurso não tenha IDs).
27714 Joshcodes
Golpeia a cabeça contra a parede. O HTTP não tem solução para o problema da confiabilidade, e isso não é bem entendido, não é muito discutido e simplesmente não é atendido na grande maioria dos aplicativos da Web. @ Joshcodes Eu tenho uma resposta para esta pergunta. Eu concordo essencialmente com Hans. Há um problema.
bbsimonbb
@bbsimonbb, o HTTP tem um conjunto robusto e bem documentado de respostas a erros. Minha resposta a esta pergunta ( stackoverflow.com/questions/630453/put-vs-post-in-rest/… ) aborda como usar o http de acordo com a especificação para obter consistência.
Joshcodes
17

Os leitores novos deste tópico ficarão impressionados com a interminável discussão sobre o que você deve fazer e a relativa ausência de lições da experiência. O fato de o REST ser "preferido" em relação ao SOAP é, suponho, um aprendizado de alto nível com a experiência, mas, por Deus, devemos ter progredido a partir daí? É 2016. A dissertação de Roy foi em 2000. O que desenvolvemos? Foi divertido? Foi fácil integrar? Suportar? Ele suportará o surgimento de smartphones e conexões móveis esquisitas?

Segundo ME, as redes da vida real não são confiáveis. Solicita tempo limite. As conexões são redefinidas. As redes ficam inoperantes por horas ou dias por vez. Os trens entram em túneis com usuários móveis a bordo. Para qualquer solicitação (como ocasionalmente reconhecido em toda essa discussão), a solicitação pode cair na água a caminho ou a resposta pode cair na água no caminho de volta. Nessas condições, emitir solicitações PUT, POST e DELETE diretamente contra recursos substantivos sempre me pareceu um pouco brutal e ingênuo.

O HTTP não faz nada para garantir a conclusão confiável da solicitação-resposta, e isso é ótimo porque esse é o trabalho dos aplicativos que reconhecem a rede. Ao desenvolver esse aplicativo, você pode percorrer os aros para usar PUT em vez do POST e, em seguida, mais aros para dar um certo tipo de erro no servidor se detectar solicitações duplicadas. De volta ao cliente, você precisa pular etapas para interpretar esses erros, buscar novamente, revalidar e republicar.

Ou você pode fazer o seguinte : considere suas solicitações inseguras como recursos efêmeros para um único usuário (vamos chamá-los de ações). Os clientes solicitam uma nova "ação" em um recurso substantivo com um POST vazio para o recurso. O POST será usado apenas para isso. Uma vez em posse do URI da ação recém-criada com segurança, o cliente coloca a solicitação insegura no URI da ação, não no recurso de destino . Resolver a ação e atualizar o recurso "real" é o trabalho da sua API e é aqui dissociado da rede não confiável.

O servidor faz o negócio, retorna a resposta e a armazena na URI de ação acordada . Se algo der errado, o cliente repetirá a solicitação (comportamento natural!) E, se o servidor já a tiver visto, repetirá a resposta armazenada e não fará mais nada .

Você identificará rapidamente a semelhança com as promessas: criamos e devolvemos o espaço reservado para o resultado antes de fazer qualquer coisa. Também como uma promessa, uma ação pode ter sucesso ou falhar uma vez, mas seu resultado pode ser buscado repetidamente.

O melhor de tudo é que damos aos aplicativos de envio e recebimento a chance de vincular a ação identificada exclusivamente à exclusividade em seus respectivos ambientes. E podemos começar a exigir e impor !, comportamento responsável dos clientes: repita suas solicitações o quanto quiser, mas não gere uma nova ação até que você possua um resultado definitivo da existente.

Como tal, numerosos problemas espinhosos desaparecem. Solicitações de inserção repetidas não criarão duplicatas e não criaremos o recurso real até que possuamos os dados. (as colunas do banco de dados podem permanecer não anuláveis). Solicitações de atualização repetidas não atingem estados incompatíveis e não substituem as alterações subseqüentes. Os clientes podem (re) buscar e processar sem problemas a confirmação original por qualquer motivo (falha do cliente, falta de resposta etc.).

Solicitações de exclusão sucessivas podem ver e processar a confirmação original, sem ocorrer um erro 404. Se as coisas demorarem mais do que o esperado, podemos responder provisoriamente e temos um local onde o cliente pode verificar novamente o resultado definitivo. A parte mais legal desse padrão é sua propriedade Kung-Fu (Panda). Tomamos uma fraqueza, a propensão para os clientes repetirem uma solicitação sempre que não entenderem a resposta e a transformarem em uma força :-)

Antes de me dizer que isso não é RESTful, considere as inúmeras maneiras pelas quais os princípios REST são respeitados. Os clientes não constroem URLs. A API permanece detectável, embora com uma pequena alteração na semântica. Os verbos HTTP são usados ​​adequadamente. Se você acha que essa é uma grande mudança para implementar, posso dizer por experiência que não é.

Se você acha que terá enormes quantidades de dados para armazenar, vamos falar sobre volumes: uma confirmação típica de atualização é uma fração de um kilobyte. Atualmente, o HTTP oferece um ou dois minutos para responder definitivamente. Mesmo que você armazene ações apenas por uma semana, os clientes terão muitas chances de alcançá-los. Se você tiver volumes muito altos, convém um armazenamento de valores-chave dedicado compatível com ácido ou uma solução na memória.

bbsimonbb
fonte
1
Armazenar a resposta não será como manter uma sessão? O que causaria problemas de escala (horizontais).
Saurabh Harwande
17

Além das diferenças sugeridas por outros, quero adicionar mais uma.

No método POST , você pode enviar parâmetros de corpo emform-data

No método PUT , você deve enviar parâmetros de corpo emx-www-form-urlencoded

Cabeçalho Content-Type:application/x-www-form-urlencoded

De acordo com isso, você não pode enviar arquivos ou dados de várias partes no método PUT

EDITAR

O tipo de conteúdo "application / x-www-form-urlencoded" é ineficiente para enviar grandes quantidades de dados binários ou texto contendo caracteres não ASCII. O tipo de conteúdo "dados de várias partes / formulário" deve ser usado para enviar formulários que contêm arquivos, dados não ASCII e dados binários.

O que significa que se você tiver que enviar

arquivos, dados não ASCII e dados binários

você deve usar o método POST

Rohit Dhiman
fonte
3
Por que isso não foi votado? Se for verdade, essa é uma distinção crítica, não é?
precisa saber é o seguinte
2
Eu enfrentei isso ao implementar a API para a atualização do perfil, que inclui o upload de fotos do perfil do usuário. Então eu testei com o carteiro, Ajax, PHP curl e laravel 5.6 como back-end.
Rohit Dhiman
14

Sempre parece haver alguma confusão sobre quando usar o HTTP POST versus o método HTTP PUT para serviços REST. A maioria dos desenvolvedores tentará associar operações CRUD diretamente aos métodos HTTP. Argumentarei que isso não está correto e não se pode simplesmente associar os conceitos CRUD aos métodos HTTP. Isso é:

Create => HTTP PUT
Retrieve => HTTP GET
Update => HTTP POST
Delete => HTTP DELETE

É verdade que o R (etrieve) e D (elete) das operações CRUD podem ser mapeados diretamente para os métodos HTTP GET e DELETE, respectivamente. No entanto, a confusão está nas operações C (reate) e U (atualização). Em alguns casos, é possível usar o PUT para criar, enquanto em outros casos um POST será necessário. A ambiguidade está na definição de um método HTTP PUT versus um método HTTP POST.

De acordo com as especificações do HTTP 1.1, os métodos GET, HEAD, DELETE e PUT devem ser idempotentes e o método POST não é idempotente. Isso significa que uma operação é idempotente se puder ser executada em um recurso uma ou várias vezes e sempre retornar o mesmo estado desse recurso. Enquanto uma operação não idempotente pode retornar um estado modificado do recurso de uma solicitação para outra. Portanto, em uma operação não idempotente, não há garantia de que alguém receberá o mesmo estado de um recurso.

Com base na definição idempotente acima, minha opinião sobre o método HTTP PUT versus o método HTTP POST para serviços REST é: Use o método HTTP PUT quando:

The client includes all aspect of the resource including the unique identifier to uniquely identify the resource. Example: creating a new employee.
The client provides all the information for a resource to be able to modify that resource.This implies that the server side does not update any aspect of the resource (such as an update date).

Nos dois casos, essas operações podem ser executadas várias vezes com os mesmos resultados. Esse é o recurso não será alterado solicitando a operação mais de uma vez. Portanto, uma verdadeira operação idempotente. Use o método HTTP POST quando:

The server will provide some information concerning the newly created resource. For example, take a logging system. A new entry in the log will most likely have a numbering scheme which is determined on the server side. Upon creating a new log entry, the new sequence number will be determined by the server and not by the client.
On a modification of a resource, the server will provide such information as a resource state or an update date. Again in this case not all information was provided by the client and the resource will be changing from one modification request to the next. Hence a non idempotent operation.

Conclusão

Não correlacione e mapeie diretamente operações CRUD para métodos HTTP para serviços REST. O uso de um método HTTP PUT versus um método HTTP POST deve ser baseado no aspecto idempotente dessa operação. Ou seja, se a operação for idempotente, use o método HTTP PUT. Se a operação não for idempotente, use o método HTTP POST.

Burhan
fonte
2
Atualize => HTTP POST: POST não é para atualização
Premraj
@premraj Você assumiu que Burhan está lhe dizendo para não fazer; ou seja, você está confluindo CRUD, REST e HTTP. Se você ler a RFC 7231, onde essas coisas são definidas, você encontrará que no protocolo HTTP, a definição de POST certamente permitirá a atualização. São apenas as restrições do REST que dizem o contrário.
IAM_AL_X 16/04
13

o servidor de origem pode criar o recurso com esse URI

Então você usa POST e provavelmente, mas não é necessário, PUT para criação de recursos. Você não precisa apoiar os dois. Para mim, o POST é perfeitamente suficiente. Portanto, é uma decisão de design.

Como sua cotação mencionou, você usa PUT para criar um recurso não atribuído a um IRI e deseja criar um recurso de qualquer maneira. Por exemplo, PUT /users/123/passwordgeralmente substitui a senha antiga por uma nova, mas você pode usá-la para criar uma senha se ela ainda não existir (por exemplo, por usuários registrados recentemente ou restaurando usuários banidos).

inf3rno
fonte
Acho que você conseguiu fornecer um dos poucos bons exemplos de como usar o PUT, bem feito.
Thecoshman
12

Vou pousar com o seguinte:

PUT refere-se a um recurso identificado pelo URI. Nesse caso, você está atualizando. É a parte dos três verbos que se referem aos recursos - excluir e começar a ser os outros dois.

O POST é basicamente uma mensagem de forma livre, com seu significado sendo definido como "fora da banda". Se a mensagem puder ser interpretada como adicionando um recurso a um diretório, tudo bem, mas basicamente você precisa entender a mensagem que está enviando (postando) para saber o que acontecerá com o recurso.


Como PUT, GET e DELETE se referem a um recurso, eles também são, por definição, idempotentes.

O POST pode executar as outras três funções, mas a semântica da solicitação será perdida nos intermediários, como caches e proxies. Isso também se aplica ao fornecimento de segurança no recurso, pois o URI de uma postagem não indica necessariamente o recurso ao qual está sendo aplicado (pode ser).

Um PUT não precisa ser uma criação; o serviço poderá ter erro se o recurso ainda não estiver criado, mas atualizá-lo. Ou vice-versa - ele pode criar o recurso, mas não permitir atualizações. A única coisa necessária sobre o PUT é que ele aponta para um recurso específico e sua carga útil é a representação desse recurso. Uma PUT bem-sucedida significa (exceto interferência) que um GET recuperaria o mesmo recurso.


Editar: Mais uma coisa - um PUT pode criar, mas, se o fizer, o ID deve ser um ID natural - também conhecido como endereço de email. Dessa forma, quando você coloca duas vezes, o segundo put é uma atualização do primeiro. Isso o torna idempotente .

Se o ID for gerado (um novo ID de funcionário, por exemplo), o segundo PUT com a mesma URL criará um novo registro, o que viola a regra de idempotência. Nesse caso, o verbo seria POST e a mensagem (não recurso) seria criar um recurso usando os valores definidos nesta mensagem.

Gerard ONeill
fonte
9

A semântica deve ser diferente, pois "PUT", como "GET", deve ser idempotente - o que significa que você pode solicitar exatamente o mesmo PUT várias vezes e o resultado será como se você a executasse apenas uma vez.

Descreverei as convenções que considero mais utilizadas e mais úteis:

Quando você coloca um recurso em um URL específico, o que acontece é que ele deve ser salvo nesse URL ou algo nesse sentido.

Quando você posta para um recurso em um URL específico, geralmente está postando uma informação relacionada a esse URL. Isso implica que o recurso no URL já existe.

Por exemplo, quando você deseja criar um novo fluxo, você pode COLOCÁ-lo em algum URL. Mas quando você deseja POSTAR uma mensagem em um fluxo existente, você POST na URL.

Quanto à modificação das propriedades do fluxo, você pode fazer isso com PUT ou POST. Basicamente, use apenas "PUT" quando a operação for idempotente - caso contrário, use POST.

Observe, no entanto, que nem todos os navegadores modernos oferecem suporte a verbos HTTP que não sejam GET ou POST.

Gregory Magarshak
fonte
O que você descreve como POST é como o PATCH deve se comportar. O POST deve significar algo mais parecido com "anexar" como em "postar na lista de discussão".
Alexander Torstling
8

Na maioria das vezes, você os usará assim:

  • POSTAR um recurso em uma coleção
  • COLOCAR um recurso identificado pela coleção /: id

Por exemplo:

  • POST / itens
  • PUT / itens / 1234

Nos dois casos, o corpo da solicitação contém os dados para o recurso a ser criado ou atualizado. Deveria ser óbvio pelos nomes das rotas que o POST não é idempotente (se você chamá-lo 3 vezes, ele criará 3 objetos), mas PUT é idempotente (se você chamá-lo 3 vezes o resultado é o mesmo). PUT é frequentemente usado para operação "upsert" (criar ou atualizar), mas você sempre pode retornar um erro 404 se desejar usá-lo apenas para modificar.

Observe que o POST "cria" um novo elemento na coleção e PUT "substitui" um elemento em uma determinada URL, mas é uma prática muito comum usar o PUT para modificações parciais, ou seja, usá-lo apenas para atualizar os recursos existentes e modifique apenas os campos incluídos no corpo (ignorando os outros campos). Tecnicamente, isso está incorreto. Se você deseja ser purista de REST, o PUT deve substituir todo o recurso e você deve usar PATCH para a atualização parcial. Pessoalmente, não me importo tanto quanto o comportamento é claro e consistente em todos os pontos de extremidade da API.

Lembre-se de que REST é um conjunto de convenções e diretrizes para manter sua API simples. Se você terminar com uma solução alternativa complicada apenas para marcar a caixa "RESTfull", estará derrotando o objetivo;)

tothemario
fonte
7

Embora exista provavelmente uma maneira agnóstica de descrevê-las, parece estar em conflito com várias declarações de respostas a sites.

Sejamos claros e diretos aqui. Se você é um desenvolvedor .NET trabalhando com API da Web, os fatos são (da documentação da API da Microsoft), http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web -api-that-support-crud-operations :

1. PUT = UPDATE (/api/products/id)
2. MCSD Exams 2014 -  UPDATE = PUT, there are **NO** multiple answers for that question period.

Claro que você "pode" usar o "POST" para atualizar, mas basta seguir as convenções estabelecidas para você com sua estrutura fornecida. No meu caso, é .NET / Web API, então PUT é para UPDATE, não há debate.

Espero que isso ajude os desenvolvedores da Microsoft que leem todos os comentários nos links dos sites Amazon e Sun / Java.

Tom Stickel
fonte
7

Aqui está uma regra simples:

Colocar em um URL deve ser usado para atualizar ou criar o recurso que pode ser localizado nesse URL.

O POST para uma URL deve ser usado para atualizar ou criar um recurso localizado em outra URL ("subordinada") ou que não seja localizável via HTTP.

Adam Griffiths
fonte
1
PUT não é para atualização, é para substituição; observe que, para criar, você não está substituindo nada por algo. O POST não é absolutamente para atualização em qualquer formato.
Thecoshman
2
A especificação http diz isso? Ou você está baseando seu comentário em outra coisa?
Adam Griffiths
É apenas senso comum, como você atualiza algo quando não sabe o que está atualizando? O POST é para criar um novo recurso.
Thecoshman
2
thecoshman - você está abusando da semântica aqui - uma substituição pode ser uma atualização se for o mesmo recurso com algumas diferenças. Uma substituição é válida apenas para put se replace for usado para alterar o mesmo recurso. A substituição por um recurso novo e diferente é inválida (remova o antigo e adicione novo?), Especialmente se o recurso 'novo' não tiver um ID natural. POST, OTOH, é algo que pode criar, atualizar, substituir e excluir - o uso da postagem depende da existência ou não de uma mensagem para interpretar, como 'aplicar o desconto', que pode ou não alterar o recurso, dependendo da lógica.
precisa
Quanto ao seu segundo comentário - que tal você 'obter' o recurso, modificar os campos necessários e depois devolvê-lo? Ou se o recurso vem de uma fonte diferente, mas usa um ID natural (o ID externo) - o put naturalmente atualiza o recurso no URL quando os dados originais são alterados.
precisa
6

Se você estiver familiarizado com as operações do banco de dados, existem

  1. Selecione
  2. Inserir
  3. Atualizar
  4. Excluir
  5. Mesclar (atualize se já existir, ou insira)

Eu uso PUTpara Mesclar e atualizo como operações e uso POSTpara Inserções.

Rajan
fonte
5

Na prática, o POST funciona bem para criar recursos. A URL do recurso recém-criado deve ser retornada no cabeçalho de resposta do local. PUT deve ser usado para atualizar completamente um recurso. Por favor, entenda que essas são as práticas recomendadas ao projetar uma API RESTful. A especificação HTTP, como tal, não restringe o uso de PUT / POST com algumas restrições para criar / atualizar recursos. Dê uma olhada em http://techoctave.com/c7/posts/71-twitter-rest-api-dissected que resume as melhores práticas.

java_geek
fonte
Na maioria das vezes, ao ler todo esse barulho, você parece estar na bola. Eu diria, porém, que devemos nos referir a PUT como o método de substituição, em vez de criar / atualizar. Eu acho que descreve melhor em um o que faz.
Thecoshman