Uma API REST deve retornar um erro interno do servidor 500 para indicar que uma consulta faz referência a um objeto que não existe?


39

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

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

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

O servidor está retornando um 500 Internal Server Errorpara 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 o Postman , posso ver que o servidor retornou JSON no corpo que contém:

errorMessage: "This ID does not exist".

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

Uma API REST deve retornar a 500 Internal Server Errorpara relatar que uma consulta faz referência a um objeto que não existe? Na 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 OKcom a resposta contendo o erro e a descrição, que seriam proprietários da API em questão.


Ocorre-me que há uma diferença potencial de expectativa, dependendo de como a chamada REST está 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 indica 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 entenderia melhor a 404 Not Found, mas ainda assim poderia argumentar com base em quais partes do caminho são interpretadas como variáveis ​​versus pontos finais.


Essa condição que você está descrevendo é considerada um sucesso ou um fracasso?
Robert Harvey


@RobertHarvey Minha expectativa era que a API retornasse algumas informações sobre o dispositivo. A consulta em si deveria ter sido bem-sucedida, mas o ID do dispositivo desaparecido não deve causar uma falha no nível da solicitação.
JYelton

18
Um ID não existente soa como um 404 para mim. O motivo mais comum para 500 erros são os programadores que permitem que uma exceção interna seja exibida pelo servidor de hospedagem. Às vezes, existem casos verdadeiramente excepcionais em que isso acontece e às vezes é apenas uma programação preguiçosa. Difícil dizer o que está acontecendo aqui.
Berin Loritsch 23/03

9
500 servidor interno significa "A culpa é nossa, nós estragamos tudo", e você nunca deve tentar retornar esse status a um usuário. Seu objetivo é indicar basicamente um erro - seu usuário pode dizer que recebe 500 quando faz uma solicitação específica e, em seguida, você pode corrigi-la.
berry120

Respostas:


96

Eu acho que uma resposta 404 é a melhor correspondência semântica aqui, porque o recurso que você estava tentando encontrar (representado pelo URI usado para a consulta) não foi encontrado. O retorno de uma carga útil 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 não encontrado
O servidor não encontrou nada que corresponda ao Request-URI. Nenhuma indicação é dada sobre se a condição é temporária ou permanente. O código de status 410 (ido) DEVE ser usado se o servidor souber, através de algum mecanismo configurável internamente, que um recurso antigo está permanentemente indisponível e não possui endereço de encaminhamento. Esse código de status é comumente usado quando o servidor não deseja revelar exatamente por que a solicitação foi recusada ou quando nenhuma outra resposta é aplicável.


6
404 é apenas uma correspondência semântica se o ID que não existe corresponder ao recurso que está sendo recuperado.
Robert Harvey

55
@ThomasOwens Uma consulta que não retorne resultados retornaria 200 status e uma matriz vazia de resultados. Um 404 seria retornado apenas ao especificar um ID de objeto específico que realmente não existe.
Sean Burton

11
@ ThomasOwens: do ponto de vista do chamador, o ponto final não é /questions, é /questions/368213. Esse ponto de extremidade não existe no seu cenário. Pense da seguinte maneira: se você faz um GET on / foo / bar e não há bar, por que a resposta deve ser diferente se / foo existe ou não?
22718 Bryan Oakley

17
Certo, não é um erro do servidor, por isso não enviamos um 5xx. É um erro de cliente - o cliente pediu algo não têm, por isso, enviar 4xx, especificamente 404.
bdsl

7
@ThomasOwens: How do you differentiate between a 404 meaning "the query returned no results" and a 404 meaning "the endpoint does not exist"?- 400 Pedido inválido.
Robert Harvey

34

Vou usar seus exemplos.

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

Se o nó de extremidade retornar uma matriz json , a melhor opção é 200 OKcom uma matriz vazia se nenhum resultado for encontrado.

Se o terminal é projetado para retornar um único resultado , minha escolha seria 404 NOT FOUND, pois, para mim, a sintaxe correta para este tipo de endpoint é: http://example.com/restapi/deviceinfo/123. Eu normalmente uso o parâmetro de solicitação apenas para filtrar e quando meu ponto de extremidade retorna uma matriz.

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

Eu acho que essa pergunta já foi respondida aqui . POST ou GET, a melhor opção parece 404 NOT FOUNDporque o recurso 123não foi encontrado.

Nos dois casos, não vejo a necessidade de explicar o motivo da solicitação não ter sido concluída. As informações da solicitação e o código HTTP já explicam o porquê.


2
Como você distingue entre um ID inexistente e um URL incorreto?
Robert Harvey

2
@luizfzs, você também pode, não vejo problema nisso. Em algumas APIs que desenvolvi, prefiro usar 204 em um PUT ou DELETE bem-sucedido ( conforme explicado aqui ) sem nenhum corpo em resposta.
Dherik

