GraphQL e REST de forma simples com o Java Spring Boot
A proposta deste artigo é de apresentar o poder do Spring Boot aplicado a duas arquiteturas de comunicação de APIs, o REST e GraphQL. Neste artigo vamos criar um projeto que irá conter as duas tecnologias e mostrar como configurá-las.
Então sem mais delongas, vamos lá!
REST API
De acordo com o Wikipédia, eis uma ótima definição sobre REST API:
Representational State Transfer, em português Transferência Representacional de Estado, é um estilo de arquitetura de software que define um conjunto de restrições a serem usadas para a criação de web services.
A proposta de uma arquitetura com REST API, coloca em uso os verbos do protocolo HTTP para transição das requisições de um software.
Hum…. legal, esta abordagem atualmente é difundida na maioria dos projetos de softwares existentes no mercado. Cada verbo do HTTP assume uma dada função de comunicação com uma aplicação. Exemplo, requisições via verbo GET são aplicados para consulta de dados, POST para persistência, PUT para atualização de dados e o DELETE para exclusão.
Como último item, o JSON é padrão de comunicação em cada uma das chamadas de requisição.
GraphQL
Quando o Facebook, desenvolveu o adotou como uma linguagem de consulta e manipulação dentro de suas aplicações, análogo ao SQL. A sua proposta é permitir que o front consiga ter a liberdade de formatar os dados que ele necessita, tornando dinâmica a consulta de dados em uma API.
O GraphQL de uma forma geral está dividido entre Types, Query, Resolvers e Mutation.
Não irei entrar em detalhes sobre os conceitos que circundam o GraphQL, recomendo a leitura do artigo Evandro F. Souza, no link:
https://medium.com/trainingcenter/graphql-os-dados-no-formato-requisitado-964f5555d467
Para aqueles que quiserem se aprofundar no assunto recomendo também a leitura do livro na casa do código.
Spring Boot e seus starters
Ahhhhh o Spring Boot, sou novo no Universo (sim é um Universo e vasto!!!) Java e de cara me deparei com o Spring Boot e seus starters.
O Spring já é um framework famoso na comunidade Java e a proposta do Spring Boot e seus starters, permitiram qualquer desenvolvedor começasse a desenvolver de forma rápida e eficiente. Tudo isso graças ao Spring Initialzr, que com poucos clicks constrói um projeto pronto para desenvolvimento.
Existem starters para os mais diversos tipos de projetos. Hibernate, MongoDB, Webflux, Kafka, Rabbit e etc. E claro a comunidade desenvolveu um starter para o GraphQL, esse é assunto para o tópico a seguir.
GraphQL Starter
O projeto GraphQL Starter, até o final da escrita deste artigo, está mantido no site:
https://www.graphql-java-kickstart.com/
A proposta do starter é de diminuir a complexidade do GraphQL Java Tools, particularmente é bem verboso. Ele contém todas as configurações e instruções para criação de um projeto, além claro de exemplos (vários exemplos).
Basicamente vamos precisar de dois pacotes no core para criar uma instância do projeto.
graphql-spring-boot-starter: É o módulo de integração com o Spring Boot;
graphql-java-tools: São ferramentas de manipulação do GraphQL;
Além desses pacotes temos seu módulo de teste (graphql-spring-boot-starter-test) e as ferramentas de playgroung.
Um ponto importante são as ferramentas de playground que podem ser integradas no projeto, são inúmeras ferramentas que podem ser integradas no projeto, vou deixar link de cada uma das ferramentas:
GraphiQL, https://github.com/graphql/graphiql;
Altair, https://altair.sirmuel.design/;
GraphQL Playground, https://github.com/graphql/graphql-playground (vamos usar essa no nosso projeto prático);
Agora sim, depois de toda essa apresentação, vamos por a mão na massa.
Mão na massa
Nessa prática vamos criar um projeto simples, uma API que opere em modo REST e GraphQL. Essa API retorna os dados de uma empresa. A proposta é apresentar as duas metodologias e ver suas diferenças.
Primeiro passo, criar o projeto.
Criando projeto
Sendo bem prático vamos olhar e entender o GIF abaixo:
Vamos lá item a item:
- No lado esquerdo onde vemos a informações Project, Language e Spring Boot, mantenha as configurações padrões;
- Em Project Metadata você tem total liberdade para alterar o que achar de mais interessante, basta seguir o padrão;
- Na penúltima opção, a Packaging mantenha o Jar;
- Na última opção do lado esquerdo, onde definimos a versão do Java recomendo usar a versão 8;
- Agora do lado direito, onde selecionamos as dependências, adicione conforme a imagem.
Se você fez tudo certinho agora é clicar no Generate e fazer o download.
Abra o projeto na sua IDE predileta, neste exemplo vamos usar Intellij Community. Sinta-se à vontade para usar outra.
Só um lembre, não vamos nos preocupar com configurações de IDE, vamos ser bem diretos e objetivos…
REST API
Vamos estruturar nosso projeto 5 pacotes secundários ao principal, conforme a imagem abaixo:
Nesse primeiro momento ignorem o pacote resolver. Mas vamos lá explicar pacote a pacote;
- Controller: Armazenar todos os controladores da aplicação. Ele vai criar nosso endpoint para a API Rest;
- Factory: Todas as fábricas do projeto, neste caso vamos criar um fábrica para prover dados para a camada Service;
- Model: Ahhhh nosso pacote de Modelos, a representação computacional da nossa Empresa;
- Service: Por último, a camada service é responsável por concentrar as regras de negócio e prover informações para os controladores;
Tudo bem organizadinho…
Vamos conhecer classe a classe de dentro pra fora, neste caso na seguinte ordem: Model, Factory, Service e Controller
Model e a classe Empresa
Bem simples e objetiva. Só uma coisa bem show de bola, percebam que não temos Get e Set nas classes. No cabeçalho da classe temos um anotações, elas são responsáveis por fazer isso. Tudo isso é responsabilidade do Lombok (https://projectlombok.org/).
Factory e a classe EmpresaFactory
O método createListEmpresa entrega uma lista de empresas prontinha para a camada Service.
Em especial essa classe tem um @Component no seu cabeçalho. Esse cara é importante para o Spring Boot, são anotações especiais utilizadas pelo DI (Injeção de dependências) do framework. Na classe a frente vamos observar o processo de injeção ocorrendo de forma "automágica".
Service e a classe EmpresaService
O método findAll vai pedir para fábrica criar uma lista de empresas. Isso será útil no nosso controlador.
Ei, olhem uma coisa legal! Eu não instanciei a Factory, mas percebam que acima da sua declaração tem um @Autowired. Essa instrução é responsável por "injetar" a instância do objeto em tempo de execução.
Controller e a classe EmpresaController
Aqui o controlador vai retornar no formato JSON com a lista de empresas.
Até aqui nós criamos um serviço REST que terá o resultado idêntico ao da imagem abaixo:
Para acessar essa URL, o endpoint criado foi o "http://localhost:8080/empresas".
GraphQL
Agora vamos para a implementação usando GraphQL. Vamos reaproveitar a mesma ideia do projeto e aplicar a camada do GraphQL.
Serão 4 passos, sendo eles:
- Edição do pom.xml;
- Alteração do arquivo application.properties ou aplication.yml;
- Criação do schema.graphqls;
- Criação do resolver.
Edição do pom.xml
Abra o seu pom.xml e adicione as seguintes linhas na chave </dependencies>:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>7.1.0</version>
</dependency>
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>6.2.0</version>
</dependency>
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>playground-spring-boot-starter</artifactId>
<version>8.0.0</version>
</dependency>
Tenha atenção para as versões. Na época deste artigo utilizei as versões acima, pode ser que quando você estiver lendo este artigo algo tenha sido modificado. É sempre bom verificar no repositório do Maven se houve alteração.
Alteração do arquivo application.properties ou aplication.yml
Abra seu arquivo application.properties ou application.yml, eu uso no padrão yml. Adicione as seguintes configurações:
server:
port: 8080
graphql:
servlet:
mapping: /graphql
enabled: true
corsEnabled: true
exception-handlers-enabled: true
graphql.playground:
mapping: /playground
endpoint: /graphql
enabled: true
pageTitle: Playground
Na configuração acima estamos configurando algumas coisinhas, fica tranquilo vou explicar todas elas.
Na seção server, estamos configurando a porta que o serviço será disponibilizado;
Na seção graphql.servlet, tenha atenção a tag mapping, enabled e corsEnabled. O mapping vai indicar qual endpoint será acessado os métodos para o graphql, então você já sabe que neste projeto não pode existir outro endpoint com este nome. O enabled irá ativar o endpoint /graphql. Por último estamos habilitando o CORS na nossa aplicação GraphQL.
Na seção graphql.playground, estamos configurando o cliente para teste da nossa API em GraphQL. Atenção a duas configurações, o mapping e o endpoint. O mapping é o endpoint de acesso para o playgroung. Já a configuração endpoint é o endereço que o playground irá se comunicar, utilize o mesmo valor do mapping definido na chave graphql.servlet.
Criação do schema.graphqls
Primeiro sejam criteriosos com o nome deste arquivo, tem que ser igual ao apresentado aqui. Crie esse arquivo na pasta resources do seu projeto. Assim como apresentado no exemplo abaixo:
O arquivo de Schema contém todo o mapeamento da API em GraphQL. Nele serão definidos os Types, Query, Mutations e etc…
Para mais detalhes, no início deste artigo faço algumas recomendações literárias sobre o assunto.
Neste nosso exemplo basta fazermos o seguinte:
Aqui estamos criando um Type chamado Empresa. Percebam que ele tem o nome e campos do nosso Modelo. Estamos criando também um Type Query com o método findAll que retorna um array de empresas (os colchetes indicam que o retorno será um array).
Vamos agora explicar e elucidar alguns pontos. O Spring Boot vai buscar esse arquivo e interpretá-lo, por isso a importância do nome está certinho. Ao finalizar, vai em busca de cada item especificado no projeto. Por isso, mais uma vez, atenção aos nomes. Mais a frente vou explicar como ele acha o findAll.
Pronto, agora só nos resta o Resolver.
Criação do resolver
Mas o que é um Resolver?????
Resolver: Função ou método que resolve valores para um tipo ou campo em um dado esquema.
Então o Resolver vai ligar o Schema a nossa aplicação.
Vamos criar um pacote chamado resolver no nosso projeto e dentro dele uma classe chamada EmpresaResolver. O nome do pacote e da classe não são obrigatórios, fiz assim para ficar organizadinho (é sou chato com isso).
Nosso código deve ficar assim:
Vamos aos itens que são importantes.
- A classe precisa do @Component;
- A classe precisa implementar a interface GraphQLQueryResolver ou a GraphQLMutationResolver.
As duas interfaces citadas no item 2 tem uma razão pra portarem este nome. Qualquer classe que implementa essa interface, o Spring Boot vai ligar com o schema.graphqls de forma automática.
Então, sempre que eu quiser criar uma Query basta implementar a interface GraphQLQueryResolver e sempre que eu quiser criar um Mutation basta definir a interface GraphQLMutationResolver.
Vejam que o nome da minha query e o tipo de retorno são os mesmos definidos no arquivo schema.graphqls. É assim que as coisas se ligam, para assim termos o resultado abaixo:
Depois de executar o projeto, estou acessando o endereço http://localhost:8080/playground.
No gif abaixo podemos ver o poder do GraphQL em ação.
Enfim, essa é uma "plalhinha" do que é possível fazer com GraphQL e REST.
O projeto apresentado aqui deixei no meu Github, abaixo o endereço:
Muito obrigado e até a próxima pessoal.