Estou procurando uma maneira razoável de representar pesquisas como URLs RESTful.
A configuração: eu tenho dois modelos, carros e garagens, onde os carros podem estar em garagens. Então, meus URLs se parecem com:
/car/xxxx
xxx == car id
returns car with given id
/garage/yyy
yyy = garage id
returns garage with given id
Um carro pode existir por si só (daí o / car) ou em uma garagem. Qual é a maneira correta de representar, digamos, todos os carros em uma determinada garagem? Algo como:
/garage/yyy/cars ?
Que tal a união de carros na garagem yyy e zzz?
Qual é o caminho certo para representar uma pesquisa de carros com determinados atributos? Diga: mostre-me todos os sedãs azuis com 4 portas:
/car/search?color=blue&type=sedan&doors=4
ou deveria ser / carros?
O uso de "pesquisa" parece inadequado por lá - qual é a melhor maneira / termo? Deveria ser apenas:
/cars/?color=blue&type=sedan&doors=4
Os parâmetros de pesquisa devem fazer parte do PATHINFO ou QUERYSTRING?
Em resumo, estou procurando orientações para o design de URL REST entre modelos e para pesquisa.
[Atualização] Gosto da resposta de Justin, mas ele não cobre o caso de pesquisa em vários campos:
/cars/color:blue/type:sedan/doors:4
ou algo assim. Como é que vamos
/cars/color/blue
para o caso de múltiplos campos?
/cars
e/car
não é semântico e, portanto, uma má ideia. Sempre use o plural quando houver mais de um item nessa categoria.Respostas:
Para a pesquisa, use cadeias de consulta. Isso é perfeitamente RESTful:
Uma vantagem para as cadeias de consulta regulares é que elas são padrão e amplamente compreendidas e que podem ser geradas a partir do form-get.
fonte
/cars?color=whatever
./cars?color=blue&type=sedan&doors=4/engines
não vai funcionar/cars?param=value
serve para filtragem simples na lista de carros e/cars/search?param=value
é para criar uma pesquisa (com ou sem persistência) em que o resultado pode conter pontuação, categorização, etc. Você também pode criar / excluir uma pesquisa nomeada como/cars/search/mysearch
. Veja isso: stackoverflow.com/a/18933902/1480391O design do URL bonito RESTful é sobre a exibição de um recurso com base em uma estrutura (estrutura semelhante a diretório, data: articles / 2005/5/13, objeto e seus atributos, etc.), a barra
/
indica a estrutura hierárquica, use o-id
lugar.Estrutura hierárquica
Eu pessoalmente preferiria:
Se um usuário remove a
/car-id
peça, ela traz acars
visualização - intuitiva. O usuário sabe exatamente onde está na árvore e para o que está olhando. Ele sabe desde o primeiro momento que garagens e carros estão relacionados./car-id
também denota que ele pertence junto ao contrário/car/id
.Procurando
A consulta de pesquisa está OK, pois existe apenas a sua preferência, o que deve ser levado em consideração. A parte engraçada vem ao ingressar nas pesquisas (veja abaixo).
Ou basicamente qualquer coisa que não seja uma barra, como explicado acima.
A fórmula:,
/cars[?;]color[=-:]blue[,;+&]
* embora eu não usasse o&
sinal, pois é irreconhecível no texto à primeira vista.Listas de opções
recursos possíveis?
Negar cadeias de pesquisa (!)
Para pesquisar carros, mas não em preto e vermelho :
?color=!black,!red
color:(!black,!red)
Pesquisas Cadastrado
Pesquisar vermelhos ou azuis ou pretas carros com 3 portas em id garagens 1..20 ou 101..103 ou 999 , mas não 5
/garage[id=1-20,101-103,999,!5]/cars[color=red,blue,black;doors=3]
Você pode então construir consultas de pesquisa mais complexas. (Veja a correspondência de atributo CSS3 para a ideia de correspondência de substrings. Por exemplo, pesquisando usuários que contenham "bar"
user*=bar
.)Conclusão
De qualquer forma, essa pode ser a parte mais importante para você, porque você pode fazer o que quiser, afinal, lembre-se de que o UEST RESTful representa uma estrutura que é facilmente compreendida
/directory/file
, como/collection/node/item
datas de diretório , datas/articles/{year}/{month}/{day}
e quando você omitir em qualquer um dos últimos segmentos, você sabe imediatamente o que recebe.Então .., todos esses caracteres são permitidos sem codificação :
a-zA-Z0-9_.-~
normalmente permitido tanto codificado quanto não, ambos os usos são equivalentes.
$-_.+!*'(),
;/?:@=&
pode ser usado sem codificação para a finalidade que eles representam, caso contrário, eles devem ser codificados.
inseguro:
<>"#%{}|\^~[]`
por que inseguro e por que deveria ser codificado: RFC 1738, consulte 2.2
Consulte também RFC 1738 # página-20 para obter mais classes de caracteres.
RFC 3986, ver 2.2.
Apesar do que eu disse anteriormente, aqui está uma distinção comum de delímetros, o que significa que alguns "são" mais importantes que outros.
:/?#[]@
!$&'()*+,;=
Mais leitura:
Hierarquia: consulte 2.3 , consulte 1.2.3
sintaxe do parâmetro do caminho da URL
Atributo CSS3 que corresponde a
IBM: Serviços da Web RESTful - Noções básicas
Nota: O RFC 1738 foi atualizado pelo RFC 3986
fonte
POST
. Além disso, outras idéias que você deu na sua resposta também são altamente apreciáveis. Muito obrigado!;
em oposição a&
é legibilidade? Porque se sim, acho que prefiro o&
delimitador mais comum ... certo? :) Obrigado!&
como delimitador, é conhecido apenas pelos desenvolvedores. Pais, avós e a população que não é educada em TI aceitam delimitadores, conforme usado no texto escrito comum.Embora ter os parâmetros no caminho tenha algumas vantagens, existem, na IMO, alguns fatores compensadores.
Nem todos os caracteres necessários para uma consulta de pesquisa são permitidos em um URL. A maioria dos caracteres de pontuação e Unicode precisaria ser codificada em URL como um parâmetro de sequência de caracteres de consulta. Estou lutando com o mesmo problema. Gostaria de usar o XPath na URL, mas nem toda a sintaxe do XPath é compatível com um caminho de URI. Portanto, para caminhos simples,
/cars/doors/driver/lock/combination
seria apropriado localizar ocombination
elemento ' ' no documento XML da porta do motorista. Mas/car/doors[id='driver' and lock/combination='1234']
não é tão amigável.Há uma diferença entre filtrar um recurso com base em um de seus atributos e especificar um recurso.
Por exemplo, desde
/cars/colors
retorna uma lista de todas as cores para todos os carros (o recurso retornado é uma coleção de objetos de cores)/cars/colors/red,blue,green
retornaria uma lista de objetos de cores vermelhos, azuis ou verdes, não uma coleção de carros.Para devolver carros, o caminho seria
/cars?color=red,blue,green
ou/cars/search?color=red,blue,green
Os parâmetros no caminho são mais difíceis de ler porque os pares nome / valor não são isolados do resto do caminho, que não são pares nome / valor.
Um último comentário. Prefiro
/garages/yyy/cars
(sempre plural) a/garage/yyy/cars
(talvez tenha sido um erro de digitação na resposta original) porque evita alterar o caminho entre o singular e o plural. Para palavras com 's' adicionados, a alteração não é tão ruim, mas mudar/person/yyy/friends
para/people/yyy
parece complicado.fonte
Para expandir a resposta de Peter - você pode fazer da Search um recurso de primeira classe:
O recurso de pesquisa teria campos para cores, modelo, status de garaged etc. e pode ser especificado em XML, JSON ou qualquer outro formato. Como o recurso Carro e garagem, você pode restringir o acesso às pesquisas com base na autenticação. Os usuários que executam frequentemente as mesmas pesquisas podem armazená-los em seus perfis para que não precisem ser recriados. Os URLs serão curtos o suficiente para que, em muitos casos, possam ser facilmente negociados por email. Essas pesquisas armazenadas podem ser a base de feeds RSS personalizados e assim por diante.
Existem muitas possibilidades de usar as pesquisas quando você as considera como recursos.
A ideia é explicada em mais detalhes neste Railscast .
fonte
A resposta de Justin provavelmente é o caminho a seguir, embora em alguns aplicativos possa fazer sentido considerar uma pesquisa específica como um recurso por si só, como se você deseja oferecer suporte a pesquisas salvas nomeadas:
ou
fonte
Eu uso duas abordagens para implementar pesquisas.
1) Caso mais simples, para consultar elementos associados e para navegação.
Isso significa que consulta carros com ID de garagem igual a 1.
Também é possível criar pesquisas mais complexas:
Carros em todas as garagens do FirstStreet que não são vermelhos (3ª página, 100 elementos por página).
2) Consultas complexas são consideradas recursos regulares criados e podem ser recuperados.
O corpo do POST para criação de pesquisa é o seguinte:
É baseado no Grails (critério DSL): http://grails.org/doc/2.4.3/ref/Domain%20Classes/createCriteria.html
fonte
Isso não é REST. Você não pode definir URIs para recursos dentro de sua API. A navegação de recursos deve ser orientada por hipertexto. Tudo bem se você deseja URIs bonitos e grandes quantidades de acoplamento, mas simplesmente não o chama REST, porque ele viola diretamente as restrições da arquitetura RESTful.
Veja este artigo pelo inventor do REST.
fonte
Embora eu goste da resposta de Justin, sinto que ela representa mais precisamente um filtro do que uma pesquisa. E se eu quiser saber sobre carros com nomes que começam com cam?
Na minha opinião, você pode incorporá-lo à maneira como lida com recursos específicos:
/ cars / cam *
Ou simplesmente adicioná-lo ao filtro:
/ cars / doors / 4 / name / cam * / colors / red, azul, verde
Pessoalmente, eu prefiro o último, porém não sou especialista em REST (tendo ouvido falar dele há apenas duas semanas ...)
fonte
/cars?name=cam*
O RESTful não recomenda o uso de verbos nas URLs / carros / pesquisa não é repousante. A maneira correta de filtrar / pesquisar / paginar suas APIs é através de Parâmetros de consulta. No entanto, pode haver casos em que você precisa quebrar a norma. Por exemplo, se você estiver pesquisando em vários recursos, precisará usar algo como / search? Q = query
Você pode acessar http://saipraveenblog.wordpress.com/2014/09/29/rest-api-best-practices/ para entender as práticas recomendadas para projetar APIs RESTful
fonte
Além disso, eu também sugeriria:
Aqui,
Search
é considerado como um recurso filho doCars
recurso.fonte
Existem muitas boas opções para o seu caso aqui. Ainda assim, você deve considerar o uso do corpo do POST.
A string de consulta é perfeita para o seu exemplo, mas se você tiver algo mais complicado, por exemplo, uma lista longa arbitrária de itens ou condicionais booleanos, convém definir a postagem como um documento que o cliente envia pelo POST.
Isso permite uma descrição mais flexível da pesquisa, além de evitar o limite de comprimento da URL do servidor.
fonte
Meu conselho seria este:
Editar:
Espero que isso lhe dê a idéia. Essencialmente, sua API Rest deve ser facilmente detectável e permitir que você navegue pelos seus dados. Outra vantagem do uso de URLs e não de cadeias de consulta é que você pode tirar proveito dos mecanismos de cache nativos existentes no servidor da Web para tráfego HTTP.
Aqui está um link para uma página que descreve os males das cadeias de consulta no REST: http://web.archive.org/web/20070815111413/http://rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful
Usei o cache do Google porque a página normal não estava funcionando para mim, eis também o link: http://rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful
fonte
/cars/colors/red,blue,green
e/cars/colors/green,blue,red
? O elemento path do URI deve ser hierárquico, e eu realmente não vejo isso aqui. Eu acho que essa é uma situação em que a string de consulta é a escolha mais apropriada.