Lembre-se de que tenho um entendimento rudimentar do REST. Digamos que eu tenho este URL:
http://api.animals.com/v1/dogs/1/
E agora, quero fazer o servidor fazer o cachorro latir. Somente o servidor sabe como fazer isso. Digamos que eu queira executá-lo em um trabalho CRON que faça o cachorro latir a cada 10 minutos pelo resto da eternidade. Como é essa chamada? Eu meio que quero fazer isso:
Solicitação de URL:
ACTION http://api.animals.com/v1/dogs/1/
No corpo da solicitação:
{"action":"bark"}
Antes de você ficar bravo comigo por criar meu próprio método HTTP, me ajude e me dê uma idéia melhor de como devo chamar um método do lado do servidor de uma maneira RESTful. :)
EDITAR PARA ESCLARECIMENTO
Mais alguns esclarecimentos sobre o que o método "casca" faz. Aqui estão algumas opções que podem resultar em chamadas de API de estrutura diferente:
- O latido apenas envia um email a dog.email e não registra nada.
- bark envia um email para dog.email e os incrementos dog.barkCount por 1.
- bark cria um novo registro "bark" com a gravação bark.timestamp quando a casca ocorreu. Também incrementa dog.barkCount em 1.
- O bark executa um comando do sistema para retirar a versão mais recente do código do cão do Github. Em seguida, ele envia uma mensagem de texto para o proprietário do cão, informando que o novo código do cão está em produção.
fonte
PATCH
pode ser apropriado. Eu explico o porquê no final da minha resposta .Respostas:
Por que apontar para um design RESTful?
Os princípios RESTful trazem os recursos que tornam os sites fáceis (para um usuário humano aleatório "navegá-los") no design da API de serviços da web , para que eles sejam fáceis de usar por um programador. REST não é bom porque é REST, é bom porque é bom. E é bom principalmente porque é simples .
A simplicidade do HTTP simples (sem envelopes SOAP e
POST
serviços sobrecarregados com URI único ), o que alguns podem chamar de "falta de recursos" , é na verdade sua maior força . Logo de cara, o HTTP pede que você tenha capacidade de endereçamento e ausência de estado : as duas decisões básicas de design que mantêm o HTTP escalável até os mega-sites de hoje (e mega-serviços).Mas o REST não é o marcador de prata: às vezes um estilo RPC ("Chamada de Procedimento Remoto" - como SOAP) pode ser apropriado e, outras vezes, outras necessidades têm precedência sobre as virtudes da Web. Isto é bom. O que realmente não gostamos é de complexidade desnecessária . Muitas vezes, um programador ou uma empresa traz serviços no estilo RPC para um trabalho que o HTTP antigo simples poderia suportar. O efeito é que o HTTP é reduzido a um protocolo de transporte para uma enorme carga XML que explica o que "realmente" está acontecendo (não o URI ou o método HTTP dá uma pista sobre isso). O serviço resultante é muito complexo, impossível de depurar e não funcionará, a menos que seus clientes tenham a configuração exata que o desenvolvedor pretendia.
Mesma forma que um código Java / C # pode ser não orientada a objetos, usando apenas HTTP não faz um design RESTful. Pode-se ficar com a pressa de pensar em seus serviços em termos de ações e métodos remotos que devem ser chamados. Não é de admirar que isso acabe principalmente em um serviço no estilo RPC (ou em um híbrido REST-RPC). O primeiro passo é pensar de forma diferente. Um design RESTful pode ser alcançado de várias maneiras, uma maneira é pensar em seu aplicativo em termos de recursos, não ações:
Vou dar exemplos abaixo. (Outro aspecto importante do REST é o uso do HATEOAS - não o escovo aqui, mas falo sobre isso rapidamente em outro post .)
Edições do primeiro desenho
Vamos dar uma olhada no design proposto:
Primeiro, não devemos considerar a criação de um novo verbo HTTP (
ACTION
). De um modo geral, isso é indesejável por vários motivos:ACTION
verbo existe?Agora vamos considerar o uso
POST
(discutirei o porquê abaixo, basta aceitar minha palavra agora):Isso pode ser bom ... mas somente se :
{"action":"bark"}
era um documento; e/v1/dogs/1/
era um URI de "processador de documentos" (semelhante à fábrica). Um "processador de documentos" é um URI no qual você simplesmente "joga as coisas" e "esquece" delas - o processador pode redirecioná-lo para um recurso recém-criado após a "execução". Por exemplo, o URI para postar mensagens em um serviço de intermediário de mensagens, que após a postagem o redirecionaria para um URI que mostra o status do processamento da mensagem.Não sei muito sobre o seu sistema, mas já aposto que os dois não são verdadeiros:
{"action":"bark"}
não é um documento , na verdade é o método que você está tentando invadir o serviço; e/v1/dogs/1/
URI representa um recurso "cão" (provavelmente o cão com eleid==1
) e não um processador de documentos.Então, tudo o que sabemos agora é que o design acima não é tão RESTful, mas o que é isso exatamente? O que há de tão ruim nisso? Basicamente, é ruim porque é um URI complexo com significados complexos. Você não pode deduzir nada disso. Como um programador saberia que um cachorro tem uma
bark
ação que pode ser secretamente infundida com uma açãoPOST
nele?Criando chamadas de API da sua pergunta
Então, vamos direto ao ponto e tentamos projetar esses latidos RESTfully pensando em termos de recursos . Permitam-me citar o livro Restful Web Services :
Seguindo a descrição acima, podemos ver que
bark
pode ser modelado como uma sub-fonte de adog
( uma vez que abark
está contida em um cachorro, ou seja, uma casca é "latida" por um cachorro).A partir desse raciocínio, já obtivemos:
POST
/barks
, sub-fonte de dog:,/v1/dogs/1/barks
representando umabark
"fábrica". Esse URI é único para cada cão (já que está abaixo/v1/dogs/{id}
).Agora, cada caso da sua lista tem um comportamento específico.
1. o latido apenas envia um e-mail para
dog.email
e não registra nada.Em primeiro lugar, latir (enviar um email) é uma tarefa síncrona ou assíncrona? Em segundo lugar, a
bark
solicitação requer algum documento (o e-mail, talvez) ou está vazio?1.1 casca envia um e-mail para
dog.email
e não registra nada (como uma tarefa síncrona)Este caso é simples. Uma chamada para o
barks
recurso de fábrica produz uma casca (um e-mail enviado) imediatamente e a resposta (se OK ou não) é dada imediatamente:Como ele registra (muda) nada,
200 OK
é suficiente. Isso mostra que tudo correu como esperado.1.2 casca envia um e-mail para
dog.email
e não registra nada (como uma tarefa assíncrona)Nesse caso, o cliente deve ter uma maneira de rastrear a
bark
tarefa. Abark
tarefa deve ser um recurso com seu próprio URI .:Dessa forma, cada um
bark
é rastreável. O cliente pode então emitir umGET
nobark
URI para saber seu estado atual. Talvez até use aDELETE
para cancelar.2. casca envia um e-mail para
dog.email
e depois incrementadog.barkCount
em 1Essa pode ser mais complicada, se você quiser que o cliente saiba que o
dog
recurso foi alterado:Nesse caso, a
location
intenção do cabeçalho é informar ao cliente que ele deve dar uma olhadadog
. Do HTTP RFC sobre303
:Se a tarefa for assíncrona,
bark
é necessário um sub-recurso, exatamente como a1.2
situação, e303
deve ser retornadoGET .../barks/Y
quando a tarefa estiver concluída.3. casca cria um novo "
bark
" registro com abark.timestamp
gravação quando a casca ocorreu. Também aumentadog.barkCount
em 1.Aqui,
bark
é criado devido à solicitação, portanto o status201 Created
é aplicado.Se a criação for assíncrona,
202 Accepted
será necessário um ( como o HTTP RFC diz ).O registro de data e hora salvo faz parte do
bark
recurso e pode ser recuperado com umGET
a ele. O cão atualizado também pode ser "documentado"GET dogs/X/barks/Y
.4. bark executa um comando do sistema para retirar a versão mais recente do código do cão do Github. Em seguida, ele envia uma mensagem de texto
dog.owner
informando que o novo código de cão está em produção.A redação deste é complicada, mas é praticamente uma tarefa assíncrona simples:
O cliente então emitia
GET
s para/v1/dogs/1/barks/a65h44
saber o estado atual (se o código foi extraído, o e-mail foi enviado ao proprietário e assim por diante). Sempre que o cão muda, a303
é aplicável.Empacotando
Citando Roy Fielding :
Nos exemplos acima,
POST
é projetado uniformemente. Isso fará o cachorro "bark
". Isso não é seguro (significando que a casca tem efeitos sobre os recursos), nem idempotente (cada solicitação produz uma novabark
), que se encaixaPOST
bem no verbo.Um programador saberia:
POST
abarks
rende abark
. Os códigos de status de resposta (também com o corpo da entidade e os cabeçalhos quando necessário) explicam o que mudou e como o cliente pode e deve proceder.Nota: As principais fontes usadas foram: livro " Restful Web Services ", o HTTP RFC e o blog de Roy Fielding .
Editar:
A pergunta e, portanto, a resposta mudaram bastante desde que foram criadas. A pergunta original perguntou sobre o design de um URI como:
Abaixo está a explicação de por que não é uma boa escolha:
Como os clientes dizem ao servidor O QUE FAZER com os dados são as informações do método .
Em que parte dos dados [o cliente deseja que o servidor] funcione estão as informações de escopo .
Como exemplo, use o URI do Google
http://www.google.com/search?q=DOG
. Lá, as informações do método sãoGET
e as informações do escopo são/search?q=DOG
.Longa história curta:
E a regra de ouro:
Você pode colocar a ação "latir" na URL (ou no corpo da entidade) e usar . Não tem problema, ele funciona e pode ser a maneira mais simples de fazer isso, mas isso não é RESTful .
POST
Para manter seu serviço realmente RESTful, pode ser necessário dar um passo atrás e pensar no que você realmente deseja fazer aqui (que efeitos isso terá sobre os recursos).
Não posso falar sobre suas necessidades comerciais específicas, mas deixe-me dar um exemplo: considere um serviço de pedidos RESTful em que os pedidos são em URIs
example.com/order/123
.Agora diga que queremos cancelar um pedido, como vamos fazer isso? Pode-se sentir tentado a pensar que é uma "ação" de "cancelamento " e designá-la como
POST example.com/order/123?do=cancel
.Isso não é RESTful, como falamos acima. Em vez disso, poderíamos
PUT
uma nova representação doorder
com umcanceled
elemento enviado paratrue
:E é isso. Se o pedido não puder ser cancelado, um código de status específico poderá ser retornado. (Um design de sub-fonte, como
POST /order/123/canceled
o corpo da entidadetrue
, também pode estar disponível por simplicidade.)No seu cenário específico, você pode tentar algo semelhante. Dessa forma, enquanto um cachorro está latindo, por exemplo, um
GET
at/v1/dogs/1/
pode incluir essa informação (por exemplo<barking>true</barking>
) . Ou ... se isso for muito complicado, afrouxe seu requisito RESTful e atenha-sePOST
.Atualizar:
Não quero tornar a resposta muito grande, mas demora um pouco para expor um algoritmo (uma ação ) como um conjunto de recursos. Em vez de pensar em termos de ações ( "faça uma pesquisa por locais no mapa" ), é preciso pensar em termos dos resultados dessa ação ( "a lista de locais no mapa que corresponde aos critérios de pesquisa" ).
Você pode voltar a esta etapa se achar que seu design não se encaixa na interface uniforme do HTTP.
As variáveis de consulta são informações de escopo , mas não denotam novos recursos (
/post?lang=en
é claramente o mesmo recurso que/post?lang=jp
, apenas uma representação diferente). Em vez disso, eles são usados para transmitir o estado do cliente (como?page=10
, para que o estado não seja mantido no servidor;?lang=en
também é um exemplo aqui) ou parâmetros de entrada para recursos algorítmicos (/search?q=dogs
,/dogs?code=1
). Mais uma vez, não recursos distintos.Propriedades dos métodos dos verbos HTTP:
Outro ponto claro que mostra
?action=something
no URI não é RESTful, são as propriedades dos verbos HTTP:GET
eHEAD
são seguros (e idempotentes);PUT
eDELETE
são apenas idempotentes;POST
não é nenhum.Segurança : Um
GET
ouHEAD
pedido é um pedido para ler alguns dados, não é um pedido para alterar qualquer estado do servidor. O cliente pode fazerGET
ouHEAD
solicitar 10 vezes e é o mesmo que fazê-lo uma vez ou nunca fazê-lo .Idempotência : uma operação idempotente em uma que tenha o mesmo efeito, seja aplicada uma ou mais de uma vez (em matemática, multiplicar por zero é idempotente). Se você
DELETE
usar um recurso uma vez, a exclusão novamente terá o mesmo efeito (o recursoGONE
já está ).POST
não é seguro nem idempotente. Fazer duasPOST
solicitações idênticas a um recurso 'factory' provavelmente resultará em dois recursos subordinados contendo as mesmas informações. Com sobrecarregado (método no URI ou no corpo da entidade)POST
, todas as apostas estão desativadas.Ambas as propriedades foram importantes para o sucesso do protocolo HTTP (em redes não confiáveis!): Quantas vezes você atualizou (
GET
) a página sem esperar até que ela esteja totalmente carregada?Criar uma ação e colocá-la na URL quebra claramente o contrato dos métodos HTTP. Mais uma vez, a tecnologia permite, você pode fazê-lo, mas esse não é o design RESTful.
fonte
POST
foi projetado para "fornecer um bloco de dados ... para um processo de manipulação de dados" . Parece que muitas pessoas distinguem recursos de ações, mas realmente ações são apenas um tipo de recurso.POST
"fornecer um bloco de dados ... a um processo de manipulação de dados", mas a diferença é realmente que, um bloco de dados , não um bloco de dados e o procedimento (ação, método, comando) a ser executado então. Isso estáPOST
sobrecarregando, e aPOST
sobrecarga é do estilo RPC, não RESTful.I respondeu anteriormente , mas esta resposta contradiz a minha resposta velho e segue uma estratégia muito diferente para chegar a uma solução. Ele mostra como a solicitação HTTP é criada a partir dos conceitos que definem REST e HTTP. Ele também usa em
PATCH
vez dePOST
ouPUT
.Ele percorre as restrições REST, os componentes do HTTP e, em seguida, uma solução possível.
DESCANSAR
O REST é um conjunto de restrições que devem ser aplicadas a um sistema hipermídia distribuído para torná-lo escalável. Mesmo para entendê-lo no contexto de controlar remotamente uma ação, é necessário pensar em controlar remotamente uma ação como parte de um sistema hipermídia distribuído - parte de um sistema para descobrir, visualizar e modificar informações interconectadas. Se isso é mais problemático do que vale, provavelmente não é bom tentar torná-lo RESTful. Se você deseja apenas uma GUI do tipo "painel de controle" no cliente que possa acionar ações no servidor via porta 80, provavelmente desejará uma interface RPC simples como JSON-RPC através de solicitações / respostas HTTP ou um WebSocket.
Mas o REST é uma maneira fascinante de pensar, e o exemplo da pergunta é fácil de modelar com uma interface RESTful, então vamos assumir o desafio de diversão e educação.
O REST é definido por quatro restrições de interface:
Você pergunta como pode definir uma interface, atendendo a essas restrições, através da qual um computador diz a outro para fazer um cachorro latir. Especificamente, você deseja que sua interface seja HTTP e não deseja descartar os recursos que tornam o HTTP RESTful quando usado como pretendido.
Vamos começar com a primeira restrição: identificação de recursos .
Então um cachorro é um recurso. Ele precisa ser identificado.
Você modela um cão usando um conjunto de identificadores e representações e dizendo que todos estão associados um ao outro em um determinado momento. Por enquanto, vamos usar o identificador "dog # 1". Isso nos leva à segunda e terceira restrições: representação de recursos e auto-descrição .
A seguir, é apresentada uma sequência de bytes que captura o estado pretendido do cão, ou seja, a representação que desejamos associar ao identificador "cão nº 1" (observe que ele representa apenas parte do estado, pois não considera o nome, a saúde do cão). ou até latidos passados):
Ele deve estar anexado aos metadados que o descrevem. Esses metadados podem ser úteis:
Por fim, vejamos a quarta restrição: HATEOAS .
Em uma interface RESTful, o cliente recebe uma representação de recurso para descobrir como deve receber ou enviar uma representação. Deve haver uma representação em algum lugar do aplicativo a partir da qual o cliente possa descobrir como receber ou enviar todas as representações que deve poder receber ou enviar, mesmo se seguir uma cadeia de representações para chegar a essas informações. Isso parece bastante simples:
O cliente solicita uma representação de um recurso identificado como a página inicial; em resposta, obtém uma representação que contém um identificador de todos os cães que o cliente pode querer. O cliente extrai um identificador e pergunta ao serviço como ele pode interagir com o cão identificado, e o serviço diz que o cliente pode enviar uma declaração em inglês descrevendo parte do estado pretendido do cão. Em seguida, o cliente envia essa declaração e recebe uma mensagem de sucesso ou uma mensagem de erro.
HTTP
O HTTP implementa restrições REST da seguinte maneira:
identificação de recurso : URI
representação de recursos : entidade-corpo
auto-descrição : método ou código de status, cabeçalhos e possivelmente partes do corpo da entidade (por exemplo, o URI de um esquema XML)
HATEOAS : hiperlinks
Você decidiu
http://api.animals.com/v1/dogs/1
como o URI. Vamos supor que o cliente tenha obtido isso de alguma página do site.Vamos usar esse corpo de entidade (o valor de
next
é um carimbo de data / hora; um valor de0
significa 'quando essa solicitação é recebida'):Agora precisamos de um método. PATCH se encaixa na descrição "parte do estado pretendido" que decidimos:
E alguns cabeçalhos:
Para indicar o idioma do corpo da entidade:
Content-Type: application/json
Para garantir que isso aconteça apenas uma vez:
If-Unmodified-Since: <date/time this was first sent>
E nós temos um pedido:
Em caso de sucesso, o cliente deve receber um
204
código de status em resposta ou a205
se a representação de/v1/dogs/1/
tiver sido alterada para refletir o novo cronograma de latidos.Em caso de falha, deve receber uma
403
e uma mensagem útil do motivo.Não é essencial para o REST que o serviço reflita o agendamento da casca em uma representação em resposta a
GET /v1/dogs/1/
, mas faria mais sentido se uma representação JSON incluísse isso:Trate o trabalho cron como um detalhe de implementação que o servidor oculta da interface. Essa é a beleza de uma interface genérica. O cliente não precisa saber o que o servidor faz nos bastidores; tudo o que importa é que o serviço entenda e responda às mudanças de estado solicitadas.
fonte
A maioria das pessoas usa o POST para esse fim. É apropriado para executar "qualquer operação insegura ou não-potencial, quando nenhum outro método HTTP parecer apropriado".
APIs como XMLRPC usam POST para acionar ações que podem executar código arbitrário. A "ação" está incluída nos dados do POST:
O RPC é um exemplo para mostrar que o POST é a escolha convencional de verbos HTTP para métodos do lado do servidor. Aqui estão os pensamentos de Roy Fielding sobre o POST - ele praticamente diz que é RESTful usar os métodos HTTP conforme especificado.
Observe que o próprio RPC não é muito RESTful porque não é orientado a recursos. Mas se você precisar de apatridia, armazenamento em cache ou camadas, não será difícil fazer as transformações apropriadas. Veja http://blog.perfectapi.com/2012/opinionated-rpc-apis-vs-restful-apis/ para um exemplo.
fonte
POST api.animals.com/v1/dogs1?action=bark
/RPC2
não faz nada para identificar um recurso - ele identifica uma tecnologia de servidor. Em vez disso, isso servemethodName
para tentar 'identificar' o 'recurso' - mas mesmo assim, ele não se beneficia da distinção substantivo / verbo; a única coisa parecida com "verbo" aqui émethodCall
. É como 'fazer recuperação do nome do estado' em vez de 'recuperar o nome do estado' - o último faz muito mais sentido.POST
é o método HTTP projetado paraMétodos do lado do servidor que lidam com ações não mapeadas por CRUD é o que Roy Fielding pretendia com o REST, então você é bom lá, e é por isso que
POST
foi feito para não ser idempotente.POST
manipulará a maioria dos lançamentos de dados nos métodos do servidor para processar as informações.Dito isso, em seu cenário de latidos de cães, se você deseja que uma latida no servidor seja realizada a cada 10 minutos, mas por algum motivo precisa que o gatilho se origine de um cliente,
PUT
serviria melhor ao objetivo, devido à sua idempotência. Bem, estritamente nesse cenário, não há risco aparente de várias solicitações POST, fazendo com que seu cão mie, mas de qualquer maneira esse é o objetivo dos dois métodos semelhantes. Minha resposta a uma pergunta SO semelhante pode ser útil para você.fonte
PUT
URL se refira ao que deve ser substituído pelo conteúdo do cliente e aPOST
URL se refira ao que deve processar o conteúdo do cliente da maneira que desejar.Se assumirmos que o latido é um recurso interno / dependente / secundário no qual o consumidor pode atuar, poderíamos dizer:
latas de cão número 1
retorna o último carimbo de data e hora da casca
não se aplica! então ignore.
fonte
/v1/dogs/1/bark
um recurso em si ePOST
uma descrição de como o estado interno desse recurso deve mudar. Acho que faz mais sentido considerar apenas/v1/dogs/1/
como um recurso e indicar no corpo da entidade que deve latir.Revisões anteriores de algumas respostas sugeriram o uso do RPC. Você não precisa procurar o RPC, pois é perfeitamente possível fazer o que deseja enquanto segue as restrições REST.
Em primeiro lugar, não coloque parâmetros de ação no URL. O URL define para o qual você está aplicando a ação e os parâmetros de consulta fazem parte do URL. Deve ser pensado inteiramente como um substantivo.
http://api.animals.com/v1/dogs/1/?action=bark
é um recurso diferente - um substantivo diferente - parahttp://api.animals.com/v1/dogs/1/
. [nb Asker removeu o?action=bark
URI da pergunta.] Por exemplo, comparehttp://api.animals.com/v1/dogs/?id=1
comhttp://api.animals.com/v1/dogs/?id=2
. Recursos diferentes, diferenciados apenas pela sequência de consultas. Portanto, a ação da sua solicitação, a menos que corresponda diretamente a um tipo de método existente sem corpo (TRACE, OPTIONS, HEAD, GET, DELETE etc.) deve ser definida no corpo da solicitação.Em seguida, decida se a ação é " idempotente ", o que significa que pode ser repetida sem efeitos adversos (consulte o próximo parágrafo para mais explicações). Por exemplo, definir um valor como true pode ser repetido se o cliente não tiver certeza de que o efeito desejado aconteceu. Eles enviam a solicitação novamente e o valor permanece verdadeiro. Adicionar 1 a um número não é idempotente. Se o cliente envia o comando Add1, não tem certeza de que funcionou e o envia novamente, o servidor adicionou um ou dois? Depois de determinar isso, você estará em uma posição melhor para escolher entre
PUT
ePOST
para o seu método.Idempotente significa que uma solicitação pode ser repetida sem alterar o resultado. Esses efeitos não incluem o log e outras atividades administrativas do servidor. Usando seus primeiro e segundo exemplos, o envio de dois e-mails para a mesma pessoa resulta em um estado diferente do envio de um e-mail (o destinatário tem dois na caixa de entrada, que podem ser considerados spam), então eu definitivamente usaria o POST para isso. . Se o barkCount no exemplo 2 tiver a intenção de ser visto por um usuário da sua API ou afetar algo visível ao cliente, também será algo que tornaria a solicitação não idempotente. Se for apenas para ser visualizado por você, ele conta como log do servidor e deve ser ignorado ao determinar a idempotência.
Por fim, determine se a ação que você deseja executar pode ter sucesso imediato ou não. O BarkDog é uma ação de conclusão rápida. RunMarathon não é. Se sua ação for lenta, considere retornar a
202 Accepted
, com um URL no corpo da resposta para que um usuário faça uma pesquisa para ver se a ação está concluída. Como alternativa, peça aos usuários POST para um URL da lista/marathons-in-progress/
e, quando a ação for concluída, redirecione-os do URL do ID em andamento para o/marathons-complete/
URL.Para os casos específicos # 1 e # 2, o servidor hospedaria uma fila e o cliente publicaria lotes de endereços nela. A ação não seria SendEmails, mas algo como AddToDispatchQueue. O servidor pode pesquisar a fila para verificar se há algum endereço de email aguardando e enviar emails, se houver. Em seguida, atualiza a fila para indicar que a ação pendente foi executada. Você teria outro URI mostrando ao cliente o estado atual da fila. Para evitar o envio duplo de e-mails, o servidor também pode manter um registro de quem enviou esse e-mail e verificar cada endereço para garantir que ele nunca envie dois para o mesmo endereço, mesmo se você POSTAR a mesma lista duas vezes para a fila.
Ao escolher um URI para qualquer coisa, tente pensar nele como resultado, não como uma ação. Por exemplo,
google.com/search?q=dogs
mostra os resultados de uma pesquisa para a palavra "cães". Não é necessário executar a pesquisa.Os casos 3 e 4 da sua lista também não são ações idempotentes. Você sugere que os diferentes efeitos sugeridos possam afetar o design da API. Nos quatro casos, eu usaria a mesma API, pois os quatro mudam o "estado mundial".
fonte
Veja minha nova resposta - ela contradiz essa e explica REST e HTTP com mais clareza e precisão.
Aqui está uma recomendação que é RESTful, mas certamente não é a única opção. Para começar a latir quando o serviço receber a solicitação:
token
é um número arbitrário que evita latidos redundantes, não importa quantas vezes essa solicitação seja enviada.next
indica a hora da próxima casca; um valor de0
significa 'ASAP'.Sempre que você
GET /v1/dogs/1/bark-schedule
, você deve obter algo parecido com isto, onde t é o tempo da última casca e u é t + 10 minutos:{"last": t, "next": u}
Eu recomendo que você use o mesmo URL para solicitar um latido que você usa para descobrir o estado atual do latido do cão. Não é essencial para o REST, mas enfatiza o ato de modificar o agendamento.
O código de status apropriado é provavelmente 205 . Estou imaginando um cliente que analisa o agendamento atual,
POST
s para o mesmo URL para alterá-lo e é instruído pelo serviço a dar uma segunda olhada no agendamento para provar que foi alterado.Explicação
DESCANSAR
Esqueça o HTTP por um momento. É essencial entender que um recurso é uma função que leva tempo como entrada e retorna um conjunto contendo identificadores e representações . Vamos simplificar isso para: um recurso é um conjunto R de identificadores e representações; R pode mudar - os membros podem ser adicionados, removidos ou modificados. (Apesar de ser mau, design instável para remover ou modificar identificadores.) Eu digo um identificador que é um elemento de R identifica R , e que uma representação que é um elemento de R representa R .
Digamos que R é um cachorro. Você identificou R como
/v1/dogs/1
. (Significado/v1/dogs/1
é membro de R .) Essa é apenas uma das muitas maneiras que você poderia identificar R . Você também pode identificar R como/v1/dogs/1/x-rays
e como/v1/rufus
.Como você representa R ? Talvez com uma fotografia. Talvez com um conjunto de raios-X. Ou talvez com uma indicação da data e hora em que R latiu pela última vez. Mas lembre-se de que essas são todas representações do mesmo recurso .
/v1/dogs/1/x-rays
é um identificador do mesmo recurso que é representado por uma resposta à pergunta "quando R latiu pela última vez?"HTTP
Várias representações de um recurso não serão muito úteis se você não puder se referir à que deseja. É por isso que o HTTP é útil: permite conectar identificadores a representações . Ou seja, é uma maneira do serviço receber uma URL e decidir qual representação servir ao cliente.
Pelo menos, é o que
GET
faz.PUT
é basicamente o inverso deGET
: você éPUT
uma representação r na URL se desejar queGET
solicitações futuras para essa URL retornem r , com algumas traduções possíveis, como JSON para HTML.POST
é uma maneira mais flexível de modificar uma representação. Pense em haver lógica de exibição e lógica de modificação que são equivalentes entre si - ambas correspondendo à mesma URL. Uma solicitação POST é uma solicitação para a lógica de modificação processar as informações e modificar quaisquer representações (não apenas a representação localizada pela mesma URL) que o serviço achar adequado. Preste atenção ao terceiro parágrafo após 9.6 PUT : você não está substituindo a coisa no URL por um novo conteúdo; você está solicitando que o URL processe algumas informações e responda de forma inteligente na forma de representações informativas.No nosso caso, solicitamos que a lógica de modificação em
/v1/dogs/1/bark-schedule
(que é a contrapartida da lógica de exibição que nos diz quando latiu pela última vez e quando latirá em seguida) processe nossas informações e modifique algumas representações de acordo. Em resposta aGET
s futuros , a lógica de exibição correspondente à mesma URL nos dirá que o cachorro está latindo agora como desejamos.Pense no trabalho cron como um detalhe de implementação. O HTTP trata da visualização e modificação de representações. A partir de agora, o serviço dirá ao cliente quando o cão latiu pela última vez e quando ele latirá a seguir. Do ponto de vista do serviço, isso é honesto, porque esses horários correspondem a tarefas cron planejadas e passadas.
fonte
REST é um padrão orientado a recursos, não é acionado por ação como seria um RPC.
Se você deseja que seu servidor descasque , procure idéias diferentes, como JSON-RPC ou comunicação por Websockets.
Toda tentativa de mantê-lo RESTful falhará na minha opinião: você pode emitir um
POST
com oaction
parâmetro, você não está criando novos recursos, mas como pode ter efeitos colaterais, fica mais seguro.fonte
POST
foi projetado para "fornecer um bloco de dados ... para um processo de manipulação de dados" . Parece que muitas pessoas distinguem recursos de ações, mas realmente ações são apenas um tipo de recurso. Chamar um recurso de ação em um servidor ainda é uma interface uniforme, armazenável em cache, modular e escalável. Também é sem estado, mas pode ser violado se o cliente for projetado para esperar uma resposta. Mas chamar um "método nulo" no servidor é o que Roy Fielding pretendia com o REST .