Est-il correct de renvoyer 404 lorsqu'une ressource REST n'est pas trouvée?
Disons que j'ai une simple ressource Jersey REST comme suit:
@Path("/foos")
public class MyRestlet
extends BaseRestlet
{
@GET
@Path("/{fooId}")
@Produces(MediaType.APPLICATION_XML)
public Response getFoo(@PathParam("fooId") final String fooId)
throws IOException, ParseException
{
final Foo foo = fooService.getFoo(fooId);
if (foo != null)
{
return Response.status(Response.Status.OK).entity(foo).build();
}
else
{
return Response.status(Response.Status.NOT_FOUND).build();
}
}
}
Sur la base du code ci-dessus, est-il correct de renvoyer un statut NOT_FOUND
(404
), ou devrais-je renvoyer 204
, ou un autre code plus approprié?
Merci D'avance!
3 réponses
Une réponse 404 dans ce cas est assez typique et facile à consommer pour les utilisateurs de L'API.
Un problème est qu'il est difficile pour un client de dire s'il a obtenu un 404 parce que l'entité particulière n'est pas trouvée, ou en raison d'un problème structurel dans L'URI. Dans votre exemple, /foos/5
peut renvoyer 404 car le foo avec id = 5 n'existe pas. Cependant, /food/1
retournerait 404 même si foo avec id=1
existe (parce que foos
est mal orthographié). En d'autres termes, 404 signifie soit un URI mal construit ou une référence à une ressource inexistante.
Un autre problème se pose lorsque vous avez un URI qui référence plusieurs ressources. Avec une simple réponse 404, le client n'a aucune idée de laquelle des ressources référencées n'a pas été trouvée.
Ces deux problèmes peuvent être partiellement atténués en renvoyant des informations supplémentaires dans le corps de réponse pour permettre à l'appelant de savoir exactement ce qui n'a pas été trouvé.
Oui, il est assez courant de renvoyer 404 pour une ressource introuvable. Tout comme une page web, quand elle n'est pas trouvée, vous obtenez un 404. Ce N'est pas seulement REST, mais une norme HTTP.
Chaque ressource doit avoir un emplacement URL. Les URL n'ont pas besoin d'être statiques, elles peuvent être templated. Il est donc possible que l'URL demandée réelle n'ait pas de ressource. Il est du devoir du serveur de décomposer L'URL du modèle pour rechercher la ressource. Si ils ressource n'existe pas, alors il est "Non Trouvé"
Voici la spécification HTTP 1.1
404 Non Trouvé
Le serveur n'a rien trouvé correspondant à L'URI de requête. Aucune indication n'est donnée si la condition est temporaire ou permanente. Le code d'état 410 (Gone) doit être utilisé si le serveur sait, via un mécanisme configurable en interne, qu'une ancienne ressource est définitivement indisponible et n'a pas d'adresse de transfert. Ce code d'état est couramment utilisé lorsque le serveur ne souhaite pas révéler exactement pourquoi la demande a été refusée, ou si aucune réponse n'est applicable.
Voici pour 204
204 Pas De Contenu
Le serveur a rempli la requête mais n'a pas besoin de renvoyer un corps d'entité et peut vouloir renvoyer des méta-informations mises à jour. La réponse peut inclure des méta-informations nouvelles ou mises à jour sous la forme d'en-têtes d'entité, qui, s'ils sont présents, doivent être associés demandé variante.
Si le client est un agent utilisateur, il ne doit pas modifier la vue du document par rapport à celle qui a provoqué l'envoi de la requête. Cette réponse est principalement destinée à permettre l'entrée d'actions sans provoquer de modification de la vue active du document de l'agent utilisateur, bien que toute métainformation nouvelle ou mise à jour doit être appliquée au document actuellement dans la vue active de l'agent utilisateur.
La réponse 204 ne doit pas inclure un corps de message, et toujours terminé par la première ligne vide après les champs d'en-tête.
Normalement, 204 serait utilisé lorsqu'une représentation a été mise à jour ou créée et qu'il n'est pas nécessaire d'envoyer un corps de réponse. Dans le cas d'une publication, vous pouvez renvoyer uniquement l'emplacement de la ressource nouvellement créée. Quelque chose comme
@POST
@Path("/something")
@Consumes(...)
public Response createBuzz(Domain domain, @Context UriInfo uriInfo) {
int domainId = // create domain and get created id
UriBuilder builder = uriInfo.getAbsolutePathBuilder();
builder.path(Integer.toString(domainId)); // concatenate the id.
return Response.created(builder.build()).build();
}
Le {[1] } renvoie la réponse avec L'URI nouvellement créé dans l'en-tête Location
.
Ajouter à la première partie. Vous avez juste besoin de garder à l'esprit que chaque demande d'un client est une demande d'accès à une ressource, que ce soit juste pour L'obtenir ou pour la mettre à jour avec PUT. Et une ressource peut être n'importe quoi sur le serveur. Si la ressource n'existe pas, alors une réponse générale serait de dire au client que nous ne pouvons pas trouver cette ressource.
Pour développer votre exemple. Disons que FooService
accsse la base de données. Chaque ligne de la base de données peut être considérée comme une ressource. Et chacune de ces lignes (ressources) a une URL unique, comme {[4] } peut localiser une ligne avec une la touche 1. Si l'id ne peut pas être trouvé, alors que ressource est "introuvable"
Un code d'erreur 4XX
signifie une erreur du côté client.
Lorsque vous demandez une ressource statique sous la forme d'une image ou d'une page html,404
réponse a du sens comme:
Le code de réponse d'erreur client HTTP 404 Not Found indique que le le serveur ne trouve pas la ressource demandée. Liens qui mènent à un 404 page sont souvent appelés liens cassés ou morts, et peuvent être soumis à lien pourriture.
Comme vous fournissez aux clients des méthodes REST, vous comptez sur les méthodes HTTP, mais vous ne devriez pas considérer les services REST comme de simples ressources.
Pour les clients, une réponse d'erreur dans la méthode REST est souvent traitée à proximité des erreurs d'autres traitements.
Par exemple, pour détecter les erreurs lors des invocations REST ou ailleurs, les clients peuvent utiliser catchError()
de RxJS.
Nous pourrions écrire un code (en TypeScript / Angular 2 pour l'exemple de code) de cette façon pour déléguer le traitement des erreurs à une fonction :
return this.http
.get<Foo>("/api/foos")
.pipe(
catchError(this.handleError)
)
.map(foo => {...})
Le problème est que toute erreur HTTP (5XX ou 4XXX) se terminera dans le rappel catchError()
.
Cela peut vraiment rendre les réponses de L'API REST trompeuses pour les clients.
Si nous faisons un parallèle avec le langage de programmation, nous pourrions considérer 5XX / 4XX comme un flux d'exception.
Généralement, nous ne lançons pas une exception uniquement parce qu'une donnée n'est pas trouvée, NOUS LA lançons car une donnée n'est pas trouvée et que cette donnée aurait été trouvée .
Pour L'API REST, nous devrions suivre le même logique.
Si l'entité peut ne pas être trouvée, renvoyer OK
dans les deux cas est parfaitement bien:
@GET
@Path("/{fooId}")
@Produces(MediaType.APPLICATION_XML)
public Response getFoo(@PathParam("fooId") final String fooId)
throws IOException, ParseException {
final Foo foo = fooService.getFoo(fooId);
if (foo != null){
return Response.status(Response.Status.OK).entity(foo).build();
}
return Response.status(Response.Status.OK).build();
}
Le client pourrait ainsi gérer le résultat en fonction du résultat est présent ou manquant.
Je ne pense pas que le retour de 204
apporte une valeur utile.
la documentation HTTP 204
indique que:
Le client n'a pas besoin de quitter sa page actuelle.
Mais demande une ressource REST et plus encore en particulier, une méthode GET ne signifie pas que le client est sur la fin d'un flux de travail (cela a plus de sens avec les méthodes POST/PUT).
Le document ajoute également:
Le cas d'utilisation courant est de retourner 204 à la suite d'une requête PUT, mise à jour d'une ressource, sans modifier le contenu actuel de la page affiché à l'utilisateur.
Nous ne sommes vraiment pas dans ce cas.
Quelques codes HTTP spécifiques pour la navigation classique matche finement avec codes de retour de L'API REST (201, 202, 401, et ainsi de suite...), mais ce n'est pas toujours le cas.
Donc, pour ces cas, plutôt que de tordre les codes originaux, je préférerais les garder simples en utilisant des codes plus généraux: 200
, 400
.