web-dev-qa-db-pt.com

REST Melhores práticas da API: onde colocar parâmetros?

Uma API REST pode ter parâmetros de pelo menos duas maneiras:

  1. Como parte do caminho da URL (ou seja, /api/resource/parametervalue)
  2. Como um argumento de consulta (ou seja, /api/resource?parameter=value)

Qual é a melhor prática aqui? Há alguma orientação geral quando usar 1 e quando usar 2?

Exemplo do mundo real: o Twitter usa parâmetros de consulta para especificar intervalos. (http://api.Twitter.com/1/statuses/home_timeline.json?since_id=12345&max_id=54321)

Seria considerado melhor design colocar esses parâmetros no caminho da URL?

348
Kalle Gustafsson

Se houver práticas recomendadas documentadas, ainda não as encontrei. No entanto, aqui estão algumas diretrizes que uso ao determinar onde colocar os parâmetros em um URL:

Parâmetros opcionais tendem a ser mais fáceis de colocar na cadeia de consulta.

Se você quiser retornar um erro 404 quando o valor do parâmetro não corresponder a um recurso existente, então eu tenderia para um parâmetro de segmento de caminho. por exemplo. /customer/232 onde 232 não é um ID de cliente válido.

Se, no entanto, você quiser retornar uma lista vazia, quando o parâmetro não for encontrado, sugiro usar parâmetros de string de consulta. por exemplo. /contacts?name=dave

Se um parâmetro afetar uma subárvore inteira do seu espaço de URI, use um segmento de caminho. por exemplo. um parâmetro de idioma /en/document/foo.txt versus /document/foo.txt?language=en

Eu prefiro identificadores exclusivos para estar em um segmento de caminho em vez de um parâmetro de consulta.

As regras oficiais para URIs são encontradas nesta especificação RFC aqui . Há também outra especificação RFC muito útil aqui que define regras para a parametrização de URIs.

254
Darrel Miller

Resposta tardia, mas adicionarei algumas informações adicionais ao que foi compartilhado, ou seja, que existem vários tipos de "parâmetros" para uma solicitação, e você deve levar isso em consideração.

  1. Localizadores - Por exemplo identificadores de recursos, como IDs ou ação/exibição
  2. Filtros - Por exemplo parâmetros que fornecem uma pesquisa, classificação ou redução do conjunto de resultados.
  3. Estado - por exemplo identificação de sessão, chaves de api, whatevs.
  4. Conteúdo - por exemplo dados a serem armazenados.

Agora vamos ver os diferentes lugares onde esses parâmetros podem ir.

  1. Solicitar cabeçalhos e cookies
  2. String de consulta de URL ("GET" vars)
  3. Caminhos de URL
  4. Cadeia de consulta de corpo/multiparte ("POST" vars)

Geralmente, você deseja que o estado seja definido em cabeçalhos ou cookies, dependendo do tipo de informação de estado. Acho que todos podemos concordar com isso. Use cabeçalhos http personalizados (X-My-Header) se você precisar.

Da mesma forma, o Conteúdo tem apenas um local para pertencer, que está no corpo da solicitação, seja como sequências de consulta ou como conteúdo http multipart e/ou JSON. Isso é consistente com o que você recebe do servidor quando ele envia conteúdo para você. Então você não deveria ser rude e fazer diferente.

Locadores como "id = 5" ou "ação = atualizar" ou "página = 2" faria sentido como um caminho de URL, como mysite.com/article/5/page=2, onde em parte você sabe o que cada parte deve significar (o básico, como artigo e 5 obviamente significa obter os dados do tipo article com id 5) e parâmetros adicionais são especificados como parte do URI. Eles podem estar na forma de page=2 ou page/2 se você souber que, após um determinado ponto no URI, as "pastas" são valores-chave pareados.

Os filtros sempre entram na string de consulta, porque enquanto eles fazem parte de encontrar os dados corretos, eles estão lá apenas para retornar um subconjunto ou uma modificação do que os localizadores retornam sozinhos. A pesquisa em mysite.com/article/?query=Obama (subconjunto) é um filtro e, portanto, é /article/5?order=backwards (modificação). Pense no que isso faz, não apenas no que é chamado!

Se "view" determina o formato de saída, então é um filtro (mysite.com/article/5?view=pdf) porque retorna uma modificação do recurso encontrado em vez de retornar em qual recurso nós queremos. Se, em vez disso, decidir qual parte específica do artigo podemos ver (mysite.com/article/5/view=summary), então é um localizador.

Lembre-se, estreitando um conjunto de recursos está filtrando. Localizar algo específico dentro de um recurso é localizar ... duh. A filtragem de subconjunto pode retornar qualquer número de resultados (até 0). A localização sempre encontrará essa instância específica de algo (se existir). A filtragem de modificação retornará os mesmos dados que o localizador, exceto modificados (se tal modificação for permitida).

Espero que isso tenha ajudado a dar às pessoas alguns momentos eureka se eles se perderam sobre onde colocar as coisas!

152
Tor Valamo

Depende de um design. Não há regras para URIs em REST sobre HTTP (o principal é que elas são exclusivas). Muitas vezes, trata-se da questão do gosto e da intuição ...

Eu tomo a seguinte abordagem:

  • url path-element: o recurso e seu elemento de caminho formam uma passagem de diretório e um sub-recurso (por exemplo,/items/{id},/users/items). Quando não tiver certeza, pergunte aos seus colegas, se eles acham que a travessia e eles pensam em "outro diretório", o caminho mais provável é a escolha certa
  • parâmetro de url: quando não há travessia realmente (os recursos de pesquisa com vários parâmetros de consulta são um exemplo muito bom para isso)
21
manuel aldana

IMO os parâmetros devem ser melhores como argumentos de consulta. A URL é usada para identificar o recurso, enquanto os parâmetros de consulta adicionados especificam qual parte do recurso você deseja, qualquer estado que o recurso deve ter, etc.

18
PeterWong

De acordo com o REST Implementation,

1) Variáveis ​​de caminho são usadas para a ação direta nos recursos, como um contato ou uma música ex ..
GET etc/api/resource/{songid} ou
GET etc/api/resource/{contactid} retornará os dados respectivos.

