Ao projetar uma interface RESTful, a semântica dos tipos de solicitação é considerada vital para o design.
- GET - Coleta de lista ou elemento de recuperação
- PUT - Substituir coleção ou elemento
- POST - Criar coleção ou elemento
- DELETE - Bem, erm, exclua coleção ou elemento
No entanto, isso não parece abranger o conceito de "pesquisa".
Por exemplo, ao projetar um conjunto de serviços da web que suportam um site de Pesquisa de emprego, você pode ter os seguintes requisitos:
- Obter anúncio de emprego individual
- GET para
domain/Job/{id}/
- GET para
- Criar anúncio de emprego
- POST para
domain/Job/
- POST para
- Atualizar anúncio de emprego
- COLOQUE para
domain/Job/
- COLOQUE para
- Excluir anúncio de trabalho
- DELETE para
domain/Job/
- DELETE para
"Obter todos os trabalhos" também é simples:
- GET para
domain/Jobs/
No entanto, como a "procura" de emprego se enquadra nessa estrutura?
Você pode afirmar que é uma variação da "coleção de listas" e implementar como:
- GET para
domain/Jobs/
No entanto, as pesquisas podem ser complexas e é totalmente possível produzir uma pesquisa que gere uma cadeia GET longa. Ou seja, referenciando uma pergunta SO aqui , há problemas ao usar cadeias GET com mais de 2000 caracteres.
Um exemplo pode estar em uma pesquisa facetada - continuando o exemplo de "trabalho".
Posso permitir a pesquisa em facetas - "Tecnologia", "Cargo", "Disciplina", além de palavras-chave de texto livre, idade do trabalho, localização e salário.
Com uma interface de usuário fluida e um grande número de tecnologias e cargos, é possível que uma pesquisa possa abranger um grande número de opções de facetas.
Ajustar este exemplo para currículos, em vez de trabalhos, traz ainda mais facetas, e você pode facilmente imaginar uma pesquisa com centenas de facetas selecionadas ou apenas 40 facetas, cada uma com 50 caracteres (por exemplo, títulos de trabalho, nomes de universidades, Nomes do empregador).
Nessa situação, pode ser desejável mover um PUT ou POST para garantir que os dados da pesquisa sejam enviados corretamente. Por exemplo:
- POST para
domain/Jobs/
Mas semanticamente, isso é uma instrução para criar uma coleção.
Você também pode dizer que expressará isso como a criação de uma pesquisa:
- POST para
domain/Jobs/Search/
ou (como sugerido por burninggramma abaixo)
- POST para
domain/JobSearch/
Semanticamente, pode parecer fazer sentido, mas na verdade você não está criando nada, está fazendo um pedido de dados.
Portanto, semanticamente é um GET , mas o GET não é garantido para suportar o que você precisa.
Portanto, a pergunta é: tentando manter o mais fiel possível ao design RESTful, enquanto asseguro que estou mantendo dentro das limitações do HTTP, qual é o design mais apropriado para uma pesquisa?
fonte
domain/Jobs?keyword={keyword}
. Isso funciona bem para mim :) Minha esperança é que oSEARCH
verbo se torne um padrão. programmers.stackexchange.com/questions/233158/...Respostas:
Você não deve esquecer que as solicitações GET têm algumas vantagens superiores a outras soluções:
1) Os pedidos GET podem ser copiados da barra de URL, são digeridos pelos mecanismos de pesquisa, são "amigáveis". Onde "amigável" significa que normalmente uma solicitação GET não deve modificar nada dentro do seu aplicativo (idempotente) . Este é o caso padrão para uma pesquisa.
2) Todos esses conceitos são muito importantes não apenas do usuário e do mecanismo de pesquisa, mas do ponto de vista arquitetural do design da API .
3) Se você criar uma solução alternativa com POST / PUT , terá problemas nos quais não está pensando no momento. Por exemplo, no caso de um navegador, navegue no botão voltar / atualizar página / histórico. Isso pode ser resolvido, é claro, mas isso será outra solução alternativa, depois outra e outra ...
Considerando tudo isso, meu conselho seria:
a) Você deve conseguir se encaixar dentro do seu GET usando uma estrutura inteligente de parâmetros . Em casos extremos, você pode até usar táticas como esta pesquisa no Google, onde eu defino muitos parâmetros, ainda é um URL super curto.
b) Crie outra entidade em seu aplicativo como o JobSearch . Supondo que você tenha tantas opções, é provável que você precise armazenar essas pesquisas e gerenciá-las, portanto, basta limpar o aplicativo. Você pode trabalhar com os objetos do JobSearch como uma entidade inteira, o que significa que você pode testá-lo / usá-lo com mais facilidade .
Pessoalmente, eu tentava lutar com todas as minhas garras para fazê-lo com a) e quando toda a esperança se perdia, eu rastejava de volta com lágrimas nos olhos para a opção b) .
fonte
domain/Jobs/Search/
, talvez comdomain/JobsSearch/
em vez disso, ou você quis dizer algo diferente? Você pode esclarecer?TL; DR: GET para filtragem, POST para pesquisa
Eu faço uma distinção entre filtrar os resultados da lista de uma coleção versus uma pesquisa complexa. O teste decisivo que eu uso é basicamente se eu precisar de mais do que filtrar (positivo, negativo ou intervalo) . Considero uma pesquisa mais complexa que exige POST.
Isso tende a ser reforçado quando se pensa no que será devolvido. Normalmente, só uso GET se um recurso tiver um ciclo de vida praticamente completo (PUT, DELETE, GET, coleção GET) . Normalmente, em uma coleção GET, estou retornando uma lista de URIs, que são os recursos REST que compõem essa coleção. Em uma consulta complexa, posso extrair vários recursos para construir a resposta (pense na junção SQL), para não enviar URIs, mas dados reais. O problema é que os dados não serão representados em um recurso, portanto, sempre terei que retornar dados. Parece-me um caso claro de exigir um POST.
-
Já faz um tempo e minha postagem original era um pouco desleixada, então pensei em atualizar.
GET é a opção intuitiva para retornar a maioria dos tipos de dados, coleções de recursos REST, dados estruturados de um recurso e até cargas singulares (imagens, documentos, etc.).
POST é o método ideal para qualquer coisa que não se encaixe em GET, PUT, DELETE etc.
Nesse ponto, acho que pesquisas simples, a filtragem intuitivamente fazem sentido através do GET. Pesquisas complexas dependem da preferência pessoal, especialmente se você estiver lançando funções de agregação, correlações cruzadas (junções), reformadores de formatação, etc. ) costuma fazer mais sentido como um corpo de solicitação POST.
Também considero o aspecto da experiência do uso da API. Geralmente, quero tornar a maioria dos métodos o mais fácil de usar e intuitivo possível. Enviarei chamadas mais flexíveis (e, portanto, mais complexas) para POSTs e em um URI de recurso diferente, especialmente se for inconsistente com o comportamento de outros recursos REST na mesma API.
De qualquer forma, a consistência é provavelmente mais importante do que se você está pesquisando no GET ou no POST.
Espero que isto ajude.
fonte
GET /class?queryParams
. Da perspectiva de um usuário, a "classe" sempre foi uma coisa e você não precisou fazer junções estranhas ao SQL.No REST, a definição de recurso é muito ampla. É realmente como você deseja agrupar alguns dados.
Por exemplo, o principal URI do Google aponta para um recurso de coleta de "links para todos os sites da Internet". Os parâmetros de consulta restringem isso aos sites que você deseja ver.
(URI = identificador universal de recursos, do qual URL = localizador universal de recursos, onde o "http: //" familiar é o formato padrão para um URI. Portanto, o URL é um localizador, mas no REST é bom generalizar isso para um identificador de recurso As pessoas as usam de forma intercambiável.)
E então use POST, que é o verbo de acréscimo ou processo para adicionar novos itens a essa coleção:
Observe que é a mesma estrutura para o
job
objeto em cada caso. Um cliente pode OBTER uma coleção de trabalhos, usando parâmetros de consulta para restringir a pesquisa e, em seguida, usar o mesmo formato para um dos itens para POSTAR um novo trabalho. Ou pode levar um desses itens e PUT ao seu URI para atualizá-lo.Para cadeias de consulta realmente longas ou complicadas, a convenção torna aceitável enviá-las como solicitações POST. Agrupe os parâmetros de consulta como pares nome / valor ou objetos aninhados em uma estrutura JSON ou XML e envie-a no corpo da solicitação. Por exemplo, se sua consulta tiver aninhado dados em vez de vários pares de nome / valor. A especificação HTTP para POST a descreve como o verbo de acréscimo ou processo. (Se você quiser navegar em um navio de guerra por uma brecha no REST, use POST.)
Eu usaria isso como plano de contingência, no entanto.
O que você perde quando faz isso é: a) GET é nulipotente - ou seja, não muda nada - o POST não é. Portanto, se a chamada falhar, o middleware não tentará ou armazenará automaticamente automaticamente os resultados e 2) com os parâmetros de pesquisa no corpo, você não poderá mais recortar e colar o URI. Ou seja, o URI não é um identificador específico para a pesquisa que você deseja.
Para diferenciar entre "criar" e "pesquisar". Existem algumas opções que são consistentes com a prática REST:
Você pode fazer isso no URI adicionando algo ao nome da coleção, como procura de emprego em vez de empregos. Isso significa apenas que você está tratando a coleção de pesquisa como um recurso separado.
Como a semântica do POST é anexada ao processo OR, você pode identificar os corpos de pesquisa com a carga útil. Como {job: ...} vs. {search: ...}. Cabe à lógica do POST publicá-la ou processá-la adequadamente.
Essa é praticamente uma preferência de design / implementação. Eu não acho que exista uma convenção clara.
Assim, como você já expôs, a ideia é definir um recurso de coleção para
jobs
Pesquise com parâmetros de consulta GET + para restringir a pesquisa. Consultas de dados longas ou estruturadas vão para o corpo de um POST (possivelmente para uma coleção de pesquisa separada). Crie com POST para anexar à coleção. E atualize com PUT para um URI específico.
(FWIW, a convenção de estilo com URIs é usar todas as letras minúsculas com palavras separadas por hífens. Mas isso não significa que você precise fazer dessa maneira.)
(Além disso, devo dizer que, a partir da sua pergunta, é claro que você está muito longe neste caminho. Eu expliquei as coisas explicitamente apenas para alinhá-las, mas sua pergunta já havia abordado a maioria dos problemas semânticos neste Eu estava apenas ligando com alguma convenção e prática.)
fonte
route
realmente não podemos lidar com a escolha do processamento. Eu teria que dar uma olhada nisso ...Geralmente uso consultas OData, elas operam como uma chamada GET, mas permitem restringir as propriedades retornadas e filtrá-las.
Você usa tokens como
$select=
e,$filter=
portanto, terá um URI que se parece com isso:Você também pode fazer paginação usando
$skip
e$top
e ordenando.Para mais informações, consulte OData.org . Você não especificou qual idioma está usando, mas se for ASP.NET, a plataforma WebApi oferece suporte a consultas OData - para outros (PHP etc), provavelmente existem bibliotecas que você pode usar para convertê-las em consultas ao banco de dados.
fonte
JobsNearMeAddedInTheLast7Days
ou o que quer que encapsule a consulta que é muito longa / complexa para OData e a exponha apenas por meio de chamadas GET .Uma abordagem a considerar é tratar o conjunto de possíveis consultas como um recurso de coleta, por exemplo
/jobs/filters
.POST
solicitações para este recurso, com os parâmetros de consulta no corpo, vai criar um novo recurso ou identificar um filtro equivalente já existente e retornar uma URL contendo o seu ID:/jobs/filters/12345
.O id pode então ser usada em uma solicitação GET para trabalhos:
/jobs?filter=12345
. SubseqüenteGET
Solicitações no recurso de filtro retornarão a definição do filtro.Essa abordagem tem a vantagem de liberá-lo do formato do parâmetro de consulta para definição de filtro, potencialmente fornecendo a você mais poder para definir filtros complexos. As condições OR são um exemplo que eu acho difícil de realizar com as cadeias de consulta.
Uma desvantagem dessa abordagem é que você perde a legibilidade da URL (embora isso possa ser atenuante ao recuperar a definição por meio de uma
GET
solicitação para o recurso de filtro). Por esse motivo, convém também oferecer suporte ao mesmo ou a um subconjunto dos parâmetros de consulta no/jobs
recurso, assim como o suporte a um recurso de filtro. Isso pode ser usado para consultas mais curtas. Se este recurso for fornecido, a fim de manter cacheability entre os dois tipos de filtragem, ao usar parâmetros de consulta sobre o/jobs
recurso, a implementação deve criar internamente / reutilizar um recurso de filtro e retornar um302
ou303
status indicando a URL na forma de/jobs?filter=12345
.fonte
GET /jobs/37
e receber um resultado, alguém excluirá o recurso e, 2 segundos depois, a mesma solicitação retornará um 404. Da mesma forma, se vocêPOST /searches
e você forem redirecionados para um resultado de pesquisa (a pesquisa é criada e você recebe um 201 com Local do cabeçalho do recurso), 2 segundos depois, o resultado pode ser apagado da memória e precisa ser regenerado. Não há necessidade de armazenamento a longo prazo.Esta é uma resposta antiga, mas ainda posso contribuir um pouco para a discussão. Observei muitas vezes um mal-entendido de REST, RESTful e Arquitetura. O RESTful nunca menciona nada sobre NÃO criar pesquisa, não há nada no RESTful sobre arquitetura, é um conjunto de princípios ou critérios de design.
Para descrever uma Pesquisa de uma maneira melhor, precisamos falar sobre uma arquitetura em particular e a que melhor se encaixa é a Arquitetura Orientada a Recursos (ROA).
No RESTful, existem princípios para projetar, idempotent não significa que o resultado não pode ser alterado, como eu li em algumas respostas, significa que o resultado de uma solicitação independente não depende de quantas vezes é executado. Ele pode mudar, vamos imaginar que estou atualizando continuamente um banco de dados alimentando-o com alguns dados que são fornecidos por uma API RESTful. Executar o mesmo GET pode alterar o resultado, mas não depende de quantas vezes ele foi executado. Se eu sou capaz de congelar o mundo, significa que não há estado, transformação ou qualquer coisa dentro do serviço quando solicito o recurso que leva a um resultado diferente.
Em uma arquitetura orientada a recursos (vamos chamá-lo de ROA a partir de agora, por questões de brevidade), focamos no recurso que pode ser um monte de coisas:
O que o torna único em termos de recurso é a capacidade de adição, o que significa que ele possui apenas um URI
Dessa forma, a pesquisa se encaixa perfeitamente no RESTful, considerando o ROA . Temos que usar o GET porque estou assumindo que sua pesquisa é normal e não muda nada, por isso é idempotente (mesmo que retorne coisas diferentes, dependendo dos novos elementos adicionados). Há uma confusão aqui dessa maneira, porque eu poderia manter o RESTful e não o ROA, significa que eu poderia seguir um padrão que cria uma pesquisa e retornar coisas diferentes com os mesmos parâmetros, porque não estou usando o princípio de endereçamento do ROA. Como é isso? Bem, se você enviar os filtros de pesquisa no corpo ou no cabeçalho, o recurso não será ADDRESSABLE.
Você pode encontrar os princípios do que é exatamente e o URI no documento original do W3:
https://www.w3.org/DesignIssues/Axioms
Qualquer URL nesta arquitetura deve ser auto-descritivo. É necessário que você siga os princípios para tratar de tudo no URI, significa que você pode usar / (barra) para separar o que precisar ou os parâmetros de consulta. Sabemos que há limitações nisso, mas esse é o padrão da arquitetura.
Seguindo o padrão de ROA no RESTful, uma pesquisa não é mais do que qualquer outro recurso, a única diferença é que os recursos vêm de um cálculo em vez de uma relação direta com o próprio objeto. Com base no princípio, pude abordar e obter um serviço de cálculo aritmético simples com base no seguinte padrão:
http://myapi.com/sum/1/2
Onde soma, 1 e 2 podem ser modificados, mas o resultado da computação é único e é endereçável, toda vez que ligo com os mesmos parâmetros, obtenho o mesmo e nada muda no serviço. O recurso / soma / 1/2 e / substract / 5/4 aderem perfeitamente aos princípios.
fonte
GET está ok, se você tiver uma coleção estática que sempre retorne os mesmos resultados (representação) para um URI. Isso também implica que os dados que geram essas representações nunca são alterados. A fonte é um banco de dados somente leitura.
O fato de o GET retornar resultados diferentes para um e o mesmo URI viola a idempotência / segurança e o princípio CoolURI e, consequentemente, não é RESTful . É possível que verbos idempotentes gravem em um banco de dados, mas eles nunca devem afetar a representação.
Uma pesquisa comum começa com uma solicitação POST que retorna uma referência ao resultado. Ele gera o resultado (é novo e pode ser buscado com um GET subsequente). Esse resultado pode ser hierárquico (é possível obter mais referências com URIs que você pode obter), e pode reutilizar elementos de pesquisas anteriores, se fizer sentido para o aplicativo.
A propósito, eu sei que as pessoas fazem isso de maneira diferente. Você não precisa me explicar o quão conveniente pode ser violar o REST.
fonte