API REST avec Jersey et Spring

API REST avec Jersey et Spring

[.s1] ##

1. Vue d'ensemble

Jersey est un framework open source pour le développement de services Web RESTful. Il sert d'implémentation de référence de JAX-RS.

Dans cet article,we’ll explore the creation of a RESTful Web Service using Jersey 2. Nous utiliserons également l’injection de dépendances (DI) de Spring avec la configuration Java.

2. Dépendances Maven

Commençons par ajouter des dépendances auxpom.xml:


    org.glassfish.jersey.containers
    jersey-container-servlet
    2.26


    org.glassfish.jersey.media
    jersey-media-json-jackson
    2.26

De plus, pour l'intégration Spring, nous devons ajouter la dépendancejersey-spring4:


    org.glassfish.jersey.ext
    jersey-spring4
    2.26

La dernière version de ces dépendances est disponible àjersey-container-servlet,jersey-media-json-jackson etjersey-spring4.

3. Configuration Web

Next, we need to set up a web project to do Servlet configuration. Pour cela, nous utiliserons lesWebApplicationInitializer de Spring:

@Order(Ordered.HIGHEST_PRECEDENCE)
public class ApplicationInitializer
  implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext)
      throws ServletException {

        AnnotationConfigWebApplicationContext context
          = new AnnotationConfigWebApplicationContext();

        servletContext.addListener(new ContextLoaderListener(context));
        servletContext.setInitParameter(
          "contextConfigLocation", "com.example.server");
    }
}

Ici, nous ajoutons l'annotation@Order(Ordered.HIGHEST_PRECEDENCE) pour nous assurer que notre initialiseur est exécuté avant l'initialiseur par défaut de Jersey-Spring.

4. Un service utilisant Jersey JAX-RS

4.1. Classe de représentation des ressources

Utilisons un exemple de classe de représentation de ressources:

@XmlRootElement
public class Employee {
    private int id;
    private String firstName;

    // standard getters and setters
}

Notez que les annotations JAXB telles que@XmlRootElement ne sont requises que si la prise en charge XML est nécessaire (en plus de JSON).

4.2. Mise en œuvre des services

Voyons maintenant comment nous pouvons utiliser les annotations JAX-RS pour créer des services Web RESTful:

@Path("/employees")
public class EmployeeResource {

    @Autowired
    private EmployeeRepository employeeRepository;

    @GET
    @Path("/{id}")
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Employee getEmployee(@PathParam("id") int id) {
        return employeeRepository.getEmployee(id);
    }

    @POST
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Response addEmployee(
      Employee employee, @Context UriInfo uriInfo) {

        employeeRepository.addEmployee(new Employee(employee.getId(),
          employee.getFirstName(), employee.getLastName(),
          employee.getAge()));

        return Response.status(Response.Status.CREATED.getStatusCode())
          .header(
            "Location",
            String.format("%s/%s",uriInfo.getAbsolutePath().toString(),
            employee.getId())).build();
    }
}

The @Path annotation provides the relative URI path to the service. Nous pouvons également incorporer des variables dans la syntaxe URI, comme le montre la variable{id}. Ensuite, les variables seront substituées à l'exécution. Pour obtenir la valeur de la variable, nous pouvons utiliser l'annotation@PathParam.

@GET, @PUT, @POST, @DELETE and @HEAD define the HTTP method of the request, qui sera traité par des méthodes annotées.

The @Produces annotation defines the endpoint’s response type (type de support MIME). Dans notre exemple, nous l'avons configuré pour renvoyer JSON ou XML en fonction de la valeur de l'en-tête HTTPAccept (application/json ouapplication/xml).

On the other hand, the @Consumes annotation defines the MIME media types that the service can consume. Dans notre exemple, le service peut consommer JSON ou XML en fonction de l'en-tête HTTPContent-Type (application/json ouapplication/xml).

L'annotation@Context est utilisée pour injecter des informations dans un champ de classe, une propriété de bean ou un paramètre de méthode. Dans notre exemple, nous l'utilisons pour injecterUriInfo. On peut aussi l'utiliser pour injecterServletConfig,ServletContext,HttpServletRequest etHttpServletResponse.

5. Utilisation deExceptionMapper

ExceptionMapper nous permet d'intercepter les exceptions et de renvoyer le code de réponse HTTP approprié au client. Dans l'exemple suivant, le code de réponse HTTP 404 est renvoyé si l'exceptionEmployeeNotFound est levée:

@Provider
public class NotFoundExceptionHandler
  implements ExceptionMapper {

    public Response toResponse(EmployeeNotFound ex) {
        return Response.status(Response.Status.NOT_FOUND).build();
    }
}

6. Gestion des classes de ressources

Enfin,let’s wire up all service implementation classes and exception mappers against an application path:

@ApplicationPath("/resources")
public class RestConfig extends Application {
    public Set> getClasses() {
        return new HashSet>(
          Arrays.asList(
            EmployeeResource.class,
            NotFoundExceptionHandler.class,
            AlreadyExistsExceptionHandler.class));
    }
}

7. Test d'API

Testons maintenant les API avec des tests en direct:

public class JerseyApiLiveTest {

    private static final String SERVICE_URL
      = "http://localhost:8082/spring-jersey/resources/employees";

    @Test
    public void givenGetAllEmployees_whenCorrectRequest_thenResponseCodeSuccess()
      throws ClientProtocolException, IOException {

        HttpUriRequest request = new HttpGet(SERVICE_URL);

        HttpResponse httpResponse = HttpClientBuilder
          .create()
          .build()
          .execute(request);

        assertEquals(httpResponse
          .getStatusLine()
          .getStatusCode(), HttpStatus.SC_OK);
    }
}

8. Conclusion

Dans cet article, nous avons présenté le framework Jersey et développé une API simple. Nous avons utilisé Spring pour les fonctionnalités d'injection de dépendances. Nous avons également vu l'utilisation deExceptionMapper.

Comme toujours, le code source complet est disponible enthis Github project.