Pourquoi Spring Boot avec GraphQL ?
Le développement moderne des applications nécessite une communication efficace entre clients et serveurs, afin d'offrir une expérience utilisateur fluide et interactive. Les technologies comme REST sont largement utilisées pour ce but, mais elles présentent certaines limites, notamment la nécessité de faire plusieurs requêtes pour récupérer les données nécessaires à une application.
GraphQL est un langage de requête et de réponse pour APIs créée par Facebook en 2015. Il permet aux clients d'interroger exactement les données qu'ils ont besoin, et non une collection prédéfinie. Cela réduit le temps de réponse et améliore l'efficacité des applications.
Un cas concret est un système de gestion de contenu où un utilisateur doit récupérer des informations sur un article, y compris son auteur, les commentaires associés et les catégories auxquelles il appartient. Avec REST, cela nécessiterait plusieurs requêtes à différents endpoints. Avec GraphQL, le client peut faire une seule requête pour obtenir toutes ces informations en un seul appel.
Prerequis
- Connaissance de Java 8 ou ultérieure
- Connaissance de Spring Boot
- Connaissance de base des bases de données relationnelles (SQL)
- Node.js et npm installés (pour les outils GraphQL)
Concepts fondamentaux
Schéma GraphQL
Le schéma GraphQL décrit le format des requêtes et des réponses possibles. Il définit les types de données, les champs disponibles et leurs relations.
## Définition d'un type Article
type Article {
id: ID!
title: String!
content: String!
author: Author
}
## Définition d'un type Author
type Author {
id: ID!
name: String!
}
Résolveurs
Les résolveurs sont des fonctions qui récupèrent les données demandées par le client en fonction du schéma. Ils définissent comment chaque champ de l'API est traité.
// Résolvant pour le type Article
@Component
public class ArticleResolver {
@Autowired
private ArticleService articleService;
public Article getArticleById(String id) {
return articleService.findById(id);
}
}
Serveur GraphQL
Le serveur GraphQL est responsable de la réception des requêtes du client, d'exécution des résolveurs appropriés et de renvoi des réponses.
// Configuration du serveur GraphQL
@Configuration
public class GraphQlConfig {
@Bean
public GraphQLSchema graphQLSchema() {
return buildSchema();
}
private GraphQLSchema buildSchema() {
return SchemaParser.newParser()
.file("schema.graphqls") // Fichier de schéma
.resolvers(new ArticleResolver()) // Résolveurs
.build()
.makeExecutableSchema();
}
}
Client GraphQL
Le client GraphQL permet aux développeurs d'interroger l'API et de gérer les réponses. Il existe des bibliothèques clientes pour plusieurs langages, comme Apollo Client pour JavaScript.
// Exemple d'utilisation d'Apollo Client
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:8080/graphql',
cache: new InMemoryCache()
});
const GET_ARTICLE = gql`
query GetArticle($id: ID!) {
article(id: $id) {
id
title
content
author {
id
name
}
}
}
`;
client.query({
query: GET_ARTICLE,
variables: { id: '1' }
}).then(result => console.log(result.data.article));
Mise en pratique : projet fil rouge
Nous allons construire un mini-projet complet pour une application de gestion de tâches. L'application permettra aux utilisateurs d'afficher, ajouter et modifier des tâches.
Étape 1 : Configuration du projet
Créez un nouveau projet Spring Boot avec les dépendances suivantes :
- Spring Web
- Spring Data JPA
- H2 Database (pour les tests)
mvn archetype:generate -DgroupId=com.example -DartifactId=todo-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
Ajoutez les dépendances dans le pom.xml :
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Autres dépendances -->
</dependencies>
Étape 2 : Création du modèle de données
// src/main/java/com/example/model/Todo.java
@Entity
public class Todo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private boolean completed;
// Getters et setters
}
Étape 3 : Configuration de la base de données
## src/main/resources/application.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
Étape 4 : Création du repository
// src/main/java/com/example/repository/TodoRepository.java
public interface TodoRepository extends JpaRepository<Todo, Long> {
}
Étape 5 : Création des services
// src/main/java/com/example/service/TodoService.java
@Service
public class TodoService {
@Autowired
private TodoRepository todoRepository;
public List<Todo> findAll() {
return todoRepository.findAll();
}
public Todo save(Todo todo) {
return todoRepository.save(todo);
}
}
Étape 6 : Création des contrôleurs REST
// src/main/java/com/example/controller/TodoController.java
@RestController
@RequestMapping("/todos")
public class TodoController {
@Autowired
private TodoService todoService;
@GetMapping
public List<Todo> getAllTodos() {
return todoService.findAll();
}
@PostMapping
public Todo createTodo(@RequestBody Todo todo) {
return todoService.save(todo);
}
}
Étape 7 : Création du schéma GraphQL
## src/main/resources/schema.graphqls
type Query {
}
type Mutation {
createTodo(title: String!, completed: Boolean!): Todo
}
type Todo {
id: ID!
title: String!
completed: Boolean!
}
Étape 8 : Création des résolveurs
// src/main/java/com/example/resolver/TodoResolver.java
@Component
public class TodoResolver {
@Autowired
private TodoService todoService;
public List<Todo> getTodos() {
return todoService.findAll();
}
public Todo createTodo(String title, boolean completed) {
Todo todo = new Todo();
todo.setTitle(title);
todo.setCompleted(completed);
return todoService.save(todo);
}
}
Étape 9 : Configuration du serveur GraphQL
// src/main/java/com/example/config/GraphQlConfig.java
@Configuration
public class GraphQlConfig {
@Autowired
private TodoResolver todoResolver;
@Bean
public GraphQLSchema graphQLSchema() {
return buildSchema();
}
private GraphQLSchema buildSchema() {
return SchemaParser.newParser()
.file("schema.graphqls")
.resolvers(todoResolver)
.build()
.makeExecutableSchema();
}
}
Étape 10 : Création du client GraphQL
Créez un simple script JavaScript pour tester l'API :
// test.js
const { ApolloClient, HttpLink, InMemoryCache } = require('@apollo/client');
const gql = require('graphql-tag');
const client = new ApolloClient({
link: new HttpLink({ uri: 'http://localhost:8080/graphql' }),
cache: new InMemoryCache()
});
const GET_TODOS = gql`
query GetTodos {
todos {
id
title
completed
}
}
`;
client.query({ query: GET_TODOS }).then(result => console.log(result.data.todos));
Exécutez le script :
node test.js
Erreurs fréquentes et debugging
1. GraphQLSchemaException: "Cannot resolve type"
// Code incorrect
@Component
public class ArticleResolver {
public Article getArticleById(String id) {
// Code incorrect
}
}
Correction :
// Code correct
@Component
public class ArticleResolver {
@Autowired
private ArticleService articleService;
public Article getArticleById(String id) {
return articleService.findById(id);
}
}
2. NullPointerException: "No resolver found for field"
type Query {
}
type Todo {
id: ID!
title: String!
completed: Boolean!
}
Correction :
Ajoutez le résolveur pour la méthode todos dans votre classe de résolveurs.
3. JsonMappingException: "No property found"
@JsonIgnoreProperties(ignoreUnknown = true)
public class Todo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private boolean completed;
// Getters et setters
}
Correction :
Ajoutez l'annotation @JsonIgnoreProperties(ignoreUnknown = true) au modèle de données.
Pour aller plus loin
Intégration avec GraphQL subscriptions : Permet d'avoir des mises à jour en temps réel.
- Lien : GraphQL Subscriptions
Authentification et autorisation : Ajoutez une couche de sécurité pour protéger vos API GraphQL.
- Lien : Spring Security with GraphQL
Performance et optimisation : Améliorez le rendement de votre API avec des directives GraphQL.
- Lien : GraphQL Performance
Défi pratique
Créez une API GraphQL pour un service de chat, permettant aux utilisateurs d'afficher la liste des chats et d'ajouter de nouveaux chats. Utilisez les concepts appris (schemas, résolveurs, serveur GraphQL) pour construire cette application.