Skip to content

Date archive for: mai 2015

Service ReST et création de ressource POST/PUT

Consommer des services ReST est devenu monnaie courante, mais la création de ressources avec un tel service nécessite de se poser quelques questions. (attention, je ne réinvente pas la roue : je cherche juste à rassembler les informations nécessaires pour se lancer)

Création de ressource : POST ou PUT ?

Première question : je crée une ressource, c’est donc avec un PUT, non ?

Eh bien, oui et non, tout dépend de l’élément responsable de la création de l’identifiant de votre ressource.

Le client fournit l’identifiant de la ressource ? Il s’agit d’un PUT

Dans le cas d’un PUT, l’URI doit spécifier directement l’identifiant de la ressource à créer.
Exemple :

$ curl -XPUT 'http://localhost:8080/restservice/resources/42' -d '{
    "name" : "mabelleresource"
}'

Le serveur fournit l’identifiant ? Il s’agit d’un POST

S’il s’agit d’un POST, c’est à la charge du serveur de donner l’identifiant.

Exemple :

$ curl -XPOST 'http://localhost:8080/restservice/resources' -d '{
    "name" : "mabelleresource"
}'

Mais ? Où est-il cet identifiant ? Eh bien … dans la réponse retournée par le serveur (et notamment par Location: qui donne l’emplacement de la ressource)

HTTP/1.1 201 - Created
Server: Pouet server v.1.02
Location: http://localhost:8080/restservice/resources/42
...
{
    "id" : "42",
    "name" : "mabelleresource"
}

Contenu de la réponse : et si on était un peu exhaustif ?

Dans la réponse à la création d’une ressource, plusieurs champs peuvent être très utiles :

  • Location, comme vu précédemment indique l’URI de la ressource
  • L’ETag de cette version de la ressource, permettant au client de mettre la donnée en cache
  • Le Content-Type et le contenu de la ressource permettant de confirmer l’id de la ressource et d’obtenir sa structure interne

Et il est très simple de fournir ces informations. Par exemple, en JAX-RS :

@Context
UriInfo uriInfo;
...

@PUT
@Path("{id}")
@Consumes("application/json")
public Response addResource(@PathParam("id") String id, Data inputdata) {
  ...
  return Response.created(uriInfo.getRequestUri())
          .tag(Integer.toString(newResource.hashCode()))
          .entity(newResource)
          .type(MediaType.APPLICATION_JSON_TYPE)
          .build();
}

Ok … et si je veux gérer correctement le ETag ?

Alors, il faut gérer la vérification de ce ETag pour déterminer si les données doivent être fournies à nouveau au client (le client fournissant la valeur à tester via le header « If-None-Match »).

Heureusement, l’objet Request prend en charge une partie de la vérification via la méthode evaluatePreconditions.

Si le ResponseBuilder retourné est null, alors on doit retourner une nouvelle resource. Sinon, ce même ResponseBuilder est utilisable directement.

Exemple d’utilisation :

    @GET
    @Path("{id}")
    public Response getApp(@PathParam("id") String id, @Context Request request) {
        Data resource = fetchData(id);
        EntityTag etag = new EntityTag(Integer.toString(resource.hashCode()));
        Response.ResponseBuilder builder = request.evaluatePreconditions(etag);

        if (builder == null) {
            builder = Response.ok(resource);
            builder.tag(etag);
        }
        return builder.build();
    }

Voilà, vous avez une bonne base de départ pour créer correctement vos ressources ReST. Bon code ! :)