RESTful DELETE com payload

Pessoa, boa noite!

Estou desenvolvendo uma API RESTful e estou com um problema com a operação “excluir bloco”, o que era para ser um simples DELETE se tornou um problema, há um requisito que exige que seja informado o motivo da exclusão.

[DELETE]
…/blocos/12
payload: “Motivo da exclusão”

Estava tudo lindo, a API ficando bacana, mas na hora de implementar descobri que o RESTEasy não dá suporte a DELETE com payload.

Alguém já passou por problema parecido? Há alguma forma de fazer um DELETE com payload? Caso não seja possível qual a forma mais elegante de lidar com uma situação dessas?

Vlw!

Você não consegue usar a propria url e passar o parametro como se fosse uma URL get
por exemplo

url-path/blocos/12?payload="Motivo ..."&motivo2="descrição"

Acontece que dentro das melhores práticas para construção de RESTFul APIs os query parameters são utilizados para passagem de parâmetros opcionais. por exemplos os filtros.

[GET]
…/usuarios?status=ativo&sexo=masculino

No caso o motivo da exclusão é um parâmetro obrigatório.

Boa tarde
andreguimaster,

Segue exemplo abaixo com Spring

  @RequestMapping(value = "/blocos/{id}", method = RequestMethod.DELETE)
  public HttpEntity<Void> delete(@PathVariable Long id, @RequestBody Motivo motivo) {
      
    //Sua lógica para exclusão. Lembrando que caso falhe tanto a persistencia do motivo quanto a exclusão do bloco
    // Você deve desfazer as transações e retornar um BadRequest.
 
  }

att,

BadRequest é um erro do cliente: informar o ID inválido, por exemplo.
Falha na persistência ou log eu diria que é um Server Error.

Tava pensando nessa falha no contexto do Motivo vir com um problema de consistência ou no caso do bloco que deve ser deletado possuir alguma referencia que impeça a exclusão, por isso um BadRequest que poderia até ir como uma mensagem explicativa para o frontend. No caso do error 500, eu considero uma exceção que não foi tratada.

Robson, bom dia.

Como estou usando o RESTEasy não vou adicionar mais essa dependência do Spring, o que provavelmente causaria problemas. Em alguns fóruns percebi que esse problema(do DELETE) é comum e que realmente algumas implementações não preveem o DELETE com payload, você pode declarar mas ao consumir o serviço dará erro.

Ainda pesquisando descobri que poderia fazer um POST sem me sentir tão culpado, que existem situações que o negócio vai permitir essas situações.

…/blocos/cancelados
{
“bloco”:“12”,
“motivo”:“motivo cancelamento”
}

No meu caso interpretei a exclusão como uma inclusão na pasta de cancelados.

Obrigado pela resposta.

Neste caso não deveria ser PUT?

/blocos/cancelados é uma url conhecida, e PUT assim como DELETE é idempotente, se você “exclui” o mesmo bloco duas vezes, não faz nenhuma diferença.

Eu uso POST quando a operação pode ser mapeada pra algum algoritmo no servidor.

Correto. E foi o que eu entendi por falha na persistencia ou falha pra logar o motivo.

Não tem razão pra retornar BadRequest quando a exclusão não pode ser feita por uma questão interna do sistema. BadRequest é um erro que está relacionado à forma como o request foi construído pelo cliente.

Se não pode excluir um recurso por questão lógica e de consistência de dados, então obviamente sua aplicação não deve oferecer essa opção na GUI, e se alguém tentar fazer isso forçando o caminho, o correto seria retornar Forbidden (403).

pfk66,

O PUT pelo que já li a respeito deve ser usado quando você atualiza alguma informação do objeto e o resource não é alterado, exemplo:

[PUT] …/bloco/12
{
“nome”:“bloco de teste”
}

O bloco continuará disponível no caminho anterior, mas com as atualizações feitas.

O ideal para minha API seria:

[DELETE] …/bloco/12
{
“motivo”:“Bloco mal gerado”
}

Mas o RESTEasy não me permitiu, por particularidades da implementação dos caras.

Como solução resolvi fazer uma interpretação diferente do cenário e adicionei o bloco ao resource dos cancelados, para inclusões e adições o método utilizado é o POST.

Sim, pensando com mais cuidado acredito que o 403, seria mais apropriado. Muito Obrigado pfk66.

att,

POST não é idempotente. Isso significa que o servidor vai criar uma nova URL a cada bloco excluido, e mandar o cliente pra lá.
Mas o que você quer é apenas incluir todos os excluídos em uma url já conhecida pelo cliente.

O legal dessa dúvida, que está gerando uma discussão legal sobre HttpVerbs, HttpResponses e agora Idempotence, me desculpe pela visão simplificada ou caso eu esteja errado.Mas o put e o delete são considerados idempotentes, porém o conceito idempotente, não se resume ao fato de uma mesma request ser repetida “n” vezes e produzir o mesmo resultado? No caso do delete, a primeira request eu retornaria 200 ou 204, ao repetir a request eu teria um 404. Isso não fere o principio do idempotente?

att,

Idempotente se refere ao request e como ele altera o estado do sistema, e não a resposta que você recebe.

Pode chegar 1 DELETE ou vários ao mesmo tempo, você sabe que o resultado produzido no sistema é o mesmo, ainda que alguns clientes recebam respostas diferentes.

1 curtida