Noções básicas sobre REST: verbos, códigos de erro e autenticação

602

Estou procurando uma maneira de agrupar APIs em torno de funções padrão em meus aplicativos Web, bancos de dados e CMSs baseados em PHP.

Eu olhei em volta e encontrei vários frameworks "esqueletos". Além das respostas na minha pergunta, há o Tonic , um framework REST que eu gosto porque é muito leve.

Gosto mais do REST por sua simplicidade e gostaria de criar uma arquitetura de API baseada nela. Estou tentando entender os princípios básicos e ainda não o compreendi completamente. Portanto, uma série de perguntas.

1. Estou entendendo certo?

Digamos que eu tenha um recurso "usuários". Eu poderia configurar vários URIs assim:

/api/users     when called with GET, lists users
/api/users     when called with POST, creates user record
/api/users/1   when called with GET, shows user record
               when called with PUT, updates user record
               when called with DELETE, deletes user record

essa é uma representação correta de uma arquitetura RESTful até agora?

2. preciso de mais verbos

Criar, Atualizar e Excluir pode ser suficiente em teoria, mas na prática precisarei de muito mais verbos. Sei que são coisas que podem ser incorporadas a uma solicitação de atualização, mas são ações específicas que podem ter códigos de retorno específicos e eu não gostaria de jogá-las todas em uma única ação.

Alguns que vêm à mente no exemplo do usuário são:

activate_login
deactivate_login
change_password
add_credit

como eu expressaria ações como as de uma arquitetura de URL RESTful?

Meu instinto seria fazer uma chamada GET para um URL como

/api/users/1/activate_login 

e espere um código de status de volta.

Isso se desvia da idéia de usar verbos HTTP, no entanto. O que você acha?

3. Como retornar mensagens e códigos de erro

Uma grande parte da beleza do REST deriva do uso de métodos HTTP padrão. Em caso de erro, emito um cabeçalho com um código de status de erro 3xx, 4xx ou 5xx. Para uma descrição detalhada do erro, posso usar o corpo (certo?). Por enquanto, tudo bem. Mas qual seria a maneira de transmitir um código de erro proprietário mais detalhado na descrição do que deu errado (por exemplo, "falha ao conectar ao banco de dados" ou "login do banco de dados errado")? Se eu colocá-lo no corpo junto com a mensagem, tenho que analisá-lo posteriormente. Existe um cabeçalho padrão para esse tipo de coisa?

4. Como fazer autenticação

  • Como seria uma autenticação baseada em chave de API, seguindo os princípios REST?
  • Existem pontos fortes contra o uso de sessões ao autenticar um cliente REST, além de ser uma violação flagrante do princípio REST? :) (apenas brincando aqui, a autenticação baseada em sessão funcionaria bem com minha infraestrutura existente.)
Pekka
fonte
13
@ Daniel, obrigado pela edição. "Eu mais verbos" foi um trocadilho intencional, mas estou deixando como está, é mais fácil de ler agora. :)
Pekka
1
BTW, sobre a descrição do erro. Acabei colocando a descrição do erro no cabeçalho da resposta. Basta adicionar o cabeçalho chamado 'Descrição do erro'.
Andrii Muzychuk 10/03
Isso se parece mais com perguntas de segurança de aplicativos. A segurança do aplicativo não é o objetivo do REST.
Nazar Merza
@NazarMerza, como estão as questões de segurança 1., 2. e 3. de aplicativos?
Pekka

Respostas:

621

Percebi essa pergunta alguns dias depois, mas sinto que posso acrescentar algumas dicas. Espero que isso possa ser útil para o seu empreendimento RESTful.


Ponto 1: Estou entendendo certo?

Você entendeu certo. Essa é uma representação correta de uma arquitetura RESTful. Você pode encontrar a seguinte matriz da Wikipedia muito útil para definir seus substantivos e verbos:


Ao lidar com um URI de coleção, como:http://example.com/resources/

  • GET : Liste os membros da coleção, completos com seus URIs de membros para navegação adicional. Por exemplo, liste todos os carros à venda.

  • PUT : Significado definido como "substituir a coleção inteira por outra coleção".

  • POST : Crie uma nova entrada na coleção em que o ID é atribuído automaticamente pela coleção. O ID criado geralmente é incluído como parte dos dados retornados por esta operação.

  • DELETE : Significado definido como "excluir a coleção inteira".


Ao lidar com um URI de Membro, como:http://example.com/resources/7HOU57Y

  • GET : Recupere uma representação do membro endereçado da coleção, expresso em um tipo MIME apropriado.

  • PUT : Atualize o membro endereçado da coleção ou crie-o com o ID especificado.

  • POST : trata o membro endereçado como uma coleção por si só e cria um novo subordinado.

  • DELETE : Exclua o membro endereçado da coleção.