2) Consulta perms/argument são usados ​​para os recursos diretos como metadados de uma música ex .., GET/api/resource/{songid}? Metadata = gêneros retornará os dados de gênero para aquela música em particular .

17
Satish Bellapu

"Pack" e POST seus dados contra o "contexto" que o universo-recurso-localizador fornece, o que significa # 1 para o bem do localizador.

Mente as limitações com # 2. Eu prefiro os POSTs para # 1.

nota: as limitações são discutidas para

POST em Existe um tamanho máximo para o conteúdo do parâmetro POST?

GET in Existe um limite para o tamanho de um pedido GET? e Tamanho máximo dos parâmetros de URL em _GET

p.s. esses limites são baseados nos recursos do cliente (navegador) e no servidor (configuração).

16
dgm

De acordo com o padrão URI o caminho é para parâmetros hierárquicos e a consulta é para parâmetros não hierárquicos. Ofc. pode ser muito subjetivo o que é hierárquico para você.

Em situações onde vários URIs são atribuídos ao mesmo recurso, gosto de colocar os parâmetros - necessários para a identificação - no caminho e os parâmetros - necessários para construir a representação - na consulta. (Para mim, desta forma, é mais fácil de encaminhar.)

Por exemplo:

  • /users/123 e /users/123?fields="name, age"
  • /users e /users?name="John"&age=30

Para map reduzir eu gosto de usar as seguintes abordagens:

  • /users?name="John"&age=30
  • /users/name:John/age:30

Portanto, cabe a você (e ao seu roteador do lado do servidor) como você constrói seus URIs.

nota: Apenas para mencionar esses parâmetros são parâmetros de consulta. Então, o que você está realmente fazendo é definir uma linguagem de consulta simples. Por consultas complexas (que contêm operadores como e, ou, maior que, etc.), sugiro que você use uma linguagem de consulta já existente. As capacidades dos templates URI são muito limitadas ...

5
inf3rno

Como programador, muitas vezes no final do cliente, prefiro o argumento da consulta. Além disso, para mim, ele separa o caminho da URL dos parâmetros, adiciona clareza e oferece mais extensibilidade. Ele também permite que eu tenha uma lógica separada entre o URL/URI e o construtor de parâmetros.

