No Java, quando pensamos na criação de uma API RESTful a primeira opção que vem a mente é o projeto Spring. Este projeto facilita a criação de APIs REST com o Spring Boot, que é uma das bibliotecas fornecidas por ele. Entretanto, o Java define uma especificação para este tipo de aplicação, a JAX-RS API.
Mesmo não possuindo tanto destaque quanto o Spring Boot, como veremos neste artigo, é bem simples criar uma API REST com a JAX-RS API.
Curso Java - Fundamentos de JAX-WS e JAX-RS
Conhecer o cursoA especificação JAX-RS API
A JAX-RS API trata-se de uma especificação, ela define interfaces e anotações fornecidas pelo Java EE, que podem ser utilizadas na criação de uma API RESTful. Um desenvolvedor pode criar a sua aplicação baseada unicamente nesta especificação, entretanto o usual é fazer uso de uma biblioteca que a implemente.
Entre as bibliotecas existentes, as implementações da JAX-RS API mais conhecidas são RESTEasy e Jersey. Sendo que a mais utilizada é a Jersey, assim neste artigo faremos uso dela.
Então vamos colocar a mão na massa.
Criando a aplicação
Para este artigo irei criar um projeto Maven utilizando o arquétipo jersey-quickstart-grizzly2
, pois este arquétipo já possui o Jersey configurado e fornece embutido o servidor Grizzly.
Pelo terminal, o projeto pode ser criado com o comando abaixo:
mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 \
-DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
-DgroupId=br.com.treinaweb -DartifactId=jaxrsexample -Dpackage=br.com.treinaweb
No arquivo pom.xml haverão as dependências do Jersey:
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
Caso não queira utilizar o Jersey com o Grizzly, você pode substituir a primeira dependência acima pelas abaixo:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
Com o projeto criado e o Jersey configurado, vamos começar a criar a nossa API REST com JAX-RS API.
Criando uma entidade e repositório
Este exemplo será um CRUD simples, mas para isso necessitamos de uma entidade, que será representada pela classe abaixo:
public class Pessoa {
private int id;
private String nome;
private int idade;
public int getId() {
return id;
}
public int getIdade() {
return idade;
}
public void setIdade(int idade) {
this.idade = idade;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public void setId(int id) {
this.id = id;
}
}
Esta aplicação não lidará com um banco de dados, assim o repositório utilizará um hashmap na memória:
public class PessoaRepository {
private final static HashMap<Integer, Pessoa> pessoas = new HashMap<>();
public List<Pessoa> GetAll(){
return new ArrayList<Pessoa>(pessoas.values());
}
public Pessoa Get(final int id) {
return pessoas.get(id);
}
public void Add(final Pessoa pessoa) {
if(pessoa.getId() == 0 )
pessoa.setId(generateId(pessoas.size() + 1));
pessoas.put(pessoa.getId(), pessoa);
}
public void Edit(final Pessoa pessoa) {
pessoas.remove(pessoa.getId());
pessoas.put(pessoa.getId(), pessoa);
}
public void Delete(final int id) {
pessoas.remove(id);
}
private int generateId(final int possible)
{
if(pessoas.containsKey(possible))
return generateId(possible + 1);
return possible;
}
}
Agora podemos criar o nosso recurso.
Recursos
No Jersey os endpoints são chamados de recursos. Um recurso nada mais é que uma classe que contém a anotação @Path
:
import javax.ws.rs.Path;
@Path("/pessoa")
public class PessoaResource {
}
Como é possível notar no código acima, a anotação @Path
é utilizada para indicar um caminho. Ao defini-lo na classe, significa que este será o nosso endpoint. Dentro dela, definimos métodos que representam os verbos HTTP, onde cada método deverá conter a anotação equivalente ao verbo que o invocará:
-
@DELETE
=DELETE
; -
@GET
=GET
; -
@HEAD
=HEAD
; -
@OPTIONS
=OPTIONS
; -
@POST
=POST
; -
@PUT
=PUT
; -
@PATCH
=PATCH
.
Neste nosso endpoint não utilizaremos todas essas anotações, apenas as equivalentes aos principais verbos: DELETE
, GET
, POST
e PUT
.
Ao realizar este procedimento, a classe ficará com o seguinte código:
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import br.com.treinaweb.model.Pessoa;
import br.com.treinaweb.repositories.PessoaRepository;
@Path("/pessoa")
public class PessoaResource {
private PessoaRepository _repositorio = new PessoaRepository();
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Pessoa> get() {
return _repositorio.GetAll();
}
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Pessoa getById(@PathParam("id") int id) {
return _repositorio.Get(id);
}
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response post(Pessoa pessoa)
{
try{
_repositorio.Add(pessoa);
return Response.status(Response.Status.CREATED).entity(pessoa).build();
}
catch(Exception ex)
{
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
}
}
@PUT
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response put(@PathParam("id") int id, Pessoa pessoa)
{
Pessoa p = _repositorio.Get(id);
if(p == null)
return Response.status(Response.Status.NOT_FOUND).build();
try{
pessoa.setId(id);
_repositorio.Edit(pessoa);
return Response.status(Response.Status.OK).entity(pessoa).build();
}
catch(Exception ex)
{
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
}
}
@DELETE
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response delete(@PathParam("id") int id)
{
Pessoa p = _repositorio.Get(id);
if(p == null)
return Response.status(Response.Status.NOT_FOUND).build();
try{
_repositorio.Delete(id);
return Response.status(Response.Status.OK).build();
}
catch(Exception ex)
{
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
}
}
}
Repare que os métodos também definem o tipo de conteúdo que irão produzir/retornar:
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Pessoa> get() {
return _repositorio.GetAll();
}
E o tipo que irão consumir:
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response post(Pessoa pessoa)
{
try{
_repositorio.Add(pessoa);
return Response.status(Response.Status.CREATED).entity(pessoa).build();
}
catch(Exception ex)
{
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
}
}
O Jersey se encarregará de converter o objeto retornado para JSON e o JSON recebido para o tipo do objeto indicado. Mas para que esta a conversão seja possível, é necessário definir a dependência abaixo (caso não esteja definida):
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-binding</artifactId>
</dependency>
Pronto, a nossa aplicação já pode ser utilizada.
Testando a aplicação
Caso esteja acompanhando este artigo e se o seu projeto foi criado com base o arquetipo jersey-quickstart-grizzly2
, você pode compilar os códigos pelo Maven:
mvn clean compile
E executar o servidor embutido da aplicação:
mvn exec:java
Indiferente da forma que a aplicação é executada, poderemos interagir com o nosso endpoint:
POST:
GET:
PUT:
GET ID:
DELETE:
Curso Java - Stream API
Conhecer o cursoConclusão
A JAX-RS API é uma poderosa especificação que pode ser aplicada em uma aplicação facilmente graças a implementação do Jersey, se tornando uma ótima alternativa para o Spring Boot.
Desta forma, caso necessite criar uma aplicação RESTfull API no Java, não deixe de dar uma olhada nos recursos fornecidos pela JAX-RS API e o Jersey.
Você pode baixar a aplicação deste artigo no meu Github.