Maneira RESTful de criar vários itens em uma solicitação

122

Estou trabalhando em um pequeno programa de servidor cliente para coletar pedidos. Eu quero fazer isso de uma "maneira REST (completa)".

O que eu quero fazer é:

Colete todas as linhas de pedido (produto e quantidade) e envie o pedido completo ao servidor

No momento, vejo duas opções para fazer isso:

  1. Envie cada linha de pedido para o servidor: POST qty e product_id

Na verdade, não quero fazer isso porque desejo limitar o número de solicitações ao servidor, portanto, a opção 2:

  1. Colete todas as linhas de pedidos e envie-as para o servidor de uma só vez.

Como devo implementar a opção 2? algumas idéias que tenho são: Quebra todas as linhas de pedido em um objeto JSON e enviá-lo ao servidor ou use uma matriz para postar as linhas de pedido.

É uma boa ideia ou boa prática implementar a opção 2 e, em caso afirmativo, como devo fazê-lo.

O que é uma boa prática?


fonte

Respostas:

74

Acredito que outra maneira correta de abordar isso seria criar outro recurso que represente sua coleção de recursos. Por exemplo, imagine que temos um ponto de extremidade /api/sheep/{id}e podemos POST /api/sheeppara criar um recurso de ovelha.

Agora, se queremos oferecer suporte à criação em massa, devemos considerar um novo recurso de rebanho em /api/flock(ou /api/<your-resource>-collectionse você não tiver um nome com um significado melhor). Lembre-se de que os recursos não precisam ser mapeados para o seu banco de dados ou modelos de aplicativos . Este é um equívoco comum.

Os recursos são uma representação de nível superior, não relacionada aos seus dados. Operar em um recurso pode ter efeitos colaterais significativos, como disparar um alerta para um usuário, atualizar outros dados relacionados, iniciar um processo de longa duração etc. Por exemplo, podemos mapear um sistema de arquivos ou mesmo o unixps comando como uma API REST.

Eu acho que é seguro assumir que operar um recurso também pode significar criar várias outras entidades como efeito colateral.

miguelcobain
fonte
Eu concordo com isso. Você deve abstrair o conceito de uma coleção de seu recurso e tratá-lo como um recurso. Isto lhe dará mais flexibilidade no futuro, bem como, quando você quer começar a fazer operações neste etc.
villy393
Essa é a abordagem correta. Isso não interrompe a solicitação de coleta POST. Desde então, é usado para postar uma única entidade. Enviar uma solicitação em massa com uma "entidade em massa separada" é a abordagem correta.
Classificador
2
Eu gosto de você ponto de extremidade API nomeando tanto com ovelhas e rebanhos! Com um certo grau de abstração, quase tem uma referência bíblica: "Tenho outras ovelhas que não são deste rebanho; devo trazê-las também, e elas ouvirão a minha voz; e se tornarão um rebanho com um pastor". João 10:16.
precisa saber é o seguinte
1
Curiosamente, as pessoas recomendam o uso da forma plural (da coleção) na URL quando você deseja criar um único recurso, assim: envie um POST para / api / books para criar um livro. Mas quando você deseja criar 100 livros (em uma única solicitação como json), em qual URL você publicaria a coleção de 100 livros? é aí que a inquietação começa.
code4kix
@ code4kix você pode usar /api/book-group, /api/book-collectionou algo semelhante.
Miguelcobain 17/10/19
46

Embora as operações em massa (por exemplo, criação de lote) sejam essenciais em muitos sistemas, elas não são formalmente tratadas pelo estilo de arquitetura RESTful.

Descobri que o POST de uma coleção, como você sugeriu, basicamente funciona, mas surgem problemas quando você precisa relatar falhas em resposta a essa solicitação. Esses problemas são piores quando várias falhas ocorrem por causas diferentes ou quando o servidor não suporta transações. Minha sugestão é que, se não houver problemas de desempenho, por exemplo, quando o provedor de serviços estiver na LAN (não na WAN) ou os dados forem relativamente pequenos, vale a pena enviar 100 solicitações POST para o servidor. Mantenha as coisas simples, comece com solicitações separadas e se você tiver um problema de desempenho, tente otimizar.

LiorH
fonte
3
Você mesmo encontrou uma solução para erros em caso de lote? Em uma conexão móvel, envie 100 solicitações de postagem para mostrar uma página como uma má ideia.
Thomas Ahle
Anexo os erros a uma matriz, direciono o usuário para uma página de erro 419 Conflict (e retorno esse erro ao cliente) e exibo a matriz de erros. Veja minha resposta abaixo para mais detalhes.
Eric Fuller
5
Isso não faz sentido. A pergunta é sobre o envio de um pedido para muitos itens, que, como muitos disseram, é possível apenas na entidade de uma solicitação POST. Como o servidor lida com isso é outra coisa completamente. Nesse caso, não vejo problema em criar um pedido, preencher o que é possível para esse pedido e também preencher detalhes que não puderam ser executados. Dessa forma, um usuário pode ver seu pedido e ver que todos os itens, exceto N, foram adicionados ao pedido, mas que alguns estavam em falta ou o sistema não sabia o que fazer. Outra opção amigável mais simples, mas menos do usuário é rejeitar tudo
thecoshman
2
@thecoshman muda muito em 3,25 anos. Você provavelmente deve postar uma resposta completamente formulada para a pergunta.
dlamblin
3
@dlamblin sim, eu provavelmente deve fazer um monte de coisas ... Eu vou chegar a ele em algum momento talvez ...
thecoshman
9