Eu gosto do que manuel aldana disse sobre a outra opção se houver algum tipo de árvore envolvida. Eu posso ver partes específicas do usuário sendo trucadas assim.

4
Joe Plante

Aqui está a minha opinião.

Os params de consulta são usados ​​como metadados para uma solicitação. Eles agem como filtro ou modificador para uma chamada de recurso existente.

Exemplo:

/calendar/2014-08-08/events

deve dar eventos de calendário para esse dia.

Se você quiser eventos para uma categoria específica

/calendar/2014-08-08/events?category=appointments

ou se você precisar de eventos com mais de 30 minutos

/calendar/2014-08-08/events?duration=30

Um teste decisivo seria verificar se a solicitação ainda pode ser atendida sem parâmetros de consulta.

4
Jay

Não existem regras rígidas e rápidas, mas a regra prática de um ponto de vista puramente conceitual que eu gostaria de usar resumidamente pode ser resumida assim: um caminho de URI (por definição) representa um recurso e parâmetros de consulta são essencialmente modificadores nesse recurso . Até agora, isso provavelmente não ajuda ... Com uma API REST você tem os principais métodos de agir sobre um único recurso usando GET, PUT e DELETE. Portanto, se algo deve ser representado no caminho ou como um parâmetro pode ser reduzido para saber se esses métodos fazem sentido para a representação em questão. Você razoavelmente PUT alguma coisa nesse caminho e seria semanticamente correto fazê-lo? Você poderia, é claro, PUT algo em qualquer lugar e dobrar o back-end para lidar com isso, mas você deveria ser PUTing o que equivale a uma representação do recurso real e não a uma versão desnecessariamente contextualizada dele. Para coleções, o mesmo pode ser feito com POST. Se você quisesse adicionar a uma coleção em particular, o que seria um URL que faz sentido POST para.

Isso ainda deixa algumas áreas cinzentas, pois alguns caminhos podem apontar para o que equivale a filhos de recursos dos pais que é um tanto discricionário e dependente de seu uso. A linha dura que isso atrai é que qualquer tipo de representação transitiva deve ser feito usando um parâmetro de consulta, uma vez que não teria um recurso subjacente.

Em resposta ao exemplo do mundo real fornecido na pergunta original (API do Twitter), os parâmetros representam uma consulta transitiva que filtra o estado dos recursos (em vez de uma hierarquia). Nesse exemplo em particular, seria totalmente irracional acrescentar à coleção representada por essas restrições, e, além disso, essa consulta não poderia ser representada como um caminho que faria qualquer sentido nos termos de um gráfico de objeto.

A adoção desse tipo de perspectiva orientada a recursos pode facilmente mapear diretamente para o gráfico de objeto de seu modelo de domínio e direcionar a lógica de sua API para o ponto em que tudo funciona de maneira muito clara e autodecumentável, uma vez que se torna claro. O conceito também pode ser esclarecido com o afastamento de sistemas que usam roteamento de URL tradicional mapeado em um modelo de dados normalmente mal ajustado (por exemplo, um RDBMS). Apache Sling certamente seria um bom lugar para começar. O conceito de envio de objetos em um sistema como Zope também fornece um analógico mais claro.

4
Matt Whipple

Uma "dimensão" deste tópico foi deixada de fora, mas é muito importante: há momentos em que as "melhores práticas" precisam entrar em acordo com a plataforma que estamos implementando ou aumentando com as capacidades REST.

Exemplo prático:

Atualmente, muitas aplicações web implementam a arquitetura MVC (Model, View, Controller). Eles assumem que um determinado caminho padrão é fornecido, ainda mais quando esses aplicativos da Web vêm com uma opção "Ativar URLs de SEO".

Apenas para mencionar um aplicativo da Web bastante famoso: uma loja de comércio eletrônico da OpenCart. Quando o administrador ativa as "URLs de SEO", espera que essas URLs entrem em um formato MVC padrão como:

http://www.domain.tld/special-offers/list-all?limit=25

