Na API em que estou trabalhando, há uma operação de exclusão em massa que aceita uma matriz de IDs:
["1000", ..., "2000"]
Eu estava livre para implementar a operação de exclusão como quisesse, então decidi tornar tudo transacional: ou seja, se um único ID for inválido, toda a solicitação falhará. Vou chamar isso de modo estrito .
try{
savepoint = conn.setSavepoint();
for(id : IDs)
if( !deleteItem(id) ){
conn.rollback(savepoint);
sendHttp400AndBeDoneWithIt();
return;
}
conn.commit();
}
A alternativa (implementada em outro lugar em nosso pacote de software) é fazer o que podemos no back-end e relatar falhas em uma matriz. Essa parte do software lida com menos solicitações para que a resposta não acabe sendo uma matriz gigantesca ... em teoria.
Um bug recente ocorrendo em um servidor com poucos recursos me fez olhar para o código novamente e agora estou questionando minha decisão original - mas desta vez sou mais motivado pelas necessidades de negócios do que pelas melhores práticas. Se, por exemplo, falhar em toda a solicitação, o usuário terá que tentar novamente; se vários itens forem excluídos, o usuário poderá concluir a ação e solicitar ao administrador que faça o resto (enquanto eu trabalho na correção do bug) !). Este seria o modo permissivo .
Tentei procurar on-line por alguma orientação sobre o assunto, mas vim de mãos vazias. Então, venho até você: O que é mais esperado por operações em massa dessa natureza? Devo seguir rigorosamente mais ou devo ser mais permissivo?
Respostas:
Não há problema em fazer uma versão 'estrita' ou 'agradável' de um ponto de extremidade de exclusão, mas você precisa informar claramente ao usuário o que aconteceu.
Estamos fazendo uma ação de exclusão com este ponto de extremidade. Provável
DELETE /resource/bulk/
ou algo semelhante. Eu não sou exigente. O que importa aqui é que, independentemente de você decidir ser rigoroso ou agradável, você precisa informar exatamente o que aconteceu.Por exemplo, uma API com a qual trabalhei tinha um
DELETE /v1/student/
terminal que aceitava IDs em massa. Nós enviamos regularmente a solicitação durante o teste, obtíamos uma200
resposta e assumíamos que tudo estava bem, apenas para descobrir mais tarde que todos na lista estavam IN no banco de dados ainda (definido como inativo) ou na verdade não foram excluídos devido a um erro que atrapalhou chamadas futurasGET /v1/student
porque recuperamos dados que não estávamos esperando.A solução para isso veio em uma atualização posterior que adicionou um corpo à resposta com os IDs que não foram excluídos. Esta é - que eu saiba - um tipo de prática recomendada.
Resumindo, não importa o que você faça, certifique-se de fornecer uma maneira de informar ao usuário final o que está acontecendo e, possivelmente, por que está acontecendo. IE, se escolhermos um formato estrito, a resposta pode ser
400 - DELETE failed on ID 1221 not found
. Se escolhermos uma versão 'agradável', pode ser207 - {message:"failed, some ids not deleted", failedids:{1221, 23432, 1224}}
(desculpe minha má formatação json).Boa sorte!
fonte
207 Multi-Status
pode ser apropriado para que a resposta fracasso parcialDeve-se ser rigoroso e permissivo.
Geralmente, as cargas a granel são divididas em duas fases:
Durante a fase de validação, cada registro é analisado estritamente para garantir que atenda aos requisitos das especificações de dados. Pode-se inspecionar facilmente dezenas de milhares de registros em apenas alguns segundos. Os registros válidos são colocados em um novo arquivo a ser carregado, o (s) inválido (s) marcado e removido e geralmente colocado em um arquivo separado (pular arquivo). A notificação é então enviada nos registros que falharam na validação, para que possam ser inspecionados e diagnosticados para fins de solução de problemas.
Depois de validados, os dados são carregados. Geralmente, ele é carregado em lotes, se for grande o suficiente para evitar transações de execução longa ou se houver uma falha, será mais fácil recuperar. O tamanho do lote depende do tamanho do conjunto de dados. Se houver apenas alguns mil registros, um lote estará OK. Aqui você pode ser um pouco permissivo com falhas, mas pode-se definir um limite de lote com falha para interromper toda a operação. Talvez se [N] os lotes falharem, interrompa toda a operação (se o servidor estiver inativo ou algo semelhante). Normalmente, não há falhas neste momento porque os dados já foram validados, mas se houve devido a problemas no ambiente ou outros, basta recarregar os lotes que falharam. Isso facilita um pouco a recuperação.
fonte
Não há uma resposta canônica para isso. As necessidades e conseqüências para o usuário precisam ser examinadas e as compensações avaliadas. O OP forneceu algumas das informações necessárias, mas eis como devo proceder:
Pergunta 1 : 'Qual é a consequência para o usuário se uma exclusão individual falhar?'
A resposta deve orientar o restante do comportamento do design / implementado.
Se, como indicado pelo OP, simplesmente o usuário percebe a exceção e abre um registro de problema, mas não é afetado (os itens não excluídos não afetam as tarefas subseqüentes), então eu aceitaria uma notificação automática para você.
Se as exclusões com falha precisarem ser resolvidas antes que o usuário possa continuar, então é estritamente preferível.
Oferecer ao usuário a opção (por exemplo, essencialmente um sinalizador de ignorar falhas com o rigoroso ou o permissivo como padrão) pode ser a abordagem mais amigável.
Pergunta 2 : 'Haveria algum problema de coerência / consistência de dados se tarefas subsequentes forem executadas com itens não excluídos ainda no repositório de dados?'
Novamente, a resposta direcionaria o melhor design / comportamento. Sim -> Rigoroso, Não -> Permissivo, Talvez -> Rigoroso ou Selecionado pelo Usuário (particularmente se for possível confiar no usuário para determinar com precisão as conseqüências).
fonte
Eu acho que isso depende se você quer escalabilidade ou não. Se você não pretende ter muitos IDs, isso não deve importar muito. Se você pretende ter um milhão de IDs, ou melhor ainda, não tem certeza absoluta de que isso não aconteça, você pode gastar uma hora excluindo IDs apenas para redefinir completamente devido a 1 ID inválido.
fonte
Eu diria que um ponto importante aqui é o que significa que uma grande quantidade de coisas será excluída.
Esses IDs têm alguma relação lógica ou são apenas um agrupamento em lotes de conveniência / desempenho?
No caso de alguma maneira, mesmo que vagamente, conectada, eu aceitaria
strict
. Se for apenas um modo de lote (por exemplo, o usuário clica em "salvar" para seus últimos minutos de trabalho e somente então o lote é transmitido), eu usaria apermissive
versão.Como a outra resposta afirma: De qualquer forma, conte ao "usuário" exatamente o que aconteceu.
fonte