Devo retornar uma resposta 204 ou 404 quando um recurso não for encontrado?

15

Estou desenvolvendo um serviço RESTful simples para torneios e horários. Quando um torneio é criado por meio de uma solicitação POST que contém um corpo JSON, o torneio é inserido em um BiMapdeclarado da seguinte maneira em uma implementação do DAO:

private BiMap<String, Tournament> tournaments = Maps.synchronizedBiMap(HashBiMap.create());

Quando um torneio é criado, seu ID de string associado é retornado para que o usuário possa ter referência futura a esse torneio. Ele / ela pode obter informações de volta do novo torneio, realizando a seguinte solicitação:

GET http://localhost:8080/eventscheduler/c15268ce-474a-49bd-a623-b0b865386f39

Mas e se nenhum torneio com esse ID for encontrado? Até agora, estou retornando uma resposta 204. Bem, Jersey está fazendo isso por mim ao retornar nullde um de seus métodos. Este é o método que corresponde à rota acima:

@Path("/{id}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Tournament getTournament(@PathParam("id") String id) {
    Optional<Tournament> optTournament = tournamentDao.getTournament(id);
    if (optTournament.isPresent())
        return optTournament.get();
    return null;
}

Minha pergunta é: está correto retornar uma 204: No Contentresposta ou deve ser uma 404resposta, pois o recurso não foi encontrado?

Se devo alterá-lo para uma questão 404, óbvia: devo alterar a assinatura do método, certo? Como agora um torneio (do tipo Tournament) pode não ser retornado, o método deve parecer diferente. Em vez disso, devo usar o Responsetipo como tipo de retorno?

dabadaba
fonte

Respostas:

32

HTTP 204significa que algo foi encontrado, mas está vazio. Por exemplo, imagine que você está exibindo arquivos de log por HTTP, com solicitações como http://example.com/logs/[date-goes-here] . Em 18 de maio de 2015:

  • http://example.com/logs/2015-05-19 retornaria HTTP 404, o que significa que não há registros, porque, bem, é difícil registrar o futuro.

  • http://example.com/logs/2015-05-18 , no entanto, retornaria HTTP 200com as entradas de log no conteúdo da resposta ou HTTP 204se o arquivo de log foi criado, mas ainda não há registros registrados para este encontro.

Se você fornecer nullà estrutura como resposta a uma solicitação, ela pressupõe que você encontrou uma entrada e, portanto, esta entrada está vazia HTTP 204. Em vez disso, você deve throw new NotFoundException();indicar à estrutura que a entrada não existe, para gerar uma HTTP 404.

Se devo alterá-lo para uma questão 404, óbvia: devo alterar a assinatura do método, certo?

Não você não. Essa é a coisa mais legal throw new NotFoundException();. Funcionará independentemente do tipo de retorno real do seu método.

Arseni Mourzenko
fonte
5
Tome nota especial da RFC 2616 . As respostas 204 são compatíveis apenas com as especificações se você estiver omitindo completamente o corpo da mensagem. Até certo ponto, o objetivo de uma resposta é dizer "não, não foi por acaso que não retornei conteúdo". Para expandir o exemplo da MainMa: Se uma ferramenta de pesquisa de log cuspir arquivos de texto (por exemplo, um invólucro fino em torno dos arquivos de log que apenas expele o arquivo de log como está), um 204 seria apropriado para um arquivo de log vazio. Se a resposta fosse um objeto JSON vazio (por exemplo, {content: ''}), uma resposta 204 seria inadequada.
22716 Brian As
" porque, bem, é difícil registrar o futuro. " - Este bit depende de uma data arbitrária; por que não fazer algo que não exija que o leitor finja que não é hoje? Talvez usar 2015-02-29seria melhor, já que é uma data que não existe?
Fund Monica's Lawsuit
1

O seu pedido é GET http://localhost:8080/eventscheduler/c15268ce-474a-49bd-a623-b0b865386f39.

Se http://localhost:8080/eventscheduler/não existir como um terminal, você deve retornar um 404. Você está tentando acessar um recurso ( /eventscheduler/) que não existe. Isso indicaria para um cliente que existe um servidor localhost:8080, mas não há nada no eventschedulerterminal.

Se http://localhost:8080/eventscheduler/existir como um terminal, mas os recursos necessários não estiverem disponíveis, um erro 5xx é apropriado. Um bom exemplo disso seria se um banco de dados estivesse offline, onde você poderia retornar um 503. Obviamente, você pode apenas querer retornar um erro 500 genérico em vez de uma instância específica.

Se http://localhost:8080/eventscheduler/existe, mas a coisa representada por c15268ce-474a-49bd-a623-b0b865386f39não existe, eu retornaria um 200 com um corpo indicando os detalhes. O terminal existe, a solicitação feita foi totalmente válida e pode ser processada, mas não houve correspondência.

Se a solicitação do cliente para o terminal não for válida, você observaria os outros erros 4xx. Você pode indicar que o cliente não está autorizado a acessar o terminal ou os itens solicitados com 401 ou 403 ou pode usar um 400 para indicar que a solicitação é inválida. Com qualquer um desses, informações adicionais podem ser fornecidas no corpo da resposta.

Thomas Owens
fonte
Não há necessidade de distinguir entre o terminal e o recurso. Se o URI não encontrou nenhum recursos, por qualquer motivo, o servidor deve retornar 404.
bdsl
Verifique o código de resposta neste site para obter um exemplo de site que está fazendo a coisa certa. É um site, não uma API, mas a mesma especificação http se aplica. softwareengineering.stackexchange.com/questions/266183385
bdsl
@ Bdsl posso dizer que é absolutamente errado. Por exemplo, estou interagindo com um serviço de usuário que pode retornar um perfil de usuário. Digamos que esse terminal seja /usere seja usado como /[email protected]. Como consumidor de API, quero saber se, /userpor algum motivo, não existe no servidor (talvez tenha sido adicionado na v2 da API e o servidor esteja na v1 ou tenha sido renomeado na v3) ou se o usuário com o email [email protected]não existe. O primeiro é um 404, o segundo é um 200 com um corpo que indica nenhum usuário com esse endereço de email.
Thomas Owens
@ Bdsl Isso é bom, mas isso não significa que é certo ou melhor. Também não acho que você possa comparar um site projetado para interação humana por meio de um navegador da Web versus uma API projetada para uso em um sistema de software.
Thomas Owens
11
Este problema é discutido mais adiante na youtube.com/watch?v=nSKp2StlS6s
bdsl