Criando uma aplicação REST com SparkJava

Spark_Java_Logo
SparkJava-Logo

Neste post veremos como podemos utilizar o framework SparkJava para criamos api’s rest rapidamente.

Para esse post criaremos um simples hello-world e um CRUD com as seguintes tecnologias :

Introdução ao SparkJava

SparkJava é um micro framework para criação de aplicações web em Kotlin e Java 8 com mínimo de esforço.

A intenção da Spark é fornecer uma alternativa para os desenvolvedores de Kotlin / Java que desejam desenvolver suas aplicações web tão expressivas quanto possível. Com uma filosofia clara, a Spark foi projetada não só para torná-lo mais produtivo, mas também para melhorar o seu código sob a influência da sintaxe elegante, declarativa e expressiva da Spark.

Com a onda de microservice que a grande maioria utilizar Spring Rest ou até mesmo soluções Java EE com Jersey/RestEasy, o Spark não fica de fora dessa onda, a mesma fornece uma  API REST pronta para atender a JSON em menos de dez linhas de código.

Spark é usado principalmente para criar APIs REST, mas também oferece suporte a uma infinidade de template engines como :

Algo importante a se citar , não confundi com Apache Spark, apesar do mesmo nome, tem objetivos diferentes.

vejamos um simples Hello-World :

import static spark.Spark.*;

public class HelloWorld {
public static void main(String[] args) {
   get("/hello", (req, res) -> "Hello World");
   }
}

agora no navegador basta usar http://localhost:4567/hello e pronto.

Bem feita essa rápida introdução sobre o framework, vamos partir para construção do nosso projeto .

Criando o Projeto

Crie um projeto Maven com seguinte  pom.xml :

 

após criar o projeto, crie dois arquivo xml na pasta “resource/META-INF” conforme mostrado abaixo :

agora daremos inicio na construção das nossas classes,  começaremos pelas classes model :


package br.org.soujava.rio.model;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import lombok.Data;

@Data
@Entity
public class JUG implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nome;
private String leader;
private String descricao;
private String email;
}

e agora a classe que retorna um código e uma mensagem de resposta de sucesso ou erro durante o uso da api :


package br.org.soujava.rio.model;

import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class ResponseModel {

private int codigo;
private String mensagem;
}

agora criaremos duas classes produtoras utilizando o CDI, uma das classe é para o EntityManager – JPA e uma para JSON-B :


package br.org.soujava.rio.produces;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

@ApplicationScoped
public class EntityManagerProducer {

@Produces
public EntityManager criarEntityManager() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("soujava-rio");
return emf.createEntityManager();
}

public void closeEntityManager(@Disposes EntityManager manager) {
manager.close();
 }
}


package br.org.soujava.rio.produces;

import javax.enterprise.inject.Produces;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;

public class JsonBindProduces {

@Produces
public Jsonb createJsonB() {
Jsonb jsonb = JsonbBuilder.create();
return jsonb;
 }
}

aqui fizemos o uso de duas anotações do CDI o @Produces e @ApplicationScope :

  • @ApplicationScoped : mantém a instância durante todo o tempo de execução da aplicação. É um escopo que compartilha os objetos para todos os usuários do sistema.
  • @Produces: Os Producer Methods são apenas métodos que produzem objetos que serão administrados pelo container CDI e injetados em outros objetos.

JSON-B é uma camada de ligação padrão para converter objetos Java em / de mensagens JSON. Ele define um algoritmo de mapeamento padrão para conversão de classes Java existentes para JSON, enquanto permite que os desenvolvedores personalizem o processo de mapeamento através do uso de anotações Java.

JSON-B foi incluída no Java EE 8 e é uma alternativa ao Jackson e Gson.

Com os nossos produtores feitos, faremos a parte de persistência de  dados utilizando o DeltaSpike-Data.

O deltaSpike-Date é uma alternativa ao Spring-Data para fazermos nossas persistência de forma simples e objetiva, conforme pode ser visto abaixo :


package br.org.soujava.rio.repository;

import org.apache.deltaspike.data.api.EntityRepository;
import org.apache.deltaspike.data.api.Repository;

import br.org.soujava.rio.model.JUG;

@Repository
public interface JUGRepository extends EntityRepository { }

em seguida criaremos uma classe uma classe utilitária que ira usar o ResponseTransformer do Spark  que transformam as rotas mapeadas a saída do método do identificador. Isso é feito estendendo o objeto ResponseTransformer e passando para o método de mapeamento. Exemplo de uma rota que transforma a saída para JSON usando o Json-B :


package br.org.soujava.rio.transformer;

import javax.inject.Inject;
import javax.json.bind.Jsonb;

import spark.ResponseTransformer;
public class JsonTransformer implements ResponseTransformer  {

@Inject
private Jsonb jsonb;

@Override
public String render(Object model) throws Exception {
return jsonb.toJson(model);
  }
}

Agora iremos fazer nossa classe Principal para nosso serviços Rest :

