Aller au contenu principal

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’ID 123
  • ❌ 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​


Quelle méthode HTTP est utilisée pour récupérer des données ?


Quelle est la bonne structure d'une URL RESTful ?


Quel code HTTP indique qu'une ressource a été créée ?


Quelle est une bonne pratique de sécurité pour une API REST ?


Quel langage est utilisé pour définir les types dans GraphQL ?


Quelle est la principale différence entre REST et GraphQL ?



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 :​

  1. Ouvrir un terminal et naviguer vers un dossier de travail.
  2. Créer un nouveau dossier pour le projet :
mkdir api-project
cd api-project
  1. Initialiser un projet Node.js :
npm init -y
  1. Installer les dépendances nécessaires :
npm install express apollo-server graphql express-graphql cors dotenv
  1. 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 :​

  1. 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");
});
  1. Exécuter le serveur :
node rest.js
  1. 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 :​

  1. 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}`);
});
  1. Exécuter le serveur :
node graphql.js
  1. 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.