Excluindo um recurso usando http DELETE

122

Portanto, considerando que o verbo DELETE em Http é idempotente, quando eu emito a seguinte solicitação, o que deve acontecer no segundo (ou terceiro, ou quarto, etc ...)?

DELETE /person/123

Na primeira vez, o recurso é excluído e eu retorno 204 (com êxito, sem conteúdo). Devo retornar um 204 em chamadas subseqüentes ou um 404 (não encontrado)?

Craig Wilson
fonte

Respostas:

152

Como as solicitações HTTP em um sistema sem estado devem ser independentes, os resultados de uma solicitação não devem depender de uma solicitação anterior. Considere o que aconteceria se dois usuários executassem um DELETE no mesmo recurso simultaneamente. Faz sentido que a segunda solicitação obtenha um 404. O mesmo deve ser verdadeiro se um usuário fizer duas solicitações.

Estou supondo que ter DELETE retornar duas respostas diferentes não pareça idempotente para você. Acho útil pensar em solicitações idempotentes como deixar o sistema no mesmo estado, sem necessariamente ter a mesma resposta. Portanto, independentemente de você excluir um recurso existente ou tentar excluir um recurso que não existe, o estado do recurso do servidor é o mesmo.

Darrel Miller
fonte
4
Obrigado. Isso faz muito sentido. Eu estava realmente pensando em idempotente como retornando a mesma resposta.
Craig Wilson
4
@Craig Careful! No livro de receitas, Subbu contradiz completamente o que acabei de dizer. Ele diz que a idempotência significa que deve retornar a mesma resposta. Felizmente, Subbu estará no RESTFest, então eu vou esclarecer com ele lá.
precisa
57
Se você excluir algo que não existe, basta retornar um 204 (mesmo que o recurso nunca exista). O cliente queria que o recurso se fosse e se foi. Retornar um 404 está expondo o processamento interno que não é importante para o cliente e resultará em uma condição de erro desnecessária.
Brian
9
@DarrelMiller Eu acho que o principal conceito aqui é que você não deve usar DELETE para verificar se existe um recurso, você primeiro utilizaria GET para isso. Então, se a resposta for 200, você executará um DELETE; caso contrário, nem se preocupe em fazer isso. Então, acho que faz sentido sempre retornar um 204 em DELETE.
manei_cc
10
@ Brian O RFC diz que deveria se comportar como rm. rmretorna um erro se não existir. tools.ietf.org/html/rfc7231#section-4.3.5
Dax Fohl
32

O livro de receitas de serviços da Web RESTful é um ótimo recurso para isso. Por acaso, sua visualização no google mostra a página sobre DELETE (página 11):

O método DELETE é idempotente. Isso implica que o servidor deve retornar o código de resposta 200 (OK), mesmo se o servidor excluiu o recurso em uma solicitação anterior. Mas, na prática, implementar DELETE como uma operação idempotente exige que o servidor acompanhe todos os recursos excluídos. Caso contrário, ele pode retornar um 404 (não encontrado).

yves amsellem
fonte
Sim, isso parece um ótimo recurso. No entanto, a seção DELETE não está sendo exibida para mim (é a página 23 e a visualização foi redigida). Você já leu este livro? Você sabe a resposta para minha pergunta?
Craig Wilson
Este livro é essencial para a criação do REST (ele fala em particular, não em um idioma).
Yves Amsellem
7
@ Craig lendo o livro de receitas, ele diz que você deve retornar 200 OK, mesmo se você já tiver excluído. No entanto, na prática, que exigiria o servidor para acompanhar todos os recursos que foram excluídos, portanto, você pode usar 404. Ele continua a dizer que as preocupações de segurança podem exigir que você volte sempre 404. Página 11.
Darrel Miller
+1 Segundo e recomendo o livro para projetar serviços RESTful.
Paul DelRe
18
Bem, o livro está errado. Idempotência não implica que o código de status seja o mesmo. O que é relevante é o estado final do servidor.
Julian Reschke
13

