Uma API REST deve retornar um 500 Internal Server Error para indicar que uma consulta faz referência a um objeto que não existe?

37

Estou trabalhando com uma API REST que reside em um servidor que manipula dados para vários dispositivos de IoT.

Minha tarefa é consultar o servidor usando a API para coletar informações de desempenho específicas sobre esses dispositivos.

Em uma instância, eu obtenho uma lista de dispositivos disponíveis e seus identificadores correspondentes e, em seguida, consulta mais tarde o servidor para obter mais detalhes usando esses identificadores (GUIDs).

O servidor está retornando um 500 Internal Server Error para uma consulta em um desses IDs. No meu aplicativo, uma exceção é lançada e não vejo detalhes sobre o erro. Se eu examinar a resposta mais de perto com Postman , eu posso ver que o servidor retornou JSON no corpo que contém:

errorMessage: "This ID does not exist".

Desconsidere o fato de que o servidor forneceu o ID para começar - esse é um problema separado para o desenvolvedor.

Uma API REST deve retornar um 500 Internal Server Error para informar que uma consulta faz referência a um objeto que não existe? Em minha opinião, os códigos de resposta HTTP devem se referir estritamente ao status da chamada REST, e não à mecânica interna da API. Eu esperaria um 200 OK com a resposta contendo o erro e a descrição, que seriam proprietários da API em questão.

Ocorre-me que existe uma diferença de potencial na expectativa dependendo de como a chamada REST é estruturada.

Considere estes exemplos:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

No primeiro caso, o ID do dispositivo é passado como uma variável GET. Um 404 ou 500 indicaria que o caminho ( /restapi/deviceinfo ) não foi encontrado ou resultou em um erro do servidor.

No segundo caso, o ID do dispositivo faz parte do URL. Eu seria mais compreensivo de um 404 Not Found , mas ainda poderia argumentar com base em quais partes do caminho são interpretadas como variáveis versus pontos de extremidade.

    
por JYelton 23.03.2018 / 17:31
fonte

11 respostas

95

Acho que uma resposta 404 é a melhor correspondência semântica aqui, porque o recurso que você estava tentando localizar (conforme representado pelo URI usado para a consulta) não foi encontrado. Retornar uma carga de erro no corpo é razoável, mas não é obrigatório.

De acordo com a RFC 2616 , a definição do código de status 404 é :

10.4.5 404 Not Found
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.

    
por 23.03.2018 / 17:42
fonte
34

Vou usar seus exemplos.

http://example.com/restapi/deviceinfo?id=123

Se o endpoint retornar um json array , a melhor opção será 200 OK com um array vazio se nenhum resultado for encontrado.

Se o endpoint foi projetado para retornar um único resultado , minha escolha seria 404 NOT FOUND , porque, para mim, a sintaxe correta para esse tipo de endpoint é: http://example.com/restapi/deviceinfo/123 . Eu costumo usar param de solicitação apenas para filtragem e quando meu endpoint retorna um array.

http://example.com/restapi/device/123/info

Acho que essa pergunta já foi respondida aqui . POST ou GET, a melhor escolha parece 404 NOT FOUND porque o recurso 123 não foi encontrado.

Em ambos os casos, não vejo a necessidade de explicar o motivo pelo qual a solicitação não foi concluída. As informações de solicitação e o código HTTP já explicam por que.

    
por 23.03.2018 / 19:35
fonte
26

HTTP 404 está correto, porque o servidor entende qual recurso o cliente está solicitando, mas não tem esse recurso.

O fato de você estar trabalhando com uma "API REST" é a chave. A API deve se comportar como se estivesse executando uma transferência de estado REpresentational, não executando uma função. (Claro, o termo "REST" passou a ter um significado mais amplo, mas você ainda pode usar seu significado literal aqui.) O cliente solicitou o estado de um recurso descrito pela URL http://example.com/restapi/device/123/info . Uma querystring ( /deviceinfo?id=123 ) não alteraria a situação. O servidor sabe que você está pedindo para transferir o estado do dispositivo 123, mas não reconhece isso como um recurso conhecido. Daí HTTP 404 .

As outras respostas possíveis discutidas aqui também têm significados específicos:

  • HTTP 200 - Nós temos o estado para você; está no corpo da resposta.
  • HTTP 204 - Nós temos o estado para você; está em branco.
  • HTTP 400 - Não podemos dizer de que recurso você está perguntando. Corrija seu URL.
  • HTTP 500 - Nós não funcionamos corretamente. Não é sua culpa.

Veja RFC 2616 Sec. 10, conforme apropriado.

    
por 24.03.2018 / 00:43
fonte
11

Um erro 5xx é normalmente usado para indicar que o servidor encontrou um erro e não pode concluir a solicitação. Se o servidor receber a solicitação, poderá analisá-lo com êxito e, em seguida, realizará o trabalho, que não deverá retornar um erro 5xx.

Não tenho certeza se existe algum tipo de convenção sobre o que retornar se uma consulta não gerar resultados. Eu vi tanto o que você descreve (um 200 com um corpo que contém uma mensagem) quanto um 404 indicando que os resultados não foram encontrados. Os 200 provavelmente fazem mais sentido - a solicitação foi concluída com sucesso e não houve problemas com a solicitação do cliente ou durante o processamento do pedido pelo servidor. Um corpo pode entregar uma mensagem ao cliente.

Eu trataria os dois exemplos ( http://example.com/restapi/deviceinfo?id=123 e http://example.com/restapi/device/123/info ) da mesma forma - o 123 é um parâmetro. Ambos os casos são formas diferentes de estruturar uma solicitação para obter informações do dispositivo para um dispositivo com o ID 123.

Primeiro, eu consideraria autorização e autenticação. Se o usuário não tiver as permissões apropriadas, retornaria um 403 ou um 401, conforme apropriado. Embora seja chamado de "Não autorizado", meu entendimento é que 401 é mais sobre autenticação e 403 é sobre não autorizado ou permissão negada. Eu não seria muito exigente aqui, no entanto, se você quisesse manter o 403 para todos os erros de autenticação e autorização.

Então, eu lidaria com o ID. Com base no seu exemplo, parece que é um ID numérico. Se um valor não numérico fosse fornecido, retornaria um 400. Se o parâmetro pudesse ser um identificador de dispositivo válido, eu continuaria com o processamento. Se houvesse outros argumentos, eles também seriam verificados aqui. Eu esperaria que o corpo da resposta contivesse informações apropriadas sobre o motivo pelo qual a solicitação foi ruim.

Se todos os parâmetros fossem válidos, começaria a processar a solicitação. Se o sistema ou qualquer dependência (um banco de dados, um serviço de terceiros, outro serviço interno) não estiver disponível, retornaria um código 5xx - 503 seria específico, mas um 500 também seria aceitável. Em ambos os casos, eu retornaria um corpo com detalhes adicionais. Considere que, se uma dependência externa relatar um 408 Request Timeout, eu comia isso e retornava um 500 para meu cliente, permitindo que um cliente recebesse um 408 somente se a solicitação ao meu sistema atingisse o tempo limite. Se o sistema for capaz de completar o pedido, eu retornaria um 200 e o corpo apropriado.

204 pode ser útil em alguns casos, mas impede que você envie um corpo de resposta. Especialmente em uma configuração de API, enviar um corpo de resposta com informações que podem ser inseridas em um mecanismo de criação de relatórios ou relatórios parece ser a decisão correta na maioria dos casos.

O único momento em que um 404 seria retornado seria se o servidor não tivesse um ponto de extremidade /deviceinfo ou% endpoint /device/:id/info .

Eu não consideraria um ID que não fosse o mesmo que o recurso não encontrado. O recurso é a informação do dispositivo para um dispositivo específico (no seu exemplo). Retornar um 404 significaria que o recurso (as informações do dispositivo) não existe. Um 200 com um corpo apropriado significa que o sistema pode, de fato, fornecer informações sobre o dispositivo. Pode ou não haver um dispositivo com o ID especificado.

    
por 23.03.2018 / 17:39
fonte
5

Um erro HTTP da série 500 indica um mau funcionamento do servidor. Além de 501 Not Implemented e 505 HTTP Version Not Supported , o uso desses códigos de erro leva a implicação de que tentar novamente a solicitação em um momento posterior pode ter êxito (embora apenas 503 Service Unavailable declare isso explicitamente). Idealmente, um servidor nunca deve produzir um desses códigos, embora a incapacidade de escrever softwares livres de erros e provisionar o servidor com recursos infinitos signifique que você precisará deles de tempos em tempos.

Para um resultado "objeto não existe", você provavelmente deve retornar 404 Not Found (quando a solicitação é para um objeto pelo nome) ou 200 Success com um corpo de resultados vazio (ao procurar um objeto por atributos ). 204 No Content parece tentador, mas eu o usaria apenas para situações em que a falta de um corpo de resposta é o resultado esperado.

    
por 24.03.2018 / 01:29
fonte
1

Como cliente de sua API, quando faço uma dessas chamadas:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

Espero receber de volta uma (representação de) um objeto DeviceInfo (ou algum tipo específico de qualquer maneira, seja um tipo formal ou apenas algo em conformidade com uma convenção documentada de "tipo de pato"). Eu quero um status 200 para dizer que eu realmente tenho um, e eu posso ir em frente e usá-lo.

Para APIs REST, penso nos códigos de status 400 e 500 como algo como exceções. Você os usa para indicar quando não é possível retornar uma resposta "normal" para a solicitação recebida, portanto, o cliente precisará fazer algo excepcional em vez de processar as informações que esperava recuperar.

Isso significa, como um consumidor de API, que posso usar algum tipo de função check-rest-call que recupera uma resposta ou lança uma exceção. Isso é ótimo; minha lógica normal pode ser código de linha reta, e posso organizar meu tratamento de erros da mesma maneira que faço no código local. 404s inesperados se manifestarão como exceções "sem recurso encontrado" sem que eu tenha que fazer nada, não como erros de "atributo ausente" quando eu estiver processando { errorMessage: "Device 123 not found" } como se fosse um objeto DeviceInfo .

Se você acha que o ponto de extremidade http://example.com/restapi/deviceinfo é encontrado, e é apenas o id=123 que não está, e então retorne 200 com uma mensagem de erro no corpo, então você criando exatamente o mesmo tipo de problemas de interface que as funções C que poderiam retornar um resultado correto ou um código de erro, ou métodos que indicam problemas retornando arbitrariamente null . É muito melhor que um usuário da sua interface tenha erros indicados por meio de um canal "separado" dos retornos regulares. Isso se aplica aqui também, embora as respostas HTTP 200, 404 e 500 sejam o mesmo canal de um ponto de vista de baixo nível. Eles são padronizados e fáceis de distinguir, portanto, minha estrutura de cliente REST pode alternar facilmente esses status para transformá-los nas estruturas adequadas em meu idioma; para fazer a mesma coisa com a camada JSON (onde você sempre diz 200 e me dá uma DeviceInfo ou uma mensagem de erro) Eu preciso incorporar algum conhecimento dos esquemas JSON que você usa.

Portanto, use 200 somente quando puder retornar um valor válido do tipo esperado (e é por isso que http://example.com/restapi/search-devices?colour=blue pode retornar 200 com uma matriz vazia se não houver dispositivos azuis; uma matriz vazia é uma matriz válida e uma responder ao pedido "Eu gostaria que os detalhes de todos os dispositivos azuis"). Se você não puder, use o código de status não-200 mais apropriado. Mesmo que "o dispositivo 123 não exista" é a resposta correta para "me dar os detalhes do dispositivo 123" e não é um erro para o servidor , é uma exceção para a expectativa do cliente que eles Receberá de volta um DeviceInfo e não deverá ser comunicado como uma resposta normal "aqui está o que você pediu".

    
por 26.03.2018 / 02:47
fonte
0

Você pode usar o erro 422 Entidade não processável para diferenciar de 404 não encontrado . 422 significa que o servidor entende o pedido, mas não pode dar uma resposta adequada. Estou usando esse código em situações semelhantes.

    
por 23.03.2018 / 20:52
fonte
0

O erro 500 normalmente indica que a solicitação travou um programa do lado do servidor; em ambientes corporativos, esses erros são tratados como um ovo na face e estão sendo evitados.

O erro 4xx deve sinalizar ao programador que o ponto de extremidade (recurso) da API não existe. Conseqüentemente, quando o endpoint apropriado é atingido, qualquer tratamento de erro a partir desse ponto é a responsabilidade do programador da API que deve ser tratada normalmente, ou seja, com uma mensagem de erro de uma resposta 200.

    
por 23.03.2018 / 21:19
fonte
0

Embora o w3 observe que 404 é usado quando nenhuma outra resposta é aplicável , não seria isso que uma resposta 204 (Sem conteúdo) é boa? A solicitação foi válida do ponto de vista de processamento e o servidor processou a solicitação e obteve um resultado. Isso é um sucesso, que se inclina para respostas de 2xx. Não havia conteúdo para este pedido em particular, então 204 diz ao usuário que não havia nada errado com a consulta, mas não há nada lá.

Você também pode fazer um caso fraco de que 409 (Conflito) é uma resposta apropriada. Embora 409 seja mais usado para um POST, ele diz

The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.

indiscutivelmente a não existência do ID solicitado é o conflito aqui, e retornar na mensagem que tal ID não existe no sistema é informação suficiente para o usuário reconhecer e consertar o conflito.

    
por 23.03.2018 / 21:52
fonte
0

As outras respostas cobrem isso, mas eu só queria ressaltar que um erro da série 500 significa "eu estraguei tudo". Nesse caso, "I" significa a API, portanto, um erro de servidor não manipulado ou semelhante. Um erro da série 400 significa "você estragou tudo" - o chamador da API enviou algo incorreto.

    
por 25.03.2018 / 17:47
fonte
-4

Outros usuários forneceram respostas válidas para o que fazer se você quiser ir pelo livro.

No entanto, gostaria de sugerir que você está lendo demais no RESTfulness e sendo absolutamente casto com relação a ele.

REST é um protocolo caprichoso, porque se você quiser ir pelo livro enquanto o usa, ele força o cliente e o servidor a serem construídos, tendo conhecimento específico do fato de que eles estão se comunicando via REST, então, em essência, o específico protocolo de comunicação utilizado não pode ser abstraído.

Existe uma abordagem diferente: evite completamente o RESTfulness e use-o apenas como um protocolo de comunicação e nada mais. Isso significa que as únicas respostas que precisam ser retornadas são "HTTP 200 OK" e "HTTP 500 Internal Server Error" porque, no que diz respeito ao protocolo de comunicação, qualquer tentativa de comunicação pode ter apenas dois resultados: a solicitação foi bem-sucedida entregue ao servidor, ou não.

O que acontece após o parto não é da conta do protocolo de comunicação. Assim, uma vez que o servidor tenha recebido com sucesso o pedido e comece a processá-lo, muitos erros podem ocorrer, mas esses são todos os erros específicos do aplicativo que não são do conhecimento do protocolo de comunicação. Eles devem ser comunicados dentro da carga útil de uma resposta que parece perfeitamente bem-sucedida, até onde o protocolo de comunicação sabe.

Por isso, recomendo retornar um "HTTP 200 OK" e dentro da carga útil da resposta ("corpo do conteúdo de resposta" no jargão HTTP) ter um código de erro específico do aplicativo que diga "ID não encontrado" .

    
por 25.03.2018 / 09:58
fonte