esse é a nossa classe principal para executarmos o nosso serviço, como pode ser visto não foi utilizado o metodo main como foi demostrado no exemplo do hello-world, neste caso a aplicação vai ser executada pelo conteiner do CDI, então irei explicar algumas partes do codigo :

Nas linhas 24 a 31 utilizamos a anotação @Inject para injetarmos nossas dependencias.

Na linha 33 temos um metodo chamado main contento uma anotação @Observes e uma classe chamada ContainerInitialized, essa anotação ficara observando ou de olho no evento ContainerInitialized, que será disparada quando a classe org.jboss.weld.environment.se.StartMain for chamada ao iniciar nossa aplicação, esse chamada foi declara no pom.xml na linha 89 .

Logo em seguida na linha 35 declaramos um metodo estatico port() passando o 8080 como a porta a ser utilizada na aplicação que por default é 4567 ,  em seguida tambem declaramos uma chamada de uma classe e o seu metodo estatico que habilita um filtro CORS para nossa aplicação poder ser usada em outros dominios, o conteudo da classe será mostrado depois .

Na linha 38 é onde começamos de fato a nossa api Rest, no SparkJava é chamado de Routes, nossa primeira rota é o Path, assim como no Jax-RS que é o equivalente ao @Path(“”) e no Spring RequestMapping(“”) .

logo depois temos as rotas Post,get,put e delete nas linhas 40 a  75 passando como paramentro o caminho para ser acessado, bem como os callback para request e response.  Como pode ser visto estamos utilizando o lambda do Java, dentro dela temos setado o tipo de conteudo que a api ira responder, no caso setamos para Json.

Em seguida declaramos um objeto JUG que recebe a variavel json.fromJson() do JSON-B para a mesma fazer a serialização de Json para objeto do tipo JUG e dentro desse metodo chamamos o req.body() que é o corpo de solicitação enviado pelo cliente, lego depois esse objeto é salvo no banco de dado H2 e depois retorna uma mensagem e um codigo em Json atraves da classe ResponseModel que foi feita a transformação atraves da chamada do metodo jsonTransformer que foi comentada algumas linhas acima.

isso em JAX-RS seria :


@POST
@Path("/cadastrar")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
	public Response cadastrarJUG(JUG jug) {
		try {
			jugRepository.save(jug);
			return Response.ok().entity(new ResponseModel(1,"JUG Adicionada Com Sucesso!")).build();
		} catch (Exception e) {
			return Response.ok().entity(new ResponseModel(0,e.getMessage())).build();
		}
	}

Na linha 56 tenho um get com parametros para codigo,  que o mesmo é pega utilizando o req.params(“codigo”); , traduzindo isso para Jax-RS é o equivalente a :


@GET
@Path("consultar/{codigo}")
public Response consultarJUG(@PathParam("codigo") Long codigo) {
JUG jug = this.jugRepository.findBy(codigo);
return Response.ok().entity(jug).build();
}

e para finalizar vejamos como fica a classe CorsFilter.enableCORS(); :


package br.org.soujava.rio.filter.cors;

import static spark.Spark.before;
import static spark.Spark.options;

public final class CorsFilter {

	public static void enableCORS() {

		options("/*", (request, response) -> {

			String accessControlRequestHeaders = request.headers("Access-Control-Request-Headers");
			if (accessControlRequestHeaders != null) {
				response.header("Access-Control-Allow-Headers", accessControlRequestHeaders);
			}

			String accessControlRequestMethod = request.headers("Access-Control-Request-Method");
			if (accessControlRequestMethod != null) {
				response.header("Access-Control-Allow-Methods", accessControlRequestMethod);
			}
			return "OK";
		});

		before((request, response) -> {
			response.header("Access-Control-Allow-Origin", "*");
			response.header("Access-Control-Request-Method", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
			response.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
			response.type("application/json");
		});
	}

apos isso podemos fazer build de nossa aplicação com o comando :


mvn clean package

apos isso dentro da pasta target tera o seguinte conteúdo :

spark

a pasta dependency-jars contem as libs que utilizamos no nosso pom.xml, agora basta executar o jar com o comando :


java -jar SparkJava-sample.jar

e fazer o uso conforme mostrado usando o PostMan :

post

também pode fazer uso de algum framework JavaScript como Angula para consumir a api como mostrada na imagem abaixo :

front

Bem isso é tudo, espero que os leitores tenham gostado de conhecer um novo framework para construções de serviços Rest rapidamente como alternativa ao JAX-RS e Spring-Rest.

Código-fonte : https://github.com/SouJava-Rio/soujava-rio-labs/tree/master/spark-samples/CRUD-Deltaspike-CDI-Angular

Front-End : https://github.com/SouJava-Rio/soujava-rio-labs/tree/master/spark-samples/CRUD-Deltaspike-CDI-Angular/app-jug

Imagem Docker : https://hub.docker.com/r/danieldiasjava/sparkjava-crud/

REFERÊNCIAS

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s