10
Por que você deve distinguir entre um ID inexistente e um URL incorreto, nesse nível? De qualquer forma, você ainda está fazendo uma solicitação válida, no que diz respeito ao HTTP. O servidor simplesmente ... bem ... não consegue encontrar o recurso que você está endereçando. Um URL incorreto não é uma solicitação malformada; é um pedido bem formado para a coisa errada .
Chao

6
@cHao Porque, como desenvolvedor, quero saber se meu aplicativo está falhando porque o item não existe ou se acidentalmente apontei meu aplicativo para app.company.cxm / test / em vez de app.company.cxm / tst /
Patrick M

7
@PatrickM: como desenvolvedor, você deve saber que as respostas a erros também podem conter um corpo da mensagem. É aí que as informações explicativas dos erros vão, se você realmente deseja. Não quebre a semântica apenas porque você é paranóico com dedos gordos. No nível HTTP, não importa se você errou /itms/1234ou não /items/12234.
Chao

27

HTTP 404 está correto, porque o servidor entende qual recurso o cliente está solicitando, mas não possui 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. (Certamente, o termo "REST" passou a ter um significado mais amplo, mas ainda é possível usar seu significado literal aqui.) O cliente solicitou o estado de um recurso descrito pelo URL http://example.com/restapi/device/123/info. Uma querystring ( /deviceinfo?id=123) não mudaria a situação. O servidor sabe que você está solicitando a transferência do estado do dispositivo 123, mas não o reconhece como um recurso conhecido. Por isso HTTP 404.

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

  • HTTP 200- Temos o estado para você; está no corpo da resposta.
  • HTTP 204- Temos o estado para você; está em branco.
  • HTTP 400- Não podemos dizer sobre o recurso que você está perguntando. Corrija seu URL.
  • HTTP 500- Falhamos. Não é sua culpa.

Veja RFC 2616 Sec. 10 conforme apropriado.


Eu concordo com a sua opinião sobre isso. Se o servidor estivesse retornando um 404, isso faria mais sentido do que o que está fazendo (um 500). Obrigado.
JYelton

11

Um erro 5xx geralmente é usado para indicar que o servidor encontrou um erro e não pode concluir a solicitação. Se o servidor atender à solicitação, puder analisá-la com êxito e executar seu trabalho, isso não retornará um erro 5xx.

Não tenho certeza se existe algum tipo de convenção sobre o que retornar se uma consulta não produzir 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. O 200 provavelmente faz mais sentido - a solicitação foi concluída com êxito e não houve problemas com a solicitação do cliente ou durante o servidor processando a solicitação. Um corpo pode entregar uma mensagem ao cliente.


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

Primeiro, eu consideraria a autorização e autenticação. Se o usuário não tiver as permissões apropriadas, eu 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 em todos os erros de autenticação e autorização.

Então, eu cuidaria da identificação. Com base no seu exemplo, parece que é um ID numérico. Se um valor não numérico fosse fornecido, eu retornaria um 400. Se o parâmetro pudesse ser um identificador de dispositivo válido, 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 por que a solicitação foi ruim.

Se todos os parâmetros fossem válidos, eu 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) estiver indisponível, eu retornaria um código 5xx - 503 seria específico, mas 500 também seriam aceitáveis. Nos dois casos, eu retornaria um corpo com detalhes adicionais. Considere que, se uma dependência externa relatar um tempo limite de solicitação 408, eu comeria isso e retornaria 500 para o meu cliente, permitindo que um cliente recebesse um 408 somente se a solicitação para o meu sistema expirar. Se o sistema puder concluir a solicitação, eu retornaria 200 e o corpo apropriado.

204 pode ser útil em alguns casos, mas impede o envio de um corpo de resposta. Especialmente em uma configuração de API, enviar um corpo de resposta com informações que podem ser alimentadas em um mecanismo de registro ou relatório parece ser a decisão certa a ser tomada na maioria dos casos.

A única vez que um 404 seria retornado é se o servidor não tivesse um /deviceinfoterminal ou um /device/:id/infoterminal.

Eu não consideraria um ID que não seja o mesmo que o recurso não encontrado. O recurso são as informações 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 realmente fornecer informações sobre o dispositivo. Pode ou não haver um dispositivo com o ID especificado.


1
@RobertHarvey Sim. Não houve erros. Só porque o servidor gerou o GUID e o enviou ao cliente não significa que outra operação o removeu. A solicitação / resposta foi bem-sucedida. O comando ou consulta representado pela solicitação não retornou dados. Para mim, isso não é um fracasso. Ela poderia ser uma exceção, mas eu não estou convencido de que é digno de um 5xx.
Thomas Owens