Concordo com o que a resposta escolhida atual disse, que o 2º (e 3º, 4º, ...) DELETE deve receber um 404 . E notei que a resposta tem 143 votos positivos, mas também tem um comentário oposto, que tem 54 votos positivos, então a comunidade é dividida em 2 campos na proporção de aproximadamente 3: 1. Aí vem mais informações para resolver esse longo debate.

  1. Antes de tudo, NÃO vamos começar com o que "eu" penso, o que "você" pensa ou o que outro autor do livro pensa. Vamos começar com as especificações HTTP, ou seja, o RFC 7231.

    • A RFC 7231, seção 4.3.5 DELETE, mencionou apenas que uma resposta bem-sucedida deveria ser 2xx, mas não destacou o que um DELETE subsequente obteria. Então, vamos nos aprofundar.
    • O RFC 7231, seção 6.5.4 404 não encontrado, diz que a resposta 404 é para um recurso que não existe. Como nenhum método http específico (em particular, não DELETE) é chamado para ser tratado de outra forma, podemos intuitivamente obter uma impressão (e com razão) de que minha solicitação DELETE /some/resource/which/does/not/existdeve resultar em 404. Em seguida, DELETE /some/resource/which/happened/to/be/removed/by/someone/else/five/days/agotambém é possível retornar um 404 Então, por que deveria DELETE /some/resource/i/deleted/five/seconds/agoser diferente? "Mas e quanto à idempotência ?!", eu posso ouvir que você está gritando isso. Espere, estamos prestes a entrar nisso.
    • Historicamente, o RFC 2616, publicado em 1999, era as especificações HTTP 1.1 mais referenciadas. Infelizmente, sua descrição sobre a idempotência foi vaga , deixando espaço para todos esses debates. Mas essas especificações foram substituídas pela RFC 7231. Citado na RFC 7231, seção 4.2.2 Métodos Idempotentes , ênfase minha:

      Um método de solicitação é considerado "idempotente" se o EFEITO NO SERVIDOR pretendido de várias solicitações idênticas com esse método for o mesmo que o efeito de uma única solicitação. Dos métodos de solicitação definidos por esta especificação, PUT, DELETE e métodos de solicitação seguros são idempotentes .

      Portanto, está escrito nas especificações, idempotency tem tudo a ver com o efeito no servidor. O primeiro DELETE retornando um 204 e o subsequente DELETE retornando 404, esse código de status diferente NÃO torna o DELETE não idempotente. Usar esse argumento para justificar um retorno 204 subsequente é simplesmente irrelevante.

  2. OK, então não se trata de idempotência. Mas então uma pergunta de acompanhamento pode ser: e se ainda optarmos por usar o 204 no DELETE subsequente? Tudo bem?

    Boa pergunta. A motivação é compreensível: permitir que o cliente ainda atinja o resultado pretendido, sem se preocupar com o tratamento de erros. Eu diria que retornar 204 no DELETE subsequente é uma "mentira branca" do lado do servidor amplamente inofensiva, que o lado do cliente não notará imediatamente a diferença. É por isso que existem ~ 25% de pessoas fazendo isso na natureza e, aparentemente, ainda funciona. Lembre-se de que essa mentira pode ser considerada semanticamente estranha, porque GET /non-existretorna 404, mas DELETE /non-existdá 204, nesse ponto o cliente descobriria que seu serviço não está totalmente em conformidade com a seção 6.5.4 404 Não encontrado .

    Mas quero ressaltar que, a maneira pretendida sugerida pela RFC 7231, ou seja, retornando 404 no DELETE subsequente, não deve ser um problema em primeiro lugar. 3x mais desenvolvedores escolheram fazer isso, e você já ouviu um incidente grave ou reclamação causada por um cliente não conseguir lidar com o 404? Presumivelmente, não, e isso ocorre porque, qualquer cliente decente que implemente HTTP DELETE (ou qualquer método HTTP, nesse caso), não assumirá cegamente que o resultado sempre será bem-sucedido 2xx. E então, assim que o desenvolvedor começar a considerar o tratamento de erros, o 404 Not Found seria um dos primeiros erros a serem lembrados. Nesse ponto, ele provavelmente chegaria a uma conclusão de que é semanticamente seguro para uma operação HTTP DELETE ignorar um erro 404. E eles fizeram isso.

