Dois-je retourner une réponse 204 ou 404 lorsqu'une ressource n'est pas trouvée?

15

Je développe un service RESTful simple pour les tournois et les horaires. Lorsqu'un tournoi est créé via une requête POST contenant un corps JSON, le tournoi est inséré dans un BiMap, déclaré comme suit dans une implémentation DAO:

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

Lorsqu'un tournoi est créé, son identifiant de chaîne associé est renvoyé afin que l' utilisateur puisse avoir une référence future de ce tournoi. Il / elle peut obtenir des informations du nouveau tournoi en effectuant la demande suivante:

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

Mais que se passe-t-il si aucun tournoi avec un tel identifiant n'est trouvé? Jusqu'à présent, je retourne une réponse 204. Eh bien, Jersey le fait pour moi en revenant nulld'une de ses méthodes. C'est la méthode qui correspond à l'itinéraire ci-dessus:

@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;
}

Ma question est: est-il correct de renvoyer une 204: No Contentréponse, ou devrait-il plutôt être une 404réponse, car la ressource n'a pas été trouvée?

Si je devais le changer en 404, question évidente: devrais-je changer la signature de la méthode non? Etant donné que maintenant un tournoi (de type Tournament) peut ne pas être retourné, la méthode devrait être différente. Dois-je Responseplutôt utiliser le type comme type de retour?

dabadaba
la source

Réponses:

32

HTTP 204signifie que quelque chose a été trouvé, mais il est vide. Par exemple, imaginez que vous diffusez des fichiers journaux via HTTP, avec des requêtes telles que http://example.com/logs/[date-goes-here] . Le 18 mai 2015:

  • http://example.com/logs/2015-05-19 reviendrait HTTP 404, ce qui signifie qu'il n'y a pas de journaux, car, eh bien, il est difficile de journaliser l'avenir.

  • http://example.com/logs/2015-05-18 , cependant, retournerait soit HTTP 200avec les entrées de journal dans le contenu de la réponse, soit HTTP 204si le fichier journal a été créé, mais aucun journal n'a encore été enregistré pour cette Date.

Si vous fournissez nullau framework en réponse à une demande, il suppose que vous avez trouvé une entrée, et cette entrée est donc vide HTTP 204. Au lieu de cela, vous devez throw new NotFoundException();indiquer au framework que l'entrée n'existe pas, afin qu'elle génère un HTTP 404.

Si je devais le changer en 404, question évidente: devrais-je changer la signature de la méthode non?

Non, non. C'est la bonne chose throw new NotFoundException();. Cela fonctionnera quel que soit le type de retour réel de votre méthode.

Arseni Mourzenko
la source
5
Prenez note de la RFC 2616 . 204 réponses ne sont conformes aux spécifications que si vous omettez complètement le corps du message. Dans une certaine mesure, l'intérêt d'une réponse 204 est de dire: «non, ce n'est pas un accident si je n'ai renvoyé aucun contenu». Pour développer l'exemple de MainMa: Si un outil de recherche de journal crache des fichiers texte (par exemple, une fine enveloppe autour des fichiers journaux qui crache simplement le fichier journal tel quel), un 204 serait approprié pour un fichier journal vide. Si la réponse était un objet JSON vide (par exemple, {content: ''}), une réponse 204 serait inappropriée.
Brian
" car, eh bien, il est difficile d'enregistrer l'avenir. " - Ce bit dépend d'une date arbitraire; pourquoi ne pas en faire quelque chose qui n'oblige pas le lecteur à prétendre que ce n'est pas le cas aujourd'hui? Peut-être qu'utiliser 2015-02-29serait mieux, puisque c'est une date qui n'existe pas du tout?
Fund Monica's Lawsuit
1

Votre demande est GET http://localhost:8080/eventscheduler/c15268ce-474a-49bd-a623-b0b865386f39.

Si http://localhost:8080/eventscheduler/n'existe pas en tant que point de terminaison, vous devez renvoyer un 404. Vous essayez d'accéder à une ressource ( /eventscheduler/) qui n'existe pas. Cela indiquerait à un client qu'un serveur existe localhost:8080, mais il n'y a rien au niveau du eventschedulerpoint de terminaison.

S'il http://localhost:8080/eventscheduler/existe en tant que point de terminaison mais que les ressources requises ne sont pas disponibles, une erreur 5xx est appropriée. Un bon exemple de cela serait si une base de données est hors ligne, où vous pouvez renvoyer un 503. Bien sûr, vous pouvez simplement renvoyer une erreur générique 500 au lieu d'une instance spécifique.

S'il http://localhost:8080/eventscheduler/existe mais que la chose représentée par c15268ce-474a-49bd-a623-b0b865386f39n'existe pas, je retournerais un 200 avec un corps indiquant les détails. Le point de terminaison existe, la demande effectuée était totalement valide et pouvait être traitée, mais il n'y avait aucune correspondance.

Si la demande de votre client au point de terminaison n'était pas valide, vous examineriez les autres erreurs 4xx. Vous pouvez indiquer que le client n'est pas autorisé à accéder au point de terminaison ou aux éléments demandés avec un 401 ou 403 ou pouvez utiliser un 400 pour indiquer que la demande n'est pas valide. Avec n'importe lequel de ces éléments, des informations supplémentaires peuvent être fournies dans le corps de réponse.

Thomas Owens
la source
Il n'est pas nécessaire de faire la distinction entre le point de terminaison et la ressource. Si l'URI ne correspond à aucune ressource, quelle qu'en soit la raison, le serveur doit renvoyer 404.
bdsl
Vérifiez le code de réponse sur ce site pour un exemple d'un site qui fait la bonne chose. C'est un site Web, pas une API, mais la même spécification http s'applique. softwareengineering.stackexchange.com/questions/266183385
bdsl
@bdsl Je peux vous dire que c'est absolument faux. Par exemple, j'interagis avec un service utilisateur qui peut renvoyer un profil utilisateur. Disons que ce point de terminaison est /useret est utilisé comme /[email protected]. En tant que consommateur d'API, je veux savoir si, /userpour une raison quelconque, n'existe pas sur le serveur (peut-être qu'il a été ajouté dans la v2 de l'API et que le serveur est dans la v1 ou il a été renommé dans la v3) ou si l'utilisateur avec l'e-mail [email protected]n'existe pas. Le premier est un 404, le second est un 200 avec un corps qui n'indique aucun utilisateur avec cette adresse e-mail.
Thomas Owens
@bdsl C'est bien, mais cela ne veut pas dire que c'est juste ou meilleur. Je ne pense pas non plus que vous puissiez comparer un site Web conçu pour une interaction humaine via un navigateur Web avec une API conçue pour être utilisée dans un système logiciel.
Thomas Owens
1
Ce problème est abordé plus en détail dans youtube.com/watch?v=nSKp2StlS6s
bdsl