Ponto 2: preciso de mais verbos

Em geral, quando você pensa que precisa de mais verbos, pode realmente significar que seus recursos precisam ser identificados novamente. Lembre-se de que no REST você está sempre atuando em um recurso ou em uma coleção de recursos. O que você escolhe como recurso é muito importante para sua definição de API.

Ativar / desativar logon : se você estiver criando uma nova sessão, poderá considerar "a sessão" como o recurso. Para criar uma nova sessão, use POST para http://example.com/sessions/com as credenciais no corpo. Para expirar, use PUT ou DELETE (talvez dependendo da intenção de manter um histórico de sessão) para http://example.com/sessions/SESSION_ID.

Alterar senha: desta vez, o recurso é "o usuário". Você precisaria de um PUT http://example.com/users/USER_IDcom as senhas antigas e novas no corpo. Você está atuando no recurso "o usuário" e uma senha de alteração é simplesmente uma solicitação de atualização. É bastante semelhante à instrução UPDATE em um banco de dados relacional.

Meu instinto seria fazer uma chamada GET para um URL como /api/users/1/activate_login

Isso vai contra um princípio REST muito básico: o uso correto de verbos HTTP. Qualquer solicitação GET nunca deve causar nenhum efeito colateral.

Por exemplo, uma solicitação GET nunca deve criar uma sessão no banco de dados, retornar um cookie com um novo ID da sessão ou deixar qualquer resíduo no servidor. O verbo GET é como a instrução SELECT em um mecanismo de banco de dados. Lembre-se de que a resposta a qualquer solicitação com o verbo GET deve ser capaz de armazenar em cache quando solicitada com os mesmos parâmetros, assim como quando você solicita uma página da web estática.


Ponto 3: Como retornar mensagens e códigos de erro

Considere os códigos de status HTTP 4xx ou 5xx como categorias de erro. Você pode elaborar o erro no corpo.

Falha ao conectar-se ao banco de dados: / Logon incorreto no banco de dados : Em geral, você deve usar um erro 500 para esses tipos de erros. Este é um erro do lado do servidor. O cliente não fez nada de errado. 500 erros são normalmente considerados "repetíveis". ou seja, o cliente pode tentar novamente a mesma solicitação exata e esperar que seja bem-sucedido assim que os problemas do servidor forem resolvidos. Especifique os detalhes no corpo, para que o cliente possa fornecer algum contexto para nós, seres humanos.

A outra categoria de erros seria a família 4xx, que geralmente indica que o cliente fez algo errado. Em particular, essa categoria de erros normalmente indica ao cliente que não há necessidade de repetir a solicitação como está, porque continuará a falhar permanentemente. ou seja, o cliente precisa alterar alguma coisa antes de tentar novamente esta solicitação. Por exemplo, os erros "Recurso não encontrado" (HTTP 404) ou "Solicitação malformada" (HTTP 400) se enquadram nessa categoria.


Ponto 4: Como fazer autenticação

Conforme apontado no ponto 1, em vez de autenticar um usuário, convém pensar em criar uma sessão. Você receberá uma nova "ID da sessão", juntamente com o código de status HTTP apropriado (200: acesso concedido ou 403: acesso negado).

Você então perguntará ao servidor RESTful: "Você pode me OBTER o recurso para este ID da sessão?".

Não há modo autenticado - o REST é sem estado: você cria uma sessão, solicita ao servidor que forneça recursos usando esse ID de sessão como parâmetro e, ao sair, você interrompe ou expira a sessão.

Daniel Vassallo
fonte
6
Muito bom, porém seu uso PUTpara alterar uma senha provavelmente está incorreto; PUTrequer todo o recurso, portanto, você deverá enviar todos os atributos do usuário para cumprir com HTTP (e, portanto, com HATEOAS REST). Em vez disso, basta alterar a senha que se deve usar PATCHou POST.
Lawrence Dol
1
Eu acho que este post seria perfeito se você expandisse mais o que "POST: trata o membro endereçado como uma coleção por si só e cria um novo subordinado". significa. - Descobri o que significa pesquisar no Google - é uma exceção à sua ótima resposta.
Martin Konecny
6
Não concordo com a última frase. Você está explicando como o REST é sem estado. Efetuar login para criar uma sessão e depois encerrar a sessão após realizar algum trabalho é o melhor exemplo de uma API com estado.
Brandon
1
"Isso vai contra um princípio REST muito básico: o uso correto de verbos HTTP. Qualquer solicitação GET nunca deve causar nenhum efeito colateral." - E se você quiser manter uma contagem de ocorrências para o recurso?
bobbyalex
1
Este artigo deve responder às suas perguntas. saipraveenblog.wordpress.com/2014/09/29/rest-api-best-practices
java_geek 6/15
79

Simplificando, você está fazendo isso completamente ao contrário.

Você não deve abordar isso a partir de quais URLs deve usar. Os URLs virão efetivamente "de graça" quando você decidir quais recursos são necessários para o seu sistema E como os representará, e as interações entre os recursos e o estado do aplicativo.

Para citar Roy Fielding

Uma API REST deve gastar quase todo o seu esforço descritivo na definição do (s) tipo (s) de mídia usado para representar recursos e direcionar o estado do aplicativo, ou na definição de nomes de relações estendidos e / ou marcação ativada por hipertexto para os tipos de mídia padrão existentes. Qualquer esforço despendido na descrição de quais métodos usar em quais URIs de interesse deve ser totalmente definido no escopo das regras de processamento para um tipo de mídia (e, na maioria dos casos, já definido pelos tipos de mídia existentes). [Falha aqui implica que informações fora da banda estão gerando interação em vez de hipertexto.]

As pessoas sempre começam com os URIs e pensam que essa é a solução e, em seguida, tendem a perder um conceito-chave na arquitetura REST, notadamente, como citado acima: "A falha aqui implica que informações fora de banda estão gerando interação em vez de hipertexto. "

Para ser honesto, muitos veem vários URIs e alguns GETs, PUTs e POSTs e acham que o REST é fácil. REST não é fácil. RPC sobre HTTP é fácil, mover blobs de dados para frente e para trás em proxy através de cargas úteis de HTTP é fácil. O REST, no entanto, vai além disso. O REST é independente de protocolo. O HTTP é muito popular e apto para sistemas REST.

O REST vive nos tipos de mídia, em suas definições e em como o aplicativo direciona as ações disponíveis para esses recursos via hipertexto (links, efetivamente).

Há uma visão diferente sobre os tipos de mídia nos sistemas REST. Alguns preferem cargas úteis específicas do aplicativo, enquanto outros gostam de elevar os tipos de mídia existentes para funções apropriadas para o aplicativo. Por exemplo, por um lado, você tem esquemas XML específicos criados para o seu aplicativo, em vez de usar algo como XHTML como sua representação, talvez por meio de microformatos e outros mecanismos.

Ambas as abordagens têm seu lugar, eu acho, o XHTML funcionando muito bem em cenários que se sobrepõem tanto à web orientada por humanos quanto à orientada por máquina, enquanto os tipos de dados anteriores e mais específicos me parecem melhores facilitam as interações máquina a máquina. Acho que a melhoria dos formatos de commodities pode dificultar a negociação de conteúdo. "application / xml + yourresource" é muito mais específico como tipo de mídia do que "application / xhtml + xml", pois o último pode ser aplicado a muitas cargas úteis que podem ou não ser algo em que um cliente de máquina está realmente interessado, nem pode determinar sem introspecção.

No entanto, o XHTML funciona muito bem (obviamente) na web humana, onde os navegadores e a renderização são muito importantes.

Você aplicativo irá guiá-lo nesses tipos de decisões.

Parte do processo de criação de um sistema REST é descobrir os recursos de primeira classe em seu sistema, juntamente com os recursos de suporte derivativos necessários para suportar as operações nos recursos primários. Depois que os recursos são descobertos, a representação desses recursos, bem como os diagramas de estado que mostram o fluxo de recursos via hipertexto nas representações, são o próximo desafio.

Lembre-se de que cada representação de um recurso, em um sistema de hipertexto, combina a representação real do recurso e as transições de estado disponíveis para o recurso. Considere cada recurso como um nó em um gráfico, com os links sendo as linhas que deixam esse nó para outros estados. Esses links informam aos clientes não apenas o que pode ser feito, mas o que é necessário para que eles sejam feitos (como um bom link combina o URI e o tipo de mídia necessário).

Por exemplo, você pode ter:

<link href="http://example.com/users" rel="users" type="application/xml+usercollection"/>
<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>

Sua documentação falará sobre o campo rel chamado "usuários" e o tipo de mídia de "application / xml + youruser".

Esses links podem parecer redundantes, eles estão todos falando com o mesmo URI, basicamente. Mas eles não são.

Isso ocorre porque, na relação "usuários", esse link está falando sobre a coleção de usuários e você pode usar a interface uniforme para trabalhar com a coleção (GET para recuperar todos eles, DELETE para excluir todos eles etc.)

Se você POSTAR para este URL, precisará passar um documento "application / xml + usercollection", que provavelmente conterá apenas uma única instância do usuário no documento, para que você possa adicionar o usuário ou talvez não adicionar várias em uma vez. Talvez sua documentação sugira que você possa simplesmente passar um único tipo de usuário, em vez da coleção.

Você pode ver o que o aplicativo requer para realizar uma pesquisa, conforme definido pelo link "search" e seu tipo de mídia. A documentação para o tipo de mídia de pesquisa informará como isso se comporta e o que esperar como resultados.

O ponto principal aqui, porém, é que os próprios URIs são basicamente sem importância. O aplicativo está no controle dos URIs, não dos clientes. Além de alguns 'pontos de entrada', seus clientes devem confiar nos URIs fornecidos pelo aplicativo para seu trabalho.

O cliente precisa saber como manipular e interpretar os tipos de mídia, mas não precisa se preocupar para onde vai.

Esses dois links são semanticamente idênticos aos olhos dos clientes:

<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>
<link href="http://example.com/AW163FH87SGV" rel="search" type="application/xml+usersearchcriteria"/>

Então, concentre-se em seus recursos. Concentre-se nas transições de estado no aplicativo e em como isso é melhor alcançado.

Will Hartung
fonte
1
Obrigado Will por esta resposta muito profunda. Vários pontos tomados. Percebo que o planejamento de "como é a URL" está fazendo o contrário, e também estou planejando pelo lado do recurso. Ter URLs para brincar apenas facilita a compreensão do conceito. Ele poderia ser que minhas necessidades podem ser satisfeitas com um sistema que não 100% princípios follow resto como você define-lo aqui. Vou elaborar uma lista completa de requisitos para cada tipo de recurso, acho que poderei decidir então. Felicidades.
Pekka
30

re 1 : Parece bom até agora. Lembre-se de retornar o URI do usuário recém-criado em um cabeçalho "Local:" como parte da resposta ao POST, junto com o código de status "201 Criado".

re 2: A ativação via GET é uma má ideia, e incluir o verbo no URI é um cheiro de design. Você pode considerar devolver um formulário em um GET. Em um aplicativo Web, esse seria um formulário HTML com um botão de envio; no caso de uso da API, convém retornar uma representação que contenha um URI para PUT para ativar a conta. Obviamente, você também pode incluir esse URI na resposta do POST para / users. O uso de PUT garantirá que sua solicitação seja idempotente, ou seja, poderá ser enviada novamente com segurança se o cliente não tiver certeza do sucesso. Em geral, pense em quais recursos você pode transformar seus verbos (tipo de "substantivo dos verbos"). Pergunte a si mesmo com qual método sua ação específica está mais alinhada. Por exemplo, change_password -> PUT; desativar -> provavelmente DELETE; add_credit -> possivelmente POST ou PUT.

3. Não invente novos códigos de status, a menos que você acredite que sejam tão genéricos que merecem ser padronizados globalmente. Tente usar o código de status mais apropriado disponível (leia sobre todos eles na RFC 2616). Inclua informações adicionais no corpo da resposta. Se você realmente tem certeza de que deseja inventar um novo código de status, pense novamente; se você ainda acredita, escolha pelo menos a categoria correta (1xx -> OK, 2xx -> informativo, 3xx -> redirecionamento; 4xx-> erro do cliente, 5xx -> erro do servidor). Eu mencionei que inventar novos códigos de status é uma má idéia?

4. Se for possível, use a estrutura de autenticação incorporada no HTTP. Veja como o Google faz autenticação no GData. Em geral, não coloque chaves de API em seus URIs. Tente evitar sessões para aprimorar a escalabilidade e dar suporte ao armazenamento em cache - se a resposta a uma solicitação diferir por causa de algo que já havia acontecido antes, você normalmente está vinculado a uma instância de processo do servidor específica. É muito melhor transformar o estado da sessão em um estado cliente (por exemplo, torná-lo parte de solicitações subsequentes) ou explicitar transformando-o em estado de recurso (servidor), ou seja, fornecer seu próprio URI.

Stefan Tilkov
fonte
Você pode discutir por que não colocar chaves de API em URLs? É porque eles são visíveis nos logs de proxy? E se as chaves forem transitórias e baseadas no tempo? E se o HTTPS for usado?
precisa saber é o seguinte
4
Além de violar o espírito (os URIs devem identificar as coisas), a principal consequência é que isso arruina o cache.
Stefan Tilkov
22

1. Você tem a idéia certa sobre como projetar seus recursos, IMHO. Eu não mudaria nada.

2. Em vez de tentar estender o HTTP com mais verbos, considere a que seus verbos propostos podem ser reduzidos em termos de métodos e recursos básicos de HTTP. Por exemplo, em vez de um activate_loginverbo, você pode configurar recursos como: o /api/users/1/login/activeque é um booleano simples. Para ativar um logon, apenas PUTum documento que diz 'true' ou 1 ou o que for. Para desativar, PUTum documento que está vazio ou diz 0 ou falso.

Da mesma forma, para alterar ou definir senhas, basta fazer PUTs para /api/users/1/password.

Sempre que você precisar adicionar algo (como um crédito), pense em termos de POSTs. Por exemplo, você pode fazer um POSTpara um recurso como /api/users/1/creditsum corpo que contém o número de créditos a serem adicionados. Um PUTno mesmo recurso pode ser usado para substituir o valor em vez de adicionar. Um POSTcom um número negativo no corpo subtrairia, e assim por diante.

3. Aconselho fortemente a não estender os códigos de status HTTP básicos. Se você não encontrar um que corresponda exatamente à sua situação, escolha o mais próximo e insira os detalhes do erro no corpo da resposta. Além disso, lembre-se de que os cabeçalhos HTTP são extensíveis; seu aplicativo pode definir todos os cabeçalhos personalizados que você desejar. Um aplicativo em que trabalhei, por exemplo, poderia retornar um 404 Not Foundsob várias circunstâncias. Em vez de fazer o cliente analisar o corpo da resposta pelo motivo, acabamos de adicionar um novo cabeçalho X-Status-Extended, que continha nossas extensões de código de status proprietário. Então você pode ver uma resposta como:

HTTP/1.1 404 Not Found    
X-Status-Extended: 404.3 More Specific Error Here

Dessa forma, um cliente HTTP, como um navegador da web, ainda saberá o que fazer com o código 404 comum, e um cliente HTTP mais sofisticado pode optar por procurar no X-Status-Extendedcabeçalho informações mais específicas.

4. Para autenticação, eu recomendo usar a autenticação HTTP, se puder. Mas IMHO não há nada de errado em usar a autenticação baseada em cookies, se isso for mais fácil para você.

friedo
fonte
4
Idéia interessante de usar recursos "estendidos" para fazer coisas em porções menores de um recurso maior.
Womble
1
Os cookies são válidos no HTTP / REST, mas o servidor não deve armazenar o cookie como estado (portanto, não como uma sessão). O cookie pode armazenar um valor como um HMAC, no entanto, que pode ser desmontado sem procurar o estado em outro lugar.
precisa
14

Noções básicas de REST

O REST possui uma restrição de interface uniforme, que indica que o cliente REST deve confiar nos padrões em vez de nos detalhes específicos do aplicativo do serviço REST real, para que o cliente REST não sofra alterações menores e provavelmente será reutilizável.

Portanto, há um contrato entre o cliente REST e o serviço REST. Se você usar HTTP como o protocolo subjacente, os seguintes padrões farão parte do contrato:

  • HTTP 1.1
    • definições de método
    • definições de código de status
    • cabeçalhos de controle de cache
    • aceitar e cabeçalhos de tipo de conteúdo
    • cabeçalhos de autenticação
  • IRI ( URI utf8 )
  • corpo (escolha um)
    • tipo MIME específico do aplicativo registrado, por exemplo, labirinto + xml
    • tipo MIME específico do fornecedor, por exemplo, vnd.github + json
    • tipo MIME genérico com
      • vocabulário RDF específico da aplicação, por exemplo, ld + json & hydra , schema.org
      • perfil específico da aplicação, por exemplo, hal + json e parâmetro link do perfil (eu acho)
  • hiperlinks
    • o que deve contê-los (escolha um)
      • enviando cabeçalhos de link
      • enviando uma resposta hipermídia, por exemplo, html, átomo + xml, hal + json, ld + json e hydra, etc ...
    • semântica
      • use relações de link da IANA e provavelmente relações de link personalizadas
      • use um vocabulário RDF específico do aplicativo

O REST possui uma restrição sem estado, que declara que a comunicação entre o serviço REST e o cliente deve ser sem estado. Isso significa que o serviço REST não pode manter os estados do cliente; portanto, você não pode ter um armazenamento de sessão no servidor. Você precisa autenticar cada solicitação. Portanto, por exemplo, a autenticação básica HTTP (parte do padrão HTTP) está correta, porque envia o nome de usuário e a senha a cada solicitação.

Para responder suas perguntas

  1. Sim, pode ser.

    Apenas para mencionar, os clientes não se preocupam com a estrutura do IRI, eles se preocupam com a semântica, porque seguem links com atributos de relações de link ou dados vinculados (RDF).

    A única coisa importante sobre os IRIs é que um único IRI deve identificar apenas um único recurso. É permitido que um único recurso, como um usuário, tenha muitos IRIs diferentes.

    É bem simples porque usamos IRIs legais /users/123/password; é muito mais fácil escrever a lógica de roteamento no servidor quando você entender o IRI simplesmente lendo-o.

  2. Você tem mais verbos, como PUT, PATCH, OPTIONS e muito mais, mas não precisa de mais ... Em vez de adicionar novos verbos, você precisa aprender como adicionar novos recursos.

    activate_login -> PUT /login/active true deactivate_login -> PUT /login/active false change_password -> PUT /user/xy/password "newpass" add_credit -> POST /credit/raise {details: {}}

    (O logon não faz sentido da perspectiva REST, devido à restrição sem estado.)

  3. Seus usuários não se importam com a razão da existência do problema. Eles querem saber apenas se há sucesso ou erro e, provavelmente, uma mensagem de erro que eles possam entender, por exemplo: "Desculpe, mas não conseguimos salvar sua postagem.", Etc ...

    Os cabeçalhos de status HTTP são os cabeçalhos padrão. Tudo o resto deve estar no corpo, eu acho. Um único cabeçalho não é suficiente para descrever, por exemplo, mensagens de erro multilíngues detalhadas.

  4. A restrição sem estado (junto com o cache e as restrições do sistema em camadas) garante que o serviço seja dimensionado bem. Você certamente não deseja manter milhões de sessões no servidor, quando pode fazer o mesmo nos clientes ...

    O cliente de terceiros obtém um token de acesso se o usuário conceder acesso a ele usando o cliente principal. Depois disso, o cliente terceirizado envia o token de acesso a cada solicitação. Existem soluções mais complicadas, por exemplo, você pode assinar todas as solicitações etc. Para obter mais detalhes, consulte o manual do OAuth.

Literatura relacionada

inf3rno
fonte
11

Para os exemplos que você declarou, usaria o seguinte:

enable_login

POST /users/1/activation

deactivate_login

DELETE /users/1/activation

mudar senha

PUT /passwords (isso pressupõe que o usuário esteja autenticado)

adicionar crédito

POST /credits (isso pressupõe que o usuário esteja autenticado)

Para erros, você retornaria o erro no corpo no formato em que você recebeu a solicitação, portanto, se você receber:

DELETE /users/1.xml

Você enviaria a resposta de volta em XML, o mesmo seria para JSON etc ...

Para autenticação, você deve usar autenticação http.

jonnii
fonte
1
Eu não usaria createcomo parte do URI (lembre-se de que os URIs devem ser substantivos e os métodos HTTP devem ser verbos que operam nesses substantivos.) Em vez disso, eu teria um recurso como o /users/1/activequal pode ser um booleano simples e pode ser definido colocando 1 ou 0 nesse recurso.
Fredo
Você está certo, eu tirei o / create. Deve ser apenas uma postagem para o recurso singleton.
jonnii
3
Também não usaria activationno URI, a menos que você manipule e gerencie explicitamente um recurso com o nome de /users/1/activation. O que faz um GET nisso? O que um PUT faz? Parece-me que você está verbalizando o URI. Além disso, quanto à negociação de tipo de conteúdo, geralmente é melhor deixar de fora o URI e inseri-lo em cabeçalhos Accept.
Cheeso
6
  1. Use post quando você não souber como seria o novo URI do recurso (você cria um novo usuário, o aplicativo atribui ao novo usuário seu ID), PUT para atualizar ou criar recursos que você sabe como eles serão representados (exemplo : PUT /myfiles/thisismynewfile.txt)
  2. retornar a descrição do erro no corpo da mensagem
  3. Você pode usar a autenticação HTTP (se for o suficiente). Os serviços da Web devem ser stateles
Arjan
fonte
5

Eu sugeriria (como primeira passagem) que PUTsó deve ser usado para atualizar entidades existentes. POSTdeve ser usado para criar novos. ie

/api/users     when called with PUT, creates user record

não parece certo para mim. O restante da sua primeira seção (uso de verbo) parece lógico, no entanto.

Brian Agnew
fonte
provavelmente alguém pensou isso não era realmente uma resposta à sua pergunta
Lubos Hasko
6
Minha opinião sobre PUT versus POST para criar novas entidades é usar PUT quando o chamador controla o nome do recurso, para que você possa PUT no recurso exato e POST quando o receptor controlar o novo nome do recurso (como no exemplo aqui).
steved
5

Detalhado, mas copiado da especificação do método HTTP 1.1 em http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

9.3 GET

O método GET significa recuperar qualquer informação (na forma de uma entidade) identificada pelo Request-URI. Se o Request-URI se referir a um processo de produção de dados, são os dados produzidos que devem ser retornados como a entidade na resposta e não o texto de origem do processo, a menos que esse texto seja a saída do processo.

A semântica do método GET muda para um "GET condicional" se a mensagem de solicitação incluir um campo de cabeçalho If-Modified-Since, If-Modified-Since, If-Match, If-None-Match ou If-Range. Um método GET condicional solicita que a entidade seja transferida apenas nas circunstâncias descritas pelos campos de cabeçalho condicional. O método GET condicional visa reduzir o uso desnecessário da rede, permitindo que as entidades em cache sejam atualizadas sem exigir várias solicitações ou transferir dados já mantidos pelo cliente.

A semântica do método GET muda para um "GET parcial" se a mensagem de solicitação incluir um campo de cabeçalho Range. Um GET parcial solicita que apenas parte da entidade seja transferida, conforme descrito na seção 14.35. O método GET parcial tem como objetivo reduzir o uso desnecessário da rede, permitindo que entidades parcialmente recuperadas sejam concluídas sem transferir dados já mantidos pelo cliente.

A resposta a uma solicitação GET é armazenável em cache se, e somente se, atender aos requisitos de cache HTTP descritos na seção 13.

Consulte a seção 15.1.3 para considerações de segurança quando usado para formulários.

9.5 POST

O método POST é usado para solicitar que o servidor de origem aceite a entidade incluída na solicitação como um novo subordinado do recurso identificado pelo Request-URI na linha de solicitação. O POST foi projetado para permitir um método uniforme para cobrir as seguintes funções:

  - Annotation of existing resources;
  - Posting a message to a bulletin board, newsgroup, mailing list,
    or similar group of articles;
  - Providing a block of data, such as the result of submitting a
    form, to a data-handling process;
  - Extending a database through an append operation.

A função real executada pelo método POST é determinada pelo servidor e geralmente depende do URI de solicitação. A entidade postada é subordinada a esse URI da mesma maneira que um arquivo é subordinado a um diretório que o contém, um artigo de notícias é subordinado a um grupo de notícias no qual é postado ou um registro é subordinado a um banco de dados.

A ação executada pelo método POST pode não resultar em um recurso que pode ser identificado por um URI. Nesse caso, 200 (OK) ou 204 (Sem conteúdo) é o status de resposta apropriado, dependendo de a resposta incluir ou não uma entidade que descreve o resultado.

Se um recurso foi criado no servidor de origem, a resposta DEVE ser 201 (criada) e conter uma entidade que descreva o status da solicitação e se refira ao novo recurso, e um cabeçalho de localização (consulte a seção 14.30).

As respostas a esse método não podem ser armazenadas em cache, a menos que a resposta inclua os campos de cabeçalho Cache-Control ou Expir apropriados. No entanto, a resposta 303 (Consulte Outro) pode ser usada para direcionar o agente do usuário para recuperar um recurso armazenável em cache.

Os pedidos POST DEVEM obedecer aos requisitos de transmissão de mensagens estabelecidos na seção 8.2.

Consulte a seção 15.1.3 para considerações de segurança.

9.6 PUT

O método PUT solicita que a entidade fechada seja armazenada no URI de solicitação fornecido. Se o pedido de URI refere-se a um recurso já existente, a entidade fechada deve ser considerada como uma versão modificada do que reside no servidor de origem. Se o Request-URI não apontar para um recurso existente e esse URI puder ser definido como um novo recurso pelo agente do usuário solicitante, o servidor de origem poderá criar o recurso com esse URI. Se um novo recurso for criado, o servidor de origem DEVE informar o agente do usuário através da resposta 201 (Criada). Se um recurso existente for modificado, os códigos de resposta 200 (OK) ou 204 (sem conteúdo) DEVEM ser enviados para indicar a conclusão bem-sucedida da solicitação. Se o recurso não puder ser criado ou modificado com o Request-URI, uma resposta de erro apropriada deve ser dada que reflete a natureza do problema. O destinatário da entidade NÃO DEVE ignorar nenhum cabeçalho Content- * (por exemplo, Content-Range) que ele não entende ou implementa e DEVE retornar uma resposta 501 (Não Implementada) nesses casos.

Se o pedido passa através de um cache e o Request-URI identifica uma ou mais entidades atualmente em cache, essas entradas devem ser tratadas como obsoletas. As respostas a este método não são armazenáveis ​​em cache.

A diferença fundamental entre as solicitações POST e PUT é refletida no significado diferente do Request-URI. O URI em uma solicitação POST identifica o recurso que manipulará a entidade fechada. Esse recurso pode ser um processo de aceitação de dados, um gateway para outro protocolo ou uma entidade separada que aceita anotações. Por outro lado, o URI em uma solicitação PUT identifica a entidade incluída na solicitação - o agente do usuário sabe qual URI se destina e o servidor NÃO DEVE tentar aplicar a solicitação a algum outro recurso. Se o servidor desejar que a solicitação seja aplicada a um URI diferente,

DEVE enviar uma resposta 301 (movida permanentemente); o agente do usuário PODE então tomar sua própria decisão sobre se deve ou não redirecionar a solicitação.

Um único recurso pode ser identificado por muitos URIs diferentes. Por exemplo, um artigo pode ter um URI para identificar "a versão atual", que é separada do URI que identifica cada versão específica. Nesse caso, uma solicitação PUT em um URI geral pode resultar na definição de vários outros URIs pelo servidor de origem.

O HTTP / 1.1 não define como um método PUT afeta o estado de um servidor de origem.

Os pedidos de PUT DEVEM obedecer aos requisitos de transmissão de mensagens estabelecidos na seção 8.2.

A menos que especificado de outra forma para um cabeçalho de entidade específico, os cabeçalhos de entidade no pedido PUT DEVEM ser aplicados ao recurso criado ou modificado pelo PUT.

9.7 APAGAR

O método DELETE solicita que o servidor de origem exclua o recurso identificado pelo Request-URI. Este método pode ser substituído por intervenção humana (ou outros meios) no servidor de origem. Não é possível garantir ao cliente que a operação foi realizada, mesmo que o código de status retornado do servidor de origem indique que a ação foi concluída com êxito. No entanto, o servidor NÃO DEVE indicar sucesso, a menos que, no momento em que a resposta seja dada, pretenda excluir o recurso ou movê-lo para um local inacessível.

Uma resposta bem-sucedida DEVE ser 200 (OK) se a resposta incluir uma entidade que descreve o status, 202 (Aceito) se a ação ainda não foi promulgada ou 204 (Sem Conteúdo) se a ação foi promulgada, mas a resposta não incluir uma entidade.

Se o pedido passa através de um cache e o Request-URI identifica uma ou mais entidades atualmente em cache, essas entradas devem ser tratadas como obsoletas. As respostas a este método não são armazenáveis ​​em cache.

gahooa
fonte
2

Sobre os códigos de retorno REST: é errado misturar códigos de protocolo HTTP e resultados REST.

No entanto, vi muitas implementações misturando-as e muitos desenvolvedores podem não concordar comigo.

Os códigos de retorno HTTP estão relacionados a HTTP Requestele próprio. Uma chamada REST é feita usando uma solicitação do Hypertext Transfer Protocol e funciona em um nível mais baixo do que o próprio método REST invocado. REST é um conceito / abordagem e sua saída é um resultado comercial / lógico , enquanto o código de resultado HTTP é um transporte .

Por exemplo, retornar "404 Não encontrado" quando você chama / users / é confuso, porque pode significar:

  • O URI está errado (HTTP)
  • Nenhum usuário encontrado (REST)

"403 Proibido / Acesso Negado" pode significar:

  • É necessária permissão especial. Os navegadores podem lidar com isso perguntando ao usuário / senha. (HTTP)
  • Permissões de acesso incorretas configuradas no servidor. (HTTP)
  • Você precisa estar autenticado (REST)

E a lista pode continuar com 'Erro do servidor 500 "(um erro HTTP do Apache / Nginx lançado ou um erro de restrição de negócios no REST) ​​ou outros erros HTTP etc.

No código, é difícil entender qual foi o motivo da falha, uma falha HTTP (transporte) ou uma falha REST (lógica).

Se a solicitação HTTP foi fisicamente executada com sucesso, ela sempre deve retornar 200 códigos, independentemente dos registros encontrados ou não. Porque o recurso URI foi encontrado e foi tratado pelo servidor http. Sim, pode retornar um conjunto vazio. É possível receber uma página da web vazia com 200 como resultado http, certo?

Em vez disso, você pode retornar 200 códigos HTTP e simplesmente um JSON com uma matriz / objeto vazio, ou usar um sinalizador bool result / success para informar sobre o status da operação executada.

Além disso, alguns provedores de Internet podem interceptar suas solicitações e retornar um código http 404. Isso não significa que seus dados não foram encontrados, mas há algo errado no nível do transporte.

Do Wiki :

Em julho de 2004, o provedor de telecomunicações do Reino Unido BT Group implantou o sistema de bloqueio de conteúdo Cleanfeed, que retorna um erro 404 a qualquer solicitação de conteúdo identificado como potencialmente ilegal pela Internet Watch Foundation. Outros ISPs retornam um erro "proibido" de HTTP 403 nas mesmas circunstâncias. A prática de empregar erros 404 falsos como forma de ocultar a censura também foi relatada na Tailândia e na Tunísia. Na Tunísia, onde a censura era severa antes da revolução de 2011, as pessoas tomaram conhecimento da natureza dos falsos erros 404 e criaram um personagem imaginário chamado "Ammar 404", que representa "o censor invisível".

Marcodor
fonte