API REST com Jersey e Spring

API REST com Jersey e Spring

[.s1] ##

1. Visão geral

Jersey é uma estrutura de software livre para desenvolver RESTful Web Services. Serve como uma implementação de referência do JAX-RS.

Neste artigo,we’ll explore the creation of a RESTful Web Service using Jersey 2. Além disso, usaremos a injeção de dependência (DI) do Spring com configuração Java.

2. Dependências do Maven

Vamos começar adicionando dependências apom.xml:


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


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

Além disso, para integração com Spring, temos que adicionar a dependênciajersey-spring4:


    org.glassfish.jersey.ext
    jersey-spring4
    2.26

A versão mais recente dessas dependências está disponível emjersey-container-servlet,jersey-media-json-jacksonejersey-spring4.

3. Configuração da Web

Next, we need to set up a web project to do Servlet configuration. Para isso, usaremosWebApplicationInitializer do 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");
    }
}

Aqui, estamos adicionando a anotação@Order(Ordered.HIGHEST_PRECEDENCE) para garantir que nosso inicializador seja executado antes do inicializador padrão Jersey-Spring.

4. Um serviço usando Jersey JAX-RS

4.1. Classe de representação de recursos

Vamos usar um exemplo de classe de representação de recursos:

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

    // standard getters and setters
}

Observe que as anotações JAXB como@XmlRootElement são necessárias apenas se o suporte XML for necessário (além de JSON).

4.2. Implementação de Serviço

Vejamos agora como podemos usar anotações JAX-RS para criar serviços da 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. Também podemos incorporar variáveis ​​na sintaxe do URI, como mostra a variável{id}. Em seguida, as variáveis ​​serão substituídas no tempo de execução. Para obter o valor da variável, podemos usar a anotação@PathParam.

@GET, @PUT, @POST, @DELETE and @HEAD define the HTTP method of the request, que será processado por métodos anotados.

The @Produces annotation defines the endpoint’s response type (tipo de mídia MIME). Em nosso exemplo, nós o configuramos para retornar JSON ou XML, dependendo do valor do cabeçalho HTTPAccept (application/json ouapplication/xml).

On the other hand, the @Consumes annotation defines the MIME media types that the service can consume. Em nosso exemplo, o serviço pode consumir JSON ou XML, dependendo do cabeçalho HTTPContent-Type (application/json ouapplication/xml).

A anotação@Context é usada para injetar informações em um campo de classe, propriedade de bean ou parâmetro de método. Em nosso exemplo, estamos usando para injetarUriInfo. Também podemos usá-lo para injetarServletConfig,ServletContext,HttpServletRequesteHttpServletResponse.

5. UsandoExceptionMapper

ExceptionMapper nos permite interceptar as exceções e retornar o código de resposta HTTP apropriado para o cliente. No exemplo a seguir, o código de resposta HTTP 404 será retornado se a exceçãoEmployeeNotFound for lançada:

@Provider
public class NotFoundExceptionHandler
  implements ExceptionMapper {

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

6. Gerenciando classes de recursos

Finalmente,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. Teste de API

Vamos agora testar as APIs com alguns testes ao vivo:

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. Conclusão

Neste artigo, apresentamos a estrutura Jersey e desenvolvemos uma API simples. Usamos Spring para recursos de injeção de dependência. Também vimos o uso deExceptionMapper.

Como sempre, o código-fonte completo está disponível emthis Github project.