É possível alterar parcialmente uma coleção com PUT ou DELETE?


21

Eu tenho uma coleção de produtos em um grupo de produtos, por exemplo:

product-groups/123/products
  1. Se eu precisar adicionar à coleção, posso aprovar apenas alguns produtos com PUT?

  2. Se eu precisar excluir alguns produtos da coleção, posso transmitir dados de filtro (uma matriz de IDs) com DELETE?

Qual é a melhor maneira de implementar a funcionalidade no espírito do ReST?

Editar: os itens são links para entidades separadas, basicamente IDs de produtos.


Os itens do grupo de produtos separam recursos gerenciados em outro lugar? Ou eles são apenas parte da coleção de grupos de produtos? Se separados, os produtos podem pertencer a vários grupos de produtos?
Martijn Pieters 22/03

2
talvez PATCH Esta especificação define o novo método HTTP / 1.1 [RFC2616], PATCH, que é usado para aplicar modificações parciais a um recurso.
Esailija 22/03

Um produto (ID) pode pertencer a vários grupos de produtos.
user151851

Existe uma maneira conhecida (melhor prática) de dizer como PATCH, ou seja, adicionar ou excluir produtos da coleção?
user151851

Respostas:


10

Em geral, você tem um ponto final que representa toda a coleção de x :

/products

Digamos, você deseja atualizar um único produto, faça um PUT para /products/{id}. Se você deseja atualizar parcialmente um único produto (não atualizando todos os campos), também pode usar um PATCH para /products/{id}. O mesmo vale para a exclusão de uma única entidade ( DELETE to /products/{id}).

Se você deseja direcionar um único recurso, qualifica-se através do caminho, qual recurso único , que deseja modificar.

A única ação que interrompe o esquema é a criação de um recurso. Ao criar um recurso, você direciona a coleção como um todo, diga POST para /products.

Dito isto, deve ficar claro que o destino das operações que afetam a coleção como um todo deve ir para o terminal de coleta apropriado.

Por exemplo, você deseja recuperar um subconjunto de produtos vermelho, solicita-o

GET para /products?colour=red.

Portanto, se você deseja excluir todos esses itens , você DELETE/products?colour=red . Ou, se você deseja excluir alguns dos produtos por meio de id, DELETE /products?id=1&id=2&id=3 .

E a criação em massa de recursos? POSTAR sua coleção [{...},{...},{...}]simplesmente para /products. O mesmo vale para PUT e PATCH .

Isso é realmente simples.

Para responder suas perguntas:

Se eu precisar adicionar à coleção, posso aprovar apenas alguns produtos com PUT?

Não é apenas OK, você é incentivado a fazer assim.

Se eu precisar excluir alguns produtos da coleção, posso transmitir dados de filtro (uma matriz de IDs) com DELETE?

Está tudo bem. Como Eneko Alonso escreveu, algumas vezes existem operações em massa encapsuladas por pontos de extremidade "controlador", ou seja, um POST é usado para acionar operações (complexas).


2
PUT é uma operação de substituição. Chamar PUT em um terminal de coleta com "alguns produtos" deve excluir (no caso do OP, excluir o relacionamento com) qualquer produto que não esteja incluído na lista de "alguns produtos". Embora possa ser usado para adicionar itens, ele também deve remover itens que não são (na minha opinião) o que o OP espera. Você deve revisar sua resposta à primeira pergunta em conformidade.
Claytond 22/0318

@claytond: Suponho que a resposta seja boa, desde que uma atualização parcial seja feita PATCHe uma substituição completa via PUT.
9000

4
@ 9000. É claro, mas a resposta atualmente diz "você é incentivado a ... adicionar à coleção ... [passando] apenas por alguns produtos com PUT". Isso certamente está incorreto. Encorajado ao POST. Capaz de COLOCAR ... mas apenas passando todos (não alguns) itens.
Claytond 22/03/19

5

Geralmente, os métodos REST têm a intenção de operar em uma única entidade / objeto (CRUD).

Existem várias opções:

  • Trate suas coleções como entidades e atualize-as via POST
  • Criar operações alternativas, não REST

O primeiro segue os padrões REST, mas pode ser caro, pois os objetos / entidades da coleção podem ser muito grandes (atualizar um grupo que possui milhares de produtos apenas para adicionar / remover um produto seria uma solicitação pesada).

A segunda opção é preferida por muitas APIs, como uma maneira de estender o REST além das operações CRUD.

Por exemplo:

