Prática recomendada para chamada da API REST com muitos parâmetros

11

Eu tenho uma API REST com operações GETs que recebem uma lista (longa) de parâmetros (8 parâmetros, por exemplo). O objetivo desta operação é pesquisar e filtrar elementos.

Qual é a melhor prática para gerenciar esse cenário ?:

(1) Recebe uma lista de parâmetros ?:

public ResultType Get(int p1, int p2, string p3...) { ... }

(2) Ou recebe um objeto que encapsula esses parâmetros ?

public class MyClass
{
    public int X { get; set; }
    public int Y { get; set; }
    public string Z { get; set; }
}

public ResultType Get(MyClass parameter) { ... }

Pense em um cenário de comércio eletrônico no qual você deseja pesquisar e filtrar "produtos" por nome, descrição, categoria, marca, modelo, preço, etc ...

Jose Alonso Monge
fonte
1
A posição é menor de um identificador do que o nome adequado para um valor.
SD
Por que você tem 8 parâmetros? O que eles fazem? Existe alguma lógica de decisão envolvida (e é uma bagunça)? Você pode dividir essa API / método em vários métodos que usam 3 ou 4 parâmetros?
Filip Milovanović
1
8 parâmetros é apenas um exemplo. Minha operação Get é um método de "pesquisa". Pense em um cenário de comércio eletrônico no qual você deseja pesquisar e filtrar "produtos" por nome, descrição, categoria, marca, modelo, preço, etc ... Eu editei a pergunta para adicionar contexto
Jose Alonso Monge

Respostas:

10

Eu tenho uma API REST com operações GETs que recebem uma lista (longa) de> parâmetros. Qual é a melhor prática para gerenciar esse cenário?

AFAIK, não há boas práticas firmemente estabelecidas (desculpe). No entanto, pode-se fazer algumas recomendações:

  • Tente evitar o usoPOST (em vez de GET) se a solicitação for segura (ou seja, livre de efeitos colaterais, em particular a não modificação de dados). Se os parâmetros forem muito grandes, talvez você precise usar POSTpara contornar as limitações de comprimento, mas geralmente isso não é um problema (a maioria dos softwares suporta URLs bastante longos), e solicitações seguras devem ser usadas GETpara permitir otimizações, como cache e pré-busca.

  • Se você usar GET, deverá enviar seus parâmetros como parâmetros de URL 1) . Nessa situação, a solução natural e comum é usar uma lista de parâmetros , é o que eu recomendaria. Sim, a lista será longa, mas a API REST é (provavelmente) destinada ao uso programático, portanto, não vejo problema nisso. Os usuários da API são livres para encapsular os parâmetros em um objeto dentro de seu próprio código.

  • Tecnicamente, você também pode colocar um objeto em um parâmetro de URL (como JSON, XML ou o que for), mas isso é incomum, portanto, eu o evitaria se possível.

1) Estritamente falando, você pode usar um corpo com uma GETsolicitação, mas isso é incomum e geralmente não é recomendado; veja, por exemplo, HTTP GET com corpo da solicitação .


Por fim, assim como nos métodos no código-fonte que possuem longas listas de parâmetros, convém considerar se a API REST precisa de uma refatoração. Assim como no código-fonte, uma lista tão longa de parâmetros indica que o terminal da API está fazendo muitas coisas diferentes. Talvez faça sentido dividi-lo ou fornecer configurações padrão? Mas essa é uma pergunta diferente ...

sleske
fonte
Tecnicamente, você também pode enviar um corpo com um GET embora incomum
Ewan
Além disso, você tem certeza que idempotent média, eu diria 'cacheable' GetTodaysDayName () pode ser considerado idempotent, mas você não gostaria de cache-lo
Ewan
Vamos começar a batalha GET vs POST !!!! :)
Ewan
@ Ewan: Quanto ao cache do GetTodaysDayName: supondo que você precise do nome de hoje dez vezes por segundo e não se preocupe em usar o dia errado por alguns segundos, provavelmente deseja armazená-lo em cache. Ainda assim, usei erroneamente "idempotente", o que eu tinha em mente era "seguro" (= não modificando). Editado.
sleske
1
As batalhas construtivas do @Ewan, nas quais os "oponentes" enriquecem a resposta um do outro, são bem-vindas. Obrigado a vocês dois por uma visão geral muito abrangente de todas as opções!
Christophe
3

A melhor prática é POSTAR os parâmetros como um objeto.

Isso evita o limite de tamanho da URL e outros problemas com as strings de consulta. Se você enviar vários parâmetros em JSON, um objeto é a maneira padrão de fazê-lo; portanto, desserializar para um faz sentido.

Você pode evitar a criação de objetos 'Solicitação' aleatórios que são usados ​​apenas em seus Controladores desserializando para um objeto dinâmico, se desejar; embora transmitir para os tipos certos posteriormente possa ser igualmente confuso.

Antigamente, você poderia ter vários parâmetros em sua ação do controlador vinculados automaticamente aos campos de um objeto JSON de entrada. Mas isso não funciona mais imediatamente no núcleo .net.

Embora exista isso, que eu poderia ser tentado a tentar

https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/application-model?view=aspnetcore-2.1#application-model-usage-in-webapicompatshim

Edit: Vou adicionar alguns pontos no uso de GET

  • Armazenamento em cache: o GET será armazenado em cache por clientes que obedecem à especificação HTTP. Mas a especificação foi projetada para acelerar o carregamento de páginas da web. O cache é útil se o resultado da API tiver os mesmos requisitos de cache que uma página da Web, mas inútil se não tiver. Você pode adicionar seu próprio cache de respostas POST no cliente, se necessário.

  • Tamanho do URL: esse é principalmente um problema quando você está enviando uma matriz. Obviamente, uma matriz pode facilmente ficar muito longa e os nomes dos parâmetros da string de consulta serão repetidos para cada item. No entanto, mesmo se você estiver enviando apenas uma sequência, tecnicamente essa sequência poderá ser muito, muito longa.

  • Log: Por padrão, muitos servidores web registram toda a cadeia de caracteres da consulta. Frequentemente, você não deseja que os dados dos parâmetros terminem em logs de texto sem formatação.

  • GET with body: Essa parece ser a resposta perfeita, satisfazendo os puristas do REST e, ao mesmo tempo, permitindo uma boa estrutura de dados, mas é incomum e desaprovado, um POST é a maneira padrão de enviar um corpo.

Ewan
fonte
2
Eu não acho que isso seja uma boa prática. Em particular, se a solicitação for idempotente, é uma prática recomendada usar GETe não PUT(para armazenamento em cache, entre outras coisas). Atualmente, os limites de tamanho de URL são muito grandes, portanto não necessariamente um problema.
sleske
@ sleske Se você acha que GET é melhor, escreva uma resposta sobre o porquê. Cordas z pode ser 4Mb tempo embora
Ewan
na verdade apenas pesquisando e o comprimento da corda json max parece incerto
Ewan
Dado o contexto, não há necessidade de ter os parâmetros de solicitação que não estão em seus logs - a menos que você não queira fazer análises sobre o que as pessoas procuravam em sua página;) GETfaz total sentido de duas perspectivas: a) análises eb) a o usuário pode armazenar a consulta para mais tarde ou compartilhá-la.
Thomas Junk
@ThomasJunk a que contexto você se refere? a string é chamada 'z', pode haver literalmente qualquer coisa nela. o que é a multa de R $ 20 milhões do GDPR?
Ewan