Onde

  • special-offers é o controlador MVC que processará o URL (mostrando a página de ofertas especiais)

  • list-all é a ação do controlador ou o nome da função a ser chamada. (*)

  • limite = 25 é uma opção, informando que 25 itens serão mostrados por página.

(*) list-all é um nome de função fictício que usei para maior clareza. Na realidade, o OpenCart e a maioria dos frameworks MVC têm uma função index implícita (e geralmente omitida na URL) padrão, que é chamada quando o usuário deseja que uma ação padrão seja executada. Então, o URL do mundo real seria:

http://www.domain.tld/special-offers?limit=25

Com uma aplicação agora bastante padrão ou estrutura frameworkd similar à acima, você freqüentemente obterá um servidor web que é otimizado para isso, que reescreve URLs para ele (o verdadeiro "URL não SEOed" seria: http://www.domain.tld/index.php?route=special-offers/list-all&limit=25).

Portanto, você, como desenvolvedor, precisa lidar com a infraestrutura existente e adaptar suas "melhores práticas", a menos que você seja o administrador do sistema, saiba exatamente como Ajustar uma configuração de reconfiguração do Apache/NGinx (o último pode ser desagradável!) E em.

Portanto, sua API REST geralmente seria muito melhor seguindo os padrões do aplicativo da Web de referência, tanto por sua consistência como facilidade/velocidade (e, portanto, economia de orçamento).

Para voltar ao exemplo prático acima, uma API REST consistente seria algo com URLs como:

http://www.domain.tld/api/special-offers-list?from=15&limit=25

ou (URLs não SEO)

http://www.domain.tld/index.php?route=api/special-offers-list?from=15&limit=25

com uma mistura de argumentos "caminhos formados" e argumentos "formados por consulta".

2
Dario Fumagalli

Eu geralmente tendem para # 2, como um argumento de consulta (ou seja,/api/resource? Parameter = value).

Uma terceira opção é realmente postar o parâmetro = valor no corpo.

Isso ocorre porque funciona melhor para recursos de vários parâmetros e é mais extensível para uso futuro.

Não importa qual você escolher, certifique-se de escolher apenas um, não misture e combine. Isso leva a uma API confusa.

2
NorthIsUp

Vejo muitas APIs REST que não lidam bem com os parâmetros. Um exemplo que surge frequentemente é quando o URI inclui informações pessoalmente identificáveis.

http://software.danielwatrous.com/design-principles-for-rest-apis/

Eu acho que uma questão corolário é quando um parâmetro não deve ser um parâmetro, mas deve ser movido para oHEADERouBODYdo pedido.

1
Daniel Watrous

É uma questão muito interessante.

Você pode usar ambos, não há nenhuma regra estrita sobre este assunto, mas usar variáveis ​​de caminho URI tem algumas vantagens:

  • Cache : A maioria dos serviços de cache da Web na Internet não faz cache da solicitação GET quando eles contêm parâmetros de consulta. Eles fazem isso porque há muitos sistemas RPC usando solicitações GET para alterar dados no servidor (falhar !! Obter deve ser um método seguro)

Mas se você usar variáveis ​​de caminho, todos esses serviços podem armazenar em cache suas solicitações GET.

  • Hierarquia : as variáveis ​​de caminho podem representar hierarquia:/City/Street/Place

Ele fornece ao usuário mais informações sobre a estrutura dos dados.

Mas se seus dados não tiverem nenhuma relação de hierarquia, você ainda poderá usar as variáveis ​​Path, usando vírgula ou ponto e vírgula:

/ Cidade/longitude, latitude

Como regra, use vírgula quando a ordem dos parâmetros for importante, use ponto-e-vírgula quando a ordenação não tiver importância:

/ IconGenerator/vermelho; azul; verde

Além desses motivos, há alguns casos em que é muito comum usar variáveis ​​de string de consulta:

  • Quando você precisa do navegador para colocar automaticamente variáveis ​​de formulário HTML no URI
  • Quando você está lidando com algoritmo. Por exemplo, o mecanismo do Google usa strings de consulta:

http: // www.google.com/search?q=rest

Resumindo, não há nenhum motivo forte para usar um desses métodos, mas sempre que possível, use variáveis ​​de URI.

0
jfcorugedo