2
Se eu estivesse projetando essa API que estou consultando, gostaria que ela retornasse 200 com um corpo que então contenha algo com efeito device: 123; status: not found;. Então eu sei que a consulta funcionou e que a API está me informando informações úteis.
JYelton

7
@Blrfl Isso é copiado (embora não "comprovado") pela redação de muitos sites 500 páginas, geralmente algo como "Cometemos um erro e investigaremos". Na minha opinião, um servidor que funcione corretamente nunca envia 500s, exceto talvez no caso de raios cósmicos.
mbrig

6
Http não tem conceito de 'ponto final', nenhuma distinção relevante entre uma variável e o restante da URL e, portanto, também não. Você pode ter um sistema de roteamento que corresponda a uma regex e roteie milhares de URLs para uma função de controlador, mas isso é um detalhe de implementação, não uma parte fundamental da API. Uma resposta 200 em um get é apenas para o caso em que o recurso solicitado está sendo recuperado. Nesse caso, o cliente deseja uma representação de um recurso que não existe, portanto 404 é a resposta correta.
bdsl

8
Um sistema com função adequada nunca envia uma resposta de 500. Um servidor com função adequada pode enviar um 500 porque, se faz parte de um sistema maior e detectou um erro interno ao sistema maior, por exemplo, o banco de dados está inoperante ou outro dependente do serviço da Web está retornando resultados sem sentido.
bdsl

5

Um erro HTTP da série 500 indica um mau funcionamento do servidor. Além de 501 Not Implementede 505 HTTP Version Not Supported, o uso desses códigos de erro implica que a tentativa de repetir a solicitação posteriormente poderá ser bem-sucedida (embora apenas o 503 Service Unavailableexponha explicitamente). Idealmente, um servidor nunca deve produzir um desses códigos, embora a incapacidade de escrever software livre de erros e fornecer ao servidor 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 é um objeto por nome) ou 200 Successcom um corpo de resultado vazio (ao procurar um objeto por atributos). 204 No Contentparece tentador, mas eu o usaria apenas para situações em que a falta de um corpo de resposta é o resultado esperado.


1

Como cliente da 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 recuperar um (representação de) um DeviceInfoobjeto (ou algum tipo específico de qualquer maneira, seja um tipo formal ou apenas algo conforme uma convenção "tipo de pato" documentada). Quero que um 200status signifique que realmente tenho um, e posso usá-lo.

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

Isso significa, como consumidor da API, que eu posso usar algum tipo de função de chamada de descanso verificado que recupera uma resposta ou gera uma exceção. Isso é ótimo; minha lógica normal pode ser um 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 "nenhum recurso encontrado" sem que eu precise fazer nada, e não como erros de "atributo ausente" quando mais tarde eu processarmos { errorMessage: "Device 123 not found" }como se fosse um DeviceInfoobjeto.

Se você considerar que o terminal http://example.com/restapi/deviceinfo foi encontrado e não for o único id=123, e retornar 200 com uma mensagem de erro no corpo, estará 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 arbitrariamentenull. É muito melhor, como usuário da sua interface, indicar erros através de um canal "separado" dos retornos regulares. Isso se aplica aqui também, mesmo que as respostas HTTP 200, 404 e 500 sejam o mesmo canal do ponto de vista de baixo nível. Eles são padronizados e fáceis de distinguir para que minha estrutura de cliente REST possa alternar facilmente esses status para transformá-los nas estruturas apropriadas no meu idioma; para fazer a mesma coisa com a camada JSON (onde você sempre diz 200 e me dá uma DeviceInfoou uma mensagem de erro), preciso incorporar algum conhecimento dos esquemas JSON usados.