Problema resolvido.

RayLuo
fonte
2
+1 "idempotência diz respeito ao efeito no servidor". Meticulosamente respondeu. Bem feito! Acredito no 404 para solicitações subsequentes de DELETE.
nwayve 16/04
11

Primeiro DELETE : 200 ou 204.

DELETEs subsequentes : 200 ou 204.

Justificativa : DELETE deve ser idempotente. Se você retornar 404 em um segundo DELETE, sua resposta será alterada de um código de sucesso para um código de erro . O programa cliente pode executar ações incorretas com base na suposição de que DELETE falhou.

Exemplo :

  • Suponha que sua operação DELETE faça parte de uma operação de várias etapas (ou uma "saga") executada pelo programa cliente.
  • O programa cliente pode ser um aplicativo móvel que realiza uma transação bancária, por exemplo.
  • Digamos que o programa cliente tenha uma nova tentativa automática para uma operação DELETE (faz sentido, porque DELETE deve ser idempotente).
  • Digamos que o primeiro DELETE foi executado com êxito, mas a resposta 200 foi perdida no caminho para o programa cliente.
  • O programa cliente tentará novamente o DELETE.
  • Se a segunda tentativa retornar 404, o programa cliente poderá cancelar a operação geral devido a esse código de erro.
  • Porém, como o primeiro DELETE executado com êxito no servidor, o sistema pode ficar em um estado inconsistente .
  • Se a segunda tentativa retornar 200 ou 204, o programa cliente continuará conforme o esperado.

Apenas para ilustrar o uso dessa abordagem, o guia de estilo da API HTTP do PayPal tem as seguintes diretrizes:

DELETE: Este método DEVE retornar o código de status 204, pois não há necessidade de retornar nenhum conteúdo na maioria dos casos, pois a solicitação é para excluir um recurso e ele foi excluído com êxito.

Como o método DELETE DEVE ser idempotente, ele ainda deve retornar 204, mesmo que o recurso já tenha sido excluído. Normalmente, o consumidor da API não se importa se o recurso foi excluído como parte desta operação ou antes. Essa também é a razão pela qual 204 em vez de 404 deve ser retornado.

Paulo Merson
fonte
1
A questão é: o que é importante para o cliente, que ele excluiu o recurso ou que o recurso foi excluído. E se algum outro cliente excluísse o recurso durante a saga. Deseja realmente falhar, considerando que o objetivo do cliente foi alcançado?
Darrel Miller
1
@DarrelMiller Bom argumento. O que é mais importante depende do contexto de negócios. Mas, em geral, prefiro retornar 204 em uma segunda tentativa DELETE, mesmo que o recurso tenha sido excluído por outro cliente. Não quero que o serviço falhe (ou seja, 404), pois o objetivo do cliente foi alcançado.
Paulo Merson 21/07
2
Como outros mencionados, a idempotência não é o seu código de resposta, é o estado do seu servidor.
Niranjan
@Niranjan Concordo que idempotência é sobre o estado do servidor, mas um código de resposta diferente pode levar o cliente a alterar desnecessariamente o estado do servidor, cancelando uma saga em andamento.
Paulo Merson
@Paulo Merson, que código você retornará se o cliente solicitar a exclusão de um item que NUNCA existiu? 204? ou 404? Se você sempre retorna 204, qual é o sentido de verificar o código de retorno?
frenchone 21/09/19