O Facebook explica como fazer isso: https://developers.facebook.com/docs/graph-api/making-multiple-requests

Solicitações em lote simples

A API em lote recebe uma matriz de solicitações HTTP lógicas representadas como matrizes JSON - cada solicitação possui um método (correspondente ao método HTTP GET / PUT / POST / DELETE etc.), um URL_relativo (a parte da URL após graph.facebook. com), matriz de cabeçalhos opcionais (correspondente aos cabeçalhos HTTP) e um corpo opcional (para solicitações POST e PUT). A API do Lote retorna uma matriz de respostas HTTP lógicas representadas como matrizes JSON - cada resposta possui um código de status, uma matriz de cabeçalhos opcional e um corpo opcional (que é uma sequência codificada em JSON).

rwitzel
fonte
1
Este é um link muito interessante, a solução proposta me parece útil. De qualquer forma, na StackOverflow, a resposta preferida é explicar o conceito da solução no corpo de uma resposta, pois os links podem mudar ou desaparecer.
Jan Vlcinsky
7
Essa é realmente a maneira do Facebook de fazer isso, não necessariamente RESTful, como o OP pediu
0cd
Eu acho que uma API do Lote (do Google, Facebook, etc - @PuneetArora) é mais útil ao agrupar várias solicitações não relacionadas. Criar uma solicitação que cria um item e agrupar todas essas solicitações para enviar uma coleção de itens é "insanidade" (Einstein). Basta criar uma solicitação que passe por uma coleção de itens.
Tfmontague #
8

Sua ideia parece válida para mim. A implementação é uma questão de sua preferência. Você pode usar JSON ou apenas parâmetros para isso (matriz "order_lines []") e fazer

POST /orders

Como você criará mais recursos ao mesmo tempo em uma única ação (ordem e suas linhas), é vital validar todos e cada um deles e salvá-los somente se todos forem aprovados na validação, ou seja. você deve fazer isso em uma transação.

Milan Novota
fonte
6

Eu acho que é melhor enviar solicitações separadas dentro de uma única conexão . Obviamente, seu servidor da web deve suportá-lo

zakovyrya
fonte
5

Ultimamente, tenho lutado com isso e aqui está o que estou trabalhando.

Se um POST que adicionar vários recursos for bem-sucedido, retorne 200 OK (eu estava considerando um 201, mas o usuário finalmente não pousa em um recurso que foi criado) junto com uma página que exibe todos os recursos adicionados, seja em leitura -só moda ou editável. Por exemplo, um usuário pode selecionar e POSTAR várias imagens para uma galeria usando um formulário que compreende apenas uma entrada de arquivo único. Se a solicitação POST for bem-sucedida, o usuário receberá um conjunto de formulários para cada representação de recurso de imagem criada, permitindo que você especifique mais detalhes sobre cada uma (nome, descrição, etc.).

Caso um ou mais recursos não sejam criados, o manipulador POST interrompe todo o processamento e anexa cada mensagem de erro individual a uma matriz. Em seguida, um 419 Conflict é retornado e o usuário é roteado para uma página de erro 419 Conflict que apresenta o conteúdo da matriz de erros, bem como um caminho de volta ao formulário enviado.

Eric Fuller
fonte
-2

Você não deseja enviar os cabeçalhos HTTP para 100 linhas de pedido. Você não deseja gerar mais solicitações além do necessário.

Envie o pedido inteiro em um objeto JSON para o servidor, para: servidor / pedido ou servidor / pedido / novo. Retorne algo que aponte para: server / order / order_id

Considere também usar CREATE PUT em vez de POST

Alegre
fonte
Suponho que ele mencione o método HTTP POST. Não existe o método CREATE HTTP.
Milan Novota
Não existe? Oh espera, não havia. Havia PUT em vez disso.
animador
22
Por que diabos você usaria o PUT para criar conteúdo? É exatamente para isso que serve o método HTTP POST.
thecoshman
8
Você usa PUT para criar recursos quando deseja que o cliente especifique o URI do recurso, como no webdav. Não concordo com o uso do PUT pelo autor, mas ele tem um papel na criação de recursos, embora esse local possa ter um escopo limitado.
precisa saber é o seguinte
2
Nota: O POST de uma entidade deve resultar na entidade se tornar subordinada do recurso endereçado na solicitação e não é idempotente. PUT substitui a entidade no endereço e é idempotente. A idempotência (palavra?) É uma expectativa importante para os consumidores.
Luke Puplett