GET product-groups/123/products (list all the products in the group)
POST product-groups/123/products/append (POST a list of new product ids to append to the group)
POST product-groups/123/products/remove (POST a list of product ids to remove from the group)

Muitas APIs sempre usam POST para essas operações estendidas, mas nada limita o uso de outros métodos http (além do limite de GET e DELETE para ter um corpo vazio)


Claro, existem alguns métodos para alcançar o objetivo. Qual é a melhor prática? Qual será mais à prova de futuro?
user151851

4
@ user151851: A conformidade total com REST (se houver) é um objetivo elevado. O esboço da abordagem aqui parece mais realista, na medida em que tenta empregar uma abordagem que está realmente sendo usada no "mundo real", tornando-o, em essência, um padrão de padrão. Isso é tão à prova de futuro quanto você conseguirá.
Robert Harvey

2
Não introduzimos verbos personalizados usando "anexar" e "excluir" no URL? Dessa forma, teremos que explicar como usar a API. Não devemos reutilizar o que temos, isto é, os métodos HTTP? Nesse caso, as ações são bem conhecidas.
user151851

7
Para qualquer outra pessoa que encontrar esta resposta: Está errado. Como o @ user151851 mencionado, isso introduz verbos no URL que é o mais não REST possível. No que diz respeito à pergunta real, não tenho uma ótima resposta, mas essa não é.
Umbrae 14/05

A "extensão" poderia ser mais orientada a recursos, tornando-a products/collectionretornando um 'envelope' de itens e o conteúdo do envelope alterado por meio de um PUT? Como "aqui está exatamente como eu quero que os itens da coleção sejam".
Luke Puplett

3

Apenas para obter respostas / comentários anteriores precisos.

De acordo com meu conhecimento, POST é o método para adicionar elementos únicos à coleção.

DELETE, por sua vez, é o método para excluir um único elemento da coleção. Ambos os cenários são perfeitamente RESTful.

No entanto, você deve usar o URI apropriado para se referir a um único elemento ou a coleção inteira.

Por exemplo, para adicionar elemento à coleção, você deve POST dados para o seguinte URI:

https://www.factory.net/products/

Para excluir um único produto da coleção, você pode usar o método DELETE enviando solicitação para algo como:

https://www.factory.net/products/108/

O método PATCH pode ser usado para atualizar alguns elementos da coleção. Por exemplo, quando você só precisa atualizar um campo em um elemento. COLOCAR uma representação completa de recursos para uma coleção muito grande pode ser uma operação muito cara.


2

Em princípio, todas as operações RESTful são válidas em uma coleção, mas certifique-se de entender como a semântica dos verbos se aplica a uma coleção:

  • PUT é uma substituição completa .

    • Se você COLOCAR em um singleton (por exemplo /item/{id}) e deixar de namefora, ele deve ser limpo ou definido como nulo ou algo semelhante.
    • Se você COLOCAR em uma coleção e não incluir um item, ele deverá ser removido dessa coleção.

    Enquanto um PUT pode ser usado para adicionar itens, você deve enviar "todos" itens. O envio de "alguns" itens deve resultar em remoções (presumo que não seja isso que o OP deseja).

  • DELETE é mais intuitivo. É válido excluir a coleção ou qualquer subconjunto filtrado. Somente os itens incluídos no filtro devem ser afetados.

  • PATCH também é válido. Em teoria, você deve fornecer uma lista de "operações". Por exemplo, você deve tecnicamente enviar algo como:

    [{ 
        "action": "update",
        "id": <id>,
        "value": {...}
    },{
        "action": "add",
        "value": {...}
    }, ...]
    

    Na prática, é mais comum ver uma API que aceita uma lista parcial de objetos em que cada item é processado usando uma lógica UPSERT (atualizar ou inserir).

  • Tecnicamente, o POST deve processar a entrada "de acordo com a semântica específica do próprio recurso".

    • Na prática, o POST é normalmente usado para operações de "criação".
    • No entanto, POST também é o verbo usado para chamadas não padrão. Embora haja um debate vigoroso sobre se os pontos de extremidade da ação são estritamente RESTful (eu lado o "não"), POST é o verbo apropriado se você estiver enviando uma solicitação para um ponto de extremidade {resource}/activate.

NOTA: Ao usar operações não-GET em coleções, considere cuidadosamente a definição de sucesso e falha. O REST não fornece uma boa maneira de comunicar sucesso parcial. Um bom padrão é supor que você executará a operação em uma transação com um critério de sucesso de tudo ou nada. Se não é isso que você deseja, provavelmente não deve interagir diretamente com a coleção.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.