Você já se perguntou se há uma maneira melhor de buscar dados para suas aplicações do que as APIs REST? No desenvolvimento de back-end, o GraphQL surgiu como uma alternativa poderosa, oferecendo uma abordagem mais flexível e eficiente para busca de dados. Para desenvolvedores familiarizados com Java, a integração do GraphQL em um back-end moderno abre as portas para APIs escaláveis e de alto desempenho adaptadas para uma ampla gama de casos de uso.
Este blog explorará as principais diferenças entre o GraphQL e o REST, destacará os benefícios únicos de usar o GraphQL para busca de dados e guiará você na implementação de uma API GraphQL em Java com um exemplo do mundo real.
O Que É o GraphQL?
O GraphQL é uma linguagem de consulta para APIs e um tempo de execução para executar essas consultas. Ao contrário do REST, onde endpoints fixos retornam dados predefinidos, o GraphQL permite que os clientes solicitem exatamente os dados de que precisam. Essa granularidade torna o GraphQL altamente eficiente, especialmente para aplicações complexas ou intensivas em dados.
Vantagens da Abordagem GraphQL:
- Busca de Dados Granular: O cliente pode consultar apenas o nome e a designação sem recuperar campos desnecessários como departamento.
- Consultas Aninhadas: Obtenha os detalhes do gerente juntamente com as informações do empregado em uma única consulta.
- Desenvolvimento Orientado a Esquema: O esquema atua como um contrato, facilitando a evolução da API.
O Que É a API REST?
O Representational State Transfer (REST) é um estilo arquitetural para construir APIs. Ele utiliza métodos padrão do HTTP como GET, POST, PUT e DELETE para realizar operações CRUD. O REST é conhecido por sua simplicidade e ampla adoção.
Limitações do REST:
- Over-fetching ou under-fetching de dados.
- Requer múltiplos endpoints e versionamento para acomodar mudanças.
- Sem capacidades embutidas de tempo real.
GraphQL vs. REST API: Qual a Diferença?
GraphQL e REST são duas abordagens populares para construir APIs, cada uma com suas vantagens. Enquanto o REST foi o padrão por anos, o GraphQL oferece mais flexibilidade e eficiência, especialmente na recuperação de dados e colaboração entre equipes de front-end e back-end.
Diferenças Chave
- Ao contrário do REST, que utiliza múltiplos endpoints e requer versionamento para mudanças, o GraphQL consolida a recuperação de dados em uma única query e reduz a necessidade de versionamento, uma vez que os clientes especificam os requisitos de dados.
- Enquanto o REST utiliza códigos de status HTTP para indicar sucesso ou erros, o GraphQL sempre retorna um status 200 OK e comunica os erros no corpo da resposta.
- O GraphQL também suporta atualizações em tempo real através de assinaturas, ao contrário do REST, que não possui suporte embutido para tempo real.
- Embora o REST esteja amplamente estabelecido com muitas ferramentas, o ambiente do GraphQL cresceu rapidamente, oferecendo ferramentas poderosas como o GraphiQL para facilitar o desenvolvimento.
- Por fim, enquanto o REST usa cabeçalhos para cache, o GraphQL requer técnicas mais avançadas devido a consultas dinâmicas, mas oferece opções como consultas persistentes para um cache eficiente.
Conceitos Centrais do GraphQL
1. Linguagem de Definição de Esquema (SDL)
O GraphQL possui seu próprio sistema de tipos que é usado para definir o esquema de uma API. A sintaxe para escrever esquemas é chamada de Linguagem de Definição de Esquema (SDL).
2. Consultas vs. Mutations vs. Assinaturas
- Consultas são usadas para buscar dados do servidor. Ao contrário do REST, que usa vários endpoints fixos, o GraphQL usa um único endpoint, e o cliente especifica os dados necessários na consulta, oferecendo flexibilidade.
- Mutations são usadas para modificar dados no servidor, como criar, atualizar ou excluir dados. Elas permitem que os clientes enviem alterações para o backend e são essenciais para aplicativos que precisam escrever dados.
- Assinaturas permitem atualizações em tempo real ao manter uma conexão constante entre o cliente e o servidor. Quando um evento assinado ocorre, o servidor envia atualizações para o cliente, fornecendo fluxos de dados contínuos, ao contrário de consultas e mutações, que seguem um ciclo de requisição-resposta.
3. Esquema GraphQL
Ele define a estrutura de dados que pode ser consultada ou modificada, atuando como um contrato entre o servidor e o cliente. Ele especifica os tipos, campos e relacionamentos disponíveis para os clientes acessarem. O esquema normalmente inclui tipos raiz especiais: Consulta para recuperação de dados, Mutação para modificar dados e Assinatura para atualizações em tempo real. Esses tipos definem coletivamente as capacidades da API e como os clientes podem interagir com ela.
4. Resolvedores: Mapeando Consultas GraphQL para Dados
Resolvedores são funções que lidam com a lógica de busca de dados em um servidor GraphQL. Cada campo em um esquema está vinculado a um resolvedor, que determina como recuperar ou calcular os dados para esse campo. Quando uma consulta é executada, o servidor invoca os resolvedores apropriados para os campos solicitados. Os resolvedores podem retornar escalares ou objetos, com a execução continuando para campos filhos se um objeto for retornado e completando se um escalar for retornado. Se nulo for retornado, a execução para. Resolvedores são essenciais para mapear consultas GraphQL para as fontes de dados reais.
Vantagens de Usar GraphQL em Java
- Recuperação Exata de Dados: Consulte apenas os dados necessários, nada mais, garantindo resultados previsíveis e eficientes.
- Solicitação Única para Múltiplos Recursos: Recupere dados relacionados em uma única consulta, reduzindo chamadas de API múltiplas.
- Sistema de Tipos: Organiza APIs por tipos e campos, garantindo que as consultas sejam válidas e os erros sejam claros.
- Ferramentas para Desenvolvedores: Aumente a produtividade com ferramentas como GraphiQL, usando definições de tipo para uma melhor construção e depuração de consultas.
- Evolução sem versão: Adicione ou deprecie campos sem quebrar consultas existentes, mantendo as APIs gerenciáveis.
- Integração de Dados Flexível: Crie uma API unificada sobre dados e código existentes que seja compatível com vários mecanismos de armazenamento e linguagens.
Configurando uma API GraphQL em Java
Exemplo Prático: Usuários e Pedidos
Imagine que você está construindo uma API de Diretório de Funcionários para uma grande organização. O objetivo é permitir que os clientes consultem detalhes como nome do funcionário, cargo, departamento e até mesmo a hierarquia de reporte deles.
1. Configure o Projeto
Crie um novo projeto Spring Boot usando Spring Tool Suite ou acessando Spring Initialiser. Em seguida, adicione essas dependências ao arquivo pom.xml
:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. Crie Suas Entidades
Crie entidades Java (por exemplo, Usuário
e Pedido
) para representar os dados que serão consultados ou alterados via GraphQL. Por exemplo:
public class User {
strategy = GenerationType.IDENTITY) (
private Long userId;
private String name;
private String email;
private String password;
// Getters and setters...
}
public class Order {
strategy = GenerationType.IDENTITY) (
private Long orderId;
private String orderDetails;
private String address;
private int price;
private User user;
// Getters and setters...
}
3. Crie Repositórios
Crie repositórios para interagir com o banco de dados:
public interface UserRepository extends JpaRepository<User, Long> {}
public interface OrderRepository extends JpaRepository<Order, Long> {}
4. Crie Classes de Serviço
Crie classes de serviço para lidar com a lógica de negócios:
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User createUser(User user) {
return userRepository.save(user);
}
public User getUser(Long userId) {
return userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found"));
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
public boolean deleteUser(Long userId) {
userRepository.deleteById(userId);
return true;
}
}
5. Crie Controladores GraphQL
Defina controladores GraphQL para lidar com consultas e mutações:
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
public List<User> getUsers() {
return userService.getAllUsers();
}
public User getUser( Long userId) {
return userService.getUser(userId);
}
public User createUser( String name, String email, String password) {
User user = new User();
user.setName(name);
user.setEmail(email);
user.setPassword(password);
return userService.createUser(user);
}
public boolean deleteUser( Long userId) {
return userService.deleteUser(userId);
}
}
6. Defina seu Esquema GraphQL
Crie um arquivo schema.graphqls
no diretório src/main/resources
:
type User {
userId: ID!
name: String
email: String
password: String
}
type Query {
getUsers: [User]
getUser(userId: ID!): User
}
type Mutation {
createUser(name: String, email: String, password: String): User
deleteUser(userId: ID!): Boolean
}
7. Configure o GraphQL no application.properties
Opcionalmente, configure as configurações do GraphQL em scr/main/resources/application.properties
:
spring.graphql.graphiql.enabled=true
8. Execute sua Aplicação
Execute a aplicação SpringBoot usando mvn spring-boot:run
ou pelo seu IDE. Uma vez em execução, você pode acessar o endpoint GraphAL em /graphiql
.
9. Teste com Consultas GraphQL
Teste a API GraphQL usando uma ferramenta como GraphiQL ou Postman.
Para Mutação:
mutation {
createUser(
name:"swetha",
email:"[email protected]",
password:"23sde4dfg43"
){
name,
userId
}
}
Resultado:
{
"data": {
"createUser": {
"name": "swetha",
"userId": "3"
}
}
}
Para Consulta:
query{
getUsers{
name
}
}
Resultado:
{
"data": {
"getUsers": [
{
"name": "Medha"
},
{
"name": "Riya"
},
{
"name": "swetha"
}
]
}
}
Recursos Avançados do GraphQL
1. Melhorando a Reutilização com Fragmentos
Um fragmento é basicamente um conjunto reutilizável de campos definidos para um tipo específico. É um recurso que ajuda a melhorar a estrutura e reutilização do seu código GraphQL.
2. Parametrizando Campos com Argumentos
No GraphQL, os campos podem aceitar argumentos para tornar as consultas mais dinâmicas e flexíveis. Esses argumentos permitem filtrar ou personalizar os dados retornados pela API.
3. Paginação e Classificação com GraphQL
Paginação
A paginação é um tópico complicado no design de API. Em um nível alto, existem duas abordagens principais em relação a como ela pode ser tratada.
- Limit-offset: Solicite um pedaço específico da lista fornecendo os índices dos itens a serem recuperados (na verdade, você está fornecendo principalmente o índice de início (offset) e uma contagem de itens a serem recuperados (limit)).
- Baseado em cursor: Este modelo de paginação é um pouco mais avançado. Cada elemento na lista é associado a um ID único (o cursor). Os clientes que paginam pela lista fornecem então o cursor do elemento de início, bem como uma contagem de itens a serem recuperados.
Classificação
No design de API do GraphQL, é possível retornar listas de elementos que são classificados (ordenados) de acordo com critérios específicos.
Desafios e Considerações ao Usar GraphQL
- Complexidade: Gerenciar esquemas e consultas do GraphQL pode ser desafiador para modelos de dados simples ou equipes inexperientes.
- Problemas de Desempenho: Consultas profundamente aninhadas podem sobrecarregar recursos do backend se não forem otimizadas.
- Desafios de Cache: Estratégias de cache padrão baseadas em REST não se aplicam e exigem soluções personalizadas.
- Preocupações com Segurança: O excesso de busca e consultas maliciosas exigem limites de consulta e outras proteções.
- Uso Híbrido: Funciona melhor para necessidades de dados complexas, frequentemente combinado com REST para operações mais simples.
Conclusão
O GraphQL oferece uma abordagem flexível e eficiente para a construção de APIs modernas em Java, tornando-se uma escolha ideal para aplicações dinâmicas e intensivas em dados. Sua arquitetura de ponto único e tipagem forte simplificam o design da API, garantindo um desempenho robusto. Seja criando um simples diretório de funcionários ou uma plataforma analítica complexa, o GraphQL capacita os desenvolvedores a oferecer soluções escaláveis com facilidade. Comece a explorar o GraphQL hoje com ferramentas como Spring Boot e graphql-java
para desbloquear todo o seu potencial em seu próximo projeto.
Código Fonte
Você pode encontrar o código fonte completo deste tutorial no Github.
Source:
https://dzone.com/articles/design-scalable-java-apis-with-graphql