Bonnes pratiques REST/GraphQL
Notions théoriques
1. Introduction aux API REST et GraphQL
Les API (Application Programming Interfaces) permettent aux applications de communiquer entre elles en échangeant des données.
Deux des approches les plus courantes pour concevoir des API sont REST et GraphQL :
- REST (Representational State Transfer) est une architecture qui repose sur des endpoints définis et des méthodes HTTP (
GET
,POST
,PUT
,DELETE
). - GraphQL, développé par Facebook, permet aux clients de spécifier exactement quelles données ils veulent récupérer via une seule requête.
2. Bonnes pratiques pour les API REST
a) Utilisation des bonnes méthodes HTTP
Chaque action doit correspondre à une méthode HTTP appropriée :
GET
: Récupérer des données.POST
: Ajouter une nouvelle ressource.PUT
: Mettre à jour une ressource existante.DELETE
: Supprimer une ressource.
b) Structuration des URL
Les URL doivent être claires et prévisibles :
- ✔️
GET /users/123
→ Récupérer l’utilisateur avec l’ID123
- ❌
GET /getUser?id=123
(mauvaise pratique)
Utiliser des noms de ressources au pluriel :
- ✔️
/products
- ❌
/product
c) Gestion des statuts HTTP
Les réponses doivent contenir des codes de statut appropriés :
200 OK
→ Requête réussie.201 Created
→ Ressource créée.400 Bad Request
→ Erreur dans la requête.401 Unauthorized
→ Authentification requise.404 Not Found
→ Ressource inexistante.500 Internal Server Error
→ Erreur côté serveur.
d) Sécurisation des API
- Utiliser HTTPS pour chiffrer les échanges.
- Mettre en place une authentification avec tokens JWT ou OAuth.
- Limiter les requêtes avec un rate limiting.
3. Bonnes pratiques pour GraphQL
a) Utilisation des requêtes ciblées
GraphQL permet de récupérer uniquement les données nécessaires, évitant ainsi le surplus d’information.
b) Organisation des types et schémas
Définir des types clairs pour structurer les données :
type User {
id: ID!
name: String!
email: String!
}
c) Gestion des erreurs
GraphQL retourne toujours un code 200, mais les erreurs doivent être bien gérées dans la réponse :
{
"errors": [
{
"message": "Utilisateur non trouvé",
"extensions": { "code": "USER_NOT_FOUND" }
}
]
}
d) Sécurisation
- Restreindre les champs accessibles pour éviter les fuites de données.
- Mettre en place une authentification et autorisation.
Exemple pratique
Il est possible de créer une API REST et une API GraphQL avec Express.js.
1. API REST simple
Créer un serveur Express avec un endpoint REST :
const express = require("express");
const app = express();
app.use(express.json());
const users = [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }];
app.get("/users", (req, res) => {
res.status(200).json(users);
});
app.listen(3000, () => {
console.log("Serveur REST sur http://localhost:3000");
});
2. API GraphQL simple
Créer un serveur GraphQL avec Apollo Server :
const { ApolloServer, gql } = require("apollo-server");
const typeDefs = gql`
type User {
id: ID!
name: String!
}
type Query {
users: [User]
}
`;
const resolvers = {
Query: {
users: () => [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]
}
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`Serveur GraphQL sur ${url}`);
});
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Ce TP a pour objectif de concevoir et implémenter une API REST et une API GraphQL en appliquant les bonnes pratiques de développement.
Étape 1 : Initialisation du projet
Avant de commencer à coder, il est nécessaire de mettre en place un projet Node.js qui servira de base pour les API REST et GraphQL.
Instructions :
- Ouvrir un terminal et naviguer vers un dossier de travail.
- Créer un nouveau dossier pour le projet :
mkdir api-project
cd api-project
- Initialiser un projet Node.js :
npm init -y
- Installer les dépendances nécessaires :
npm install express apollo-server graphql express-graphql cors dotenv
- Vérifier que les fichiers suivants sont bien présents dans le dossier :
package.json
(créé automatiquement)node_modules/
(dossier contenant les bibliothèques installées)- Les modules Express, Apollo Server, GraphQL, express-graphql, cors et dotenv sont installés pour gérer les API REST et GraphQL.
Étape 2 : Création d'une API REST bien structurée
L'objectif est de créer une API REST qui respecte les bonnes pratiques en matière de structuration des routes, gestion des erreurs et sécurité.
Instructions :
- Créer un fichier
rest.js
et ajouter le code suivant :
require("dotenv").config();
const express = require("express");
const cors = require("cors");
const app = express();
app.use(express.json());
app.use(cors());
const users = [
{ id: 1, name: "Alice", email: "alice@example.com" },
{ id: 2, name: "Bob", email: "bob@example.com" }
];
// Récupérer tous les utilisateurs
app.get("/users", (req, res) => {
res.status(200).json(users);
});
// Récupérer un utilisateur par ID
app.get("/users/:id", (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: "Utilisateur non trouvé" });
}
res.status(200).json(user);
});
// Ajouter un nouvel utilisateur
app.post("/users", (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: "Nom et email requis" });
}
const newUser = { id: users.length + 1, name, email };
users.push(newUser);
res.status(201).json(newUser);
});
// Supprimer un utilisateur
app.delete("/users/:id", (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: "Utilisateur non trouvé" });
}
users.splice(index, 1);
res.status(204).send();
});
app.listen(3000, () => {
console.log("Serveur REST démarré sur http://localhost:3000");
});
- Exécuter le serveur :
node rest.js
- Tester les routes avec Postman ou cURL :
GET http://localhost:3000/users
GET http://localhost:3000/users/1
POST http://localhost:3000/users
avec un corps JSON contenant{ "name": "Charlie", "email": "charlie@example.com" }
DELETE http://localhost:3000/users/1
Vérifier si :
- L'API REST est bien structurée avec des routes claires (
/users
,/users/:id
). - Les erreurs sont gérées correctement (
404 Not Found
,400 Bad Request
). - L'API respecte les bonnes pratiques en matière de sécurité et de gestion des données.
Étape 3 : Création d'une API GraphQL bien organisée
L'objectif est de concevoir une API GraphQL qui permet de récupérer et de modifier des utilisateurs avec un schéma bien défini.
Instructions :
- Créer un fichier
graphql.js
et ajouter le code suivant :
const { ApolloServer, gql } = require("apollo-server");
const users = [
{ id: 1, name: "Alice", email: "alice@example.com" },
{ id: 2, name: "Bob", email: "bob@example.com" }
];
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
}
type Query {
users: [User]
user(id: ID!): User
}
type Mutation {
addUser(name: String!, email: String!): User
deleteUser(id: ID!): String
}
`;
const resolvers = {
Query: {
users: () => users,
user: (_, { id }) => users.find(user => user.id === parseInt(id))
},
Mutation: {
addUser: (_, { name, email }) => {
const newUser = { id: users.length + 1, name, email };
users.push(newUser);
return newUser;
},
deleteUser: (_, { id }) => {
const index = users.findIndex(user => user.id === parseInt(id));
if (index === -1) {
return "Utilisateur non trouvé";
}
users.splice(index, 1);
return "Utilisateur supprimé";
}
}
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`Serveur GraphQL démarré sur ${url}`);
});
- Exécuter le serveur :
node graphql.js
- Tester les requêtes dans GraphQL Playground :
- Récupérer tous les utilisateurs :
query {
users {
id
name
email
}
}
- Ajouter un utilisateur :
mutation {
addUser(name: "Charlie", email: "charlie@example.com") {
id
name
email
}
}
- Supprimer un utilisateur :
mutation {
deleteUser(id: "1")
}
Vérifier si :
- L'API GraphQL est bien organisée avec un schéma clair et des types bien définis.
- Les requêtes et mutations permettent d'interagir efficacement avec les données.
- L'API respecte les bonnes pratiques en matière de structuration et de gestion des erreurs.
Conclusion
Ce TP a permis de concevoir une API REST et une API GraphQL en appliquant les bonnes pratiques :
- Structuration des routes et des schémas pour une meilleure lisibilité.
- Gestion des erreurs pour éviter les comportements imprévisibles.
- Sécurisation des accès en limitant les requêtes et en validant les entrées.
Les API REST et GraphQL sont désormais fonctionnelles et prêtes à être améliorées avec des fonctionnalités supplémentaires comme l'authentification et la pagination.