REST, HTTP DELETE e parâmetros

135

Existe algo não RESTful no fornecimento de parâmetros para uma solicitação HTTP DELETE?


Meu cenário é que estou modelando o "Tem certeza de que deseja excluir isso?" cenário. Em alguns casos, o estado do recurso sugere que a exclusão solicitada pode ser inválida. Você provavelmente pode imaginar alguns cenários em que a confirmação de uma exclusão é necessária

A solução que adotamos é passar um parâmetro para a solicitação de exclusão para indicar que não há problema em prosseguir com a exclusão ("? Force_delete = true")

por exemplo

DELETE http://server/resource/id?force_delete=true

Eu acredito que ainda é tranquilo desde:

(a) A semântica de DELETE não está sendo alterada - o usuário ainda pode enviar uma solicitação DELETE normal, mas isso pode falhar com 409 e o corpo da resposta explica o porquê. Eu digo que pode falhar porque (por razões que não valem a pena explicar) em algumas ocasiões, não há motivos para solicitar ao usuário.

(b) Não há nada na dissertação de Roy que sugira que seja contra o espírito do REST - por que haveria uma vez que o HTTP é apenas uma implementação do REST, por que os parâmetros HTTP passantes são importantes


Alguém pode me indicar uma declaração definitiva que identifique o motivo pelo qual isso não é RESTful?

Em uma pergunta relacionada, se o usuário não especificar force_delete, retornarei 409 Conflict- esse é o código de resposta mais apropriado?


Acompanhamento

Após algumas pesquisas, acho que adicionar parâmetros ao DELETE pode violar vários princípios.

A primeira é que a implementação possivelmente viola a "Interface Uniforme" (consulte a seção 5.1.5 da dissertação de Roy

Ao adicionar 'force_delete', adicionamos uma restrição adicional ao método DELETE já bem definido. Essa restrição é significativa apenas para nós.

Você também pode argumentar que isso viola o "5.1.2 Client-Server", pois o diálogo de confirmação é realmente uma preocupação da interface do usuário e, novamente, nem todos os clientes desejam confirmar a exclusão.

Sugestões alguém?

Chris McCauley
fonte
1
Seu URL para a dissertação de Roy contém um ")" que causa um erro 404. ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm .
NuclearPeon

Respostas:

78

Não, não é RESTful. A única razão pela qual você deve colocar um verbo ( force_delete) no URI é se você precisa sobrecarregar os métodos GET / POST em um ambiente em que os métodos PUT / DELETE não estão disponíveis. A julgar pelo uso do método DELETE, esse não é o caso.

O código de erro HTTP 409/Conflictdeve ser usado para situações em que existe um conflito que impede o serviço RESTful de executar a operação, mas ainda existe a chance de o usuário conseguir resolver o conflito sozinho. Uma confirmação de pré-exclusão (onde não há conflitos reais que impediria a exclusão) não é um conflito em si, pois nada impede a API de executar a operação solicitada.

Como Alex disse (não sei quem recusou, ele está correto), isso deve ser tratado na interface do usuário, porque um serviço RESTful, como tal, apenas processa solicitações e, portanto, não tem estado (ou seja, não deve depender de confirmações mantendo qualquer informação do servidor sobre uma solicitação).

Dois exemplos de como fazer isso na interface do usuário seriam:

  • pre-HTML5 : * mostra uma caixa de diálogo de confirmação JS ao usuário e envia a solicitação somente se o usuário confirmar
  • HTML5 : * use um formulário com a ação DELETE, onde o formulário conteria apenas os botões "Confirmar" e "Cancelar" ("Confirmar" seria o botão Enviar)

(*) Observe que as versões HTML anteriores a 5 não oferecem suporte a métodos HTTP PUT e DELETE nativamente, no entanto, os navegadores mais modernos podem executar esses dois métodos por meio de chamadas AJAX. Consulte este tópico para obter detalhes sobre o suporte entre navegadores.


Atualização (com base em investigações e discussões adicionais):

O cenário em que o serviço exigiria a force_delete=truepresença da bandeira viola a interface uniforme, conforme definida na dissertação de Roy Fielding. Além disso, conforme RFC HTTP , o método DELETE pode ser substituído no servidor de origem (cliente), o que implica que isso não é feito no servidor de destino (serviço).

Portanto, uma vez que o serviço receba uma solicitação DELETE, deve processá-la sem precisar de confirmação adicional (independentemente de o serviço realmente executar a operação).

Ratos
fonte
2
Você poderia explicar qual restrição REST está sendo violada? Considerando que os URIs devem ser opacos para o cliente, por que você acredita que as expectativas do cliente não estão sendo atendidas com o uso de um HTTP DELETE que exclui um recurso, mas falha ao excluir outro. Não tenho certeza se 409 é o melhor código de status a ser retornado, mas além de ser uma implementação um pouco estranha, não consigo encontrar nenhuma restrição REST que está sendo quebrada.
Darrel Miller
2
@ Darrel: (imho) viola a interface uniforme pelo método DELETE que não funciona conforme os padrões HTTP. Considere um cliente REST que assume um serviço REST padrão - como o serviço permitirá que o cliente saiba que precisa adicionar force_delete=true? Conforme o RFC HTTP, o método DELETE pode ser substituído no servidor de origem (cliente), o que implica que isso não é feito no servidor de destino (serviço). Portanto, entendo que, uma vez que o serviço receba uma solicitação DELETE, ele deve processá-lo sem a necessidade de confirmação (independentemente de o serviço realmente executar a operação).
MicE 30/03/10
1
@ Chris, para o seu segundo ponto: sim, esse é o meu entendimento também, ou seja, que o estado sugere um conflito real e não uma necessidade de confirmação. Acabei de notar a atualização que você fez na sua pergunta e eu concordo - enquanto eu examinava a questão, cheguei à mesma conclusão (que isso viola a interface uniforme e que a confirmação deve ser feita no cliente / interface do usuário) lado). Também deparei com um tópico muito interessante aqui, pode ajudar: mail-archive.com/[email protected]/msg13578.html
MicE
2
@MicE Em grande parte, concordo com você que não é a maneira ideal de lidar com esse cenário. Só estou sendo um pouco exigente quanto ao rótulo "não é RESTful". Por um tempo aqui, essa frase foi jogada em tudo. No entanto, seria possível definir regras para um tipo de mídia que diz que se você tentar EXCLUIR um recurso e receber um erro (eu diria que 403 proibido seria melhor que 409), o cliente deve tentar EXCLUIR um recurso relacionado aderindo a um "force_delete = true". De certa forma, é um pouco como autorização. GET, obtenha 401, adicione o cabeçalho de autenticação e GET novamente.
Darrel Miller
2
@ Darrel: esse é um ponto muito bom, obrigado. E eu já vi pessoas lançando o rótulo não RESTful . Hoje em dia, a barreira entre serviços e aplicativos da web está se tornando muito nebulosa, então um conjunto de pessoas pode ver isso do ponto de vista de serviço puro, enquanto outros o vêem do ponto de vista misto de aplicativo / serviço. É nesse ponto que acredito que a verdadeira questão sobre como fazer a confirmação entra em jogo. @ Chris: atualizado - obrigado senhor por um tópico e discussão muito interessante!
Ratos
35

Eu acho que isso não é repousante. Não acho que o serviço reparador deva lidar com o requisito de forçar o usuário a confirmar uma exclusão. Eu lidaria com isso na interface do usuário.

Especificar force_delete = true faz sentido se essa for a API de um programa? Se alguém estivesse escrevendo um script para excluir este recurso, você gostaria de forçá-lo a especificar force_delete = true para realmente excluir o recurso?

Alex Rockwell
fonte
O primeiro parágrafo da sua resposta é a sua opinião e eu respeito isso, mas você não apontou para algo na literatura que proíbe o uso do URI assim - ele ainda identifica o recurso e o verbo HTTP mais apropriado está sendo usado. Em resposta às suas perguntas; sim, ainda faria sentido (na minha opinião). Eu esperaria um script (talvez com base em CURL) a respeitar a resposta 409 e sugerir ao usuário como o pedido poderia ser reenviado - tudo com base na minha resposta corpo
Chris McCauley
Bom argumento sobre a comparação da API da web com a API de um programa. Geralmente, é uma boa maneira de descobrir se uma API é RESTful ou não.
precisa
18

É uma pergunta antiga, mas aqui estão alguns comentários ...

  1. No SQL, o comando DELETE aceita um parâmetro "CASCADE", que permite especificar que os objetos dependentes também devem ser excluídos. Este é um exemplo de um parâmetro DELETE que faz sentido, mas 'man rm' pode fornecer outros. Como esses casos poderiam ser implementados no REST / HTTP sem um parâmetro?
  2. @ Jan, parece ser uma convenção bem estabelecida que a parte do caminho da URL identifique um recurso, enquanto a string de consulta não (pelo menos não necessariamente). São muitos os exemplos: obter o mesmo recurso, mas em um formato diferente, obter campos específicos de um recurso etc. Se considerarmos a sequência de consultas como parte do identificador do recurso, é impossível ter um conceito de "visualizações diferentes do mesmo recurso" sem recorrer a mecanismos não RESTful, como negociação de conteúdo HTTP (que pode ser indesejável por vários motivos).
Shay Rojansky
fonte
Obrigado por adicioná-lo à conversa, mesmo que não seja muito uma conversa, pois dura anos.
23412 silviot
6

Além da resposta de Alex:

Observe que http: // server / resource / id? Force_delete = true identifica um recurso diferente de http: // server / resource / id . Por exemplo, é uma enorme diferença se você exclui / customers /? Status = old ou / customers /.

Jan

Jan Algermissen
fonte
Discordo, estou livre para fornecer vários URIs para identificar o mesmo recurso.
precisa
18
Yep - todos são livres para fazer uma bagunça :-)
Jan Algermissen
A indicação de URIs canônicos pode ajudar com isso: googlewebmastercentral.blogspot.com/2009/02/…
MicE 30/03/10
@ Chris Só deve haver um URI que retorne uma representação de um recurso. Outros URIs podem se referir ao mesmo conceito, mas fazer um GET deve retornar um 303 Consulte Outro. E apenas para contrariar a objeção óbvia a isso, /foo.xml e /foo.json são dois recursos diferentes.
Darrel Miller
@ Darrell - concordo, mas o formato não é um problema aqui. Além disso, o .format é uma convenção no Rails e outras estruturas que não fazem parte do REST - você deve usar a negociação de conteúdo em HTTP com MIME ou microformatos para implementá-lo completamente.
precisa