Portanto, use apenas 200 quando você puder retornar um valor válido do tipo esperado (é por isso que http://example.com/restapi/search-devices?colour=bluepode retornar 200 com uma matriz vazia se não houver dispositivos azuis; uma matriz vazia é uma matriz válida e uma resposta sensata à solicitação "I gostaria dos detalhes de todos os dispositivos azuis "). Se não puder, use o código de status não-200 mais apropriado. Mesmo que "o dispositivo 123 não exista" seja a resposta correta para "forneça os detalhes do dispositivo 123" e não seja um erro para o servidor , é uma exceção à expectativa do cliente de que ele retornará DeviceInfoe deve não seja comunicado como uma resposta normal "aqui está o que você pediu".


Infelizmente, também sou cliente desta API e não posso alterá-la. Este é um ótimo resumo de como deve funcionar.
JYelton

0

Você poderia usar o erro 422 Unprocessable Entity para diferenciar de 404 não encontrado . 422 significa que o servidor entende a solicitação, mas não pode dar uma resposta adequada. Estou usando esse código em situações semelhantes.


4
Este artigo descreve o uso do 422 em mais detalhes. Eu não acho que esse código de erro seja realmente aplicável aqui.
Robert Harvey

Obrigado, muito útil! Vou ter que aprofundar esse assunto!
FiNeX 23/03/19

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 cara e estão sendo evitados.

O erro 4xx deve sinalizar ao programador que o ponto de extremidade da API (recurso) não existe. Consequentemente, uma vez atingido o ponto de extremidade apropriado, qualquer tratamento de erro a partir desse ponto é de responsabilidade do programador da API que deve ser tratado normalmente, ou seja, com uma mensagem de erro de 200 respostas.


1
Então você está dizendo "não use 500 porque não está travando o servidor?"
Robert Harvey

0

Embora o w3 observe que 404 é usado quando nenhuma outra resposta é aplicável , não seria para isso que uma resposta 204 (Sem conteúdo) é adequada? A solicitação era válida do ponto de vista de processamento e o servidor processou a solicitação e tem um resultado. Esse é um sucesso, que se inclina para respostas 2xx. Como não havia conteúdo para essa solicitação específica, o 204 informa ao usuário que não havia nada errado com a consulta, mas não havia nada lá.

Você também pode argumentar que 409 (Conflito) é uma resposta apropriada. Embora 409 seja usado com mais frequência para um POST, ele diz

A solicitação não pôde ser concluída devido a um conflito com o estado atual do recurso. Esse código é permitido apenas em situações em que se espera que o usuário possa resolver o conflito e reenviar a solicitação. O corpo da resposta DEVE incluir informações suficientes para que o usuário reconheça a fonte do conflito. Idealmente, a entidade de resposta incluiria informações suficientes para que o usuário ou agente do usuário corrija o problema; no entanto, isso pode não ser possível e não é necessário.

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


3
Não, a resposta 204 em uma solicitação get só faria sentido quando o recurso solicitado foi encontrado e sua representação possui exatamente zero caracteres.
bdsl

0

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


-4

Outros usuários forneceram respostas válidas para o que fazer se você quiser seguir as instruções.

No entanto, eu sugiro que você esteja lendo muito sobre o RESTfulness e sendo absolutamente respeitoso com relação a ele.

REST é um protocolo caprichoso, porque se você deseja seguir o livro enquanto o usa, força o cliente e o servidor a serem construídos com conhecimento específico do fato de que estão se comunicando via REST, portanto, em essência, o protocolo de comunicação específico usado não pode ser abstraído.

Há 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 "Erro interno do servidor HTTP 500" 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 a entrega não é da conta do protocolo de comunicação. Portanto, uma vez que o servidor tenha recebido a solicitação com êxito e comece a processá-la, muitos erros poderão ocorrer, mas esses são todos erros específicos do aplicativo que não são da conta do protocolo de comunicação nada. Eles devem ser comunicados dentro da carga de uma resposta que pareça perfeitamente bem-sucedida, tanto quanto o protocolo de comunicação sabe.

Portanto, eu recomendo retornar um "HTTP 200 OK" e, dentro da carga útil da resposta ("corpo do conteúdo da resposta" na linguagem HTTP), tenha um código de erro específico do aplicativo que diga "ID não encontrado" ou qualquer outra coisa.


A julgar pelos votos negativos, acho que devo ter ferido os sentimentos de algumas pessoas. Ou talvez alguma outra parte do corpo. C -: =
Mike Nakis 26/03

Eles deveriam realmente ler isto: blogs.dropbox.com/developers/2015/04/…
Mike Nakis

1
Não faz mal aqui. Você está errado. Mesmo o artigo ao qual você vinculou não menciona o uso de códigos de status tão flagrantemente errados que erros e sucesso parecem iguais. Diz: "Falando de bom gosto, é importante lembrar que o design da API não é estritamente sobre as implicações práticas no software cliente e servidor. O público-alvo de uma API é o desenvolvedor que a consumirá. De acordo com o" princípio do mínimo espanto ", os desenvolvedores terão mais facilidade em aprender e entender uma API se seguir as mesmas convenções que outras APIs com as quais estão familiarizadas".
cHao 26/03

@cHao, suponho que a parte que diz "O Dropbox atualmente usa cerca de 10 códigos de status diferentes (8 erros e 2 para obter sucesso), mas estamos planejando reduzir esse número em uma versão futura da API" não significou nada para vocês.
Mike Nakis 8/03

Não quis dizer o que você está recebendo disso. Se eles souberem o que estão fazendo, então, no extremo, reduzirão para um sucesso e quatro códigos de erro (400, 401, 404 e 500), porque obviamente se preocupam com as convenções.
cHao 8/03
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.