Executando verificação de segurança...
1

Como vocês criam rotas que "executam ações" nas APIs de vocês?

Pra começar, um breve contexto:

Já vi sistemas por aí, onde as alterações de dados (inclusive as "ações") são feitas por uma única rota que utiliza o método PUT (ou PATCH).

Acredito que isso acontece porque em vários cursos online, é demonstrada a criação de uma aplicação ‘CRUD’ com 5 rotas (o que é ok para fins didáticos).

Exemplo, considerando uma API consumida pelo frontend, de um sistema de chats de mensagens (tipo o Whaticket):

POST /chats → cria um novo chat
GET /chats → retorna a lista de chats
GET /chats/:id → retorna um chat específico
PUT /chats/:id → altera um chat específico
DELETE /chats/:id → remove um chat específico


Até aqui parece tudo certo, né?

Mas agora imagina que os chats tem esses 2 campos:

→ 'status': que pode ter os valores: pending, assigned (em andamento) e closed
→ 'userId': indicando o usuário que está atendendo o chat

E que existem 3 botões/ações no sistema:

→ ‘finalizar um chat’
→ ‘começar a atender um chat’
→ ‘transferir um chat’

Se for mantida apenas a rota 'PUT /chats/:id', começa a surgir a necessidade de alguns IFs e condicionais, que podem se tornar difíceis de ler, entender e manter.

Por exemplo, o backend precisaria identificar que se o status estiver sendo alterado, e o novo status for ‘closed’, o chat está sendo finalizado, e realizar o fluxo necessário (por exemplo, o envio de uma mensagem de despedida).

Ele também precisaria identificar que se o userId estiver sendo alterado, o chat está sendo transferido, e também realizar o fluxo necessário (por exemplo, voltar o status do chat para ‘pending’ até que o novo usuário comece a atendê-lo).

E com isso, teríamos uma rota que faz várias coisas, de forma implícita e não tão clara, tendo várias responsabilidades e condicionais no código.

Ok, mas qual seria a solução?

Para rotas que realizam ações específicas em determinado registro, é comum o mercado no geral utilizar POST e o nome da ação.

Exemplo:

POST /chats/:id/transfer
POST /chats/:id/close

Ou em APIs de pagamentos, é comum algo como:
POST /payments/:id/refund (para estornar um pagamento)
POST /subscriptions/:id/cancel (para cancelar uma assinatura recorrente)

Dessa forma, o código fica mais separado e fácil de ler, entender e manter, pois cada rota do backend realiza uma única ação.

E também fica mais claro para o frontend qual requisição a ser feita para cada ação, sem precisar saber/enviar detalhes específicos de cada campo.

Fiquem à vontade pra deixar a opinião de vocês sobre esse assunto :)

Carregando publicação patrocinada...
1

Concordo com quase tudo, só mudaria o final pra PUT (considerando que só esta atualizando o status do chat)
PUT /chats/:id/transfer
PUT /chats/:id/close
PUT /payments/:id/refund
PUT /subscriptions/:id/cancel

1

Boa Pedro! Eu conversei com outras pessoas sobre esse assunto, e também surgiu essa sugestão de usar o PUT, como também de usar o PATCH. Pra mim me parece um pouco estranho usar esses métodos sem enviar nenhum dado pra ser alterado/substituído. Uma pessoa até brincou, que devia existir o método ACTION hahah.

Uma informação que achei bem interessante pra refletir é que o PUT deve ser idempotente, logo ao ocorrer 2 requisições idênticas, a segunda não deveria causar uma operação diferente no registro. Mas é algo que poderia ocorrer com essas ações, com 2 requisições ocorreriam 2 estornos de um pagamento (considerando estorno de valores parciais).

Mas assim, vejo que não tem um super consenso quanto a isso, não sinto que as especificações do REST cobrem exatamente esse cenário, então acho válida sua opinião.

Por exemplo, a API da Recurly (líder global em API de assinaturas recorrentes) usa o PUT nessas rotas de ações, ao invés de POST, ex.: 'PUT /subscriptions/:id/cancel'.

Já o Stripe (referência em Developer Experience) usa o DELETE, mas usa 'POST /payouts/:id/cancel' pra cancelar um saque e 'POST /charges/:id/capture' pra capturar uma cobrança.