Créer une API GraphQL moderne avec FastAPI et Strawberry
Ce guide présente, étape par étape, la création d’une API GraphQL en Python avec FastAPI et Strawberry, en expliquant les choix d’outils et les bonnes pratiques à chaque étape.
Outils utilisés
FastAPI
FastAPI est un framework web moderne pour Python, conçu pour créer des APIs performantes, robustes et faciles à maintenir. Il offre :
- Un support natif d’async/await pour la performance
- Une documentation automatique (Swagger/OpenAPI)
- Une intégration simple avec les standards Python (type hints, Pydantic)
- Idéal pour des APIs REST ou GraphQL modernes
Strawberry
Strawberry est une bibliothèque Python pour créer des APIs GraphQL. Elle se distingue par :
- Une syntaxe moderne basée sur les dataclasses et les annotations de type Python
- Un support natif de FastAPI et Starlette
- La génération automatique du schéma GraphQL et de la documentation interactive (GraphiQL)
- La gestion des queries, mutations et subscriptions (WebSocket)
Pourquoi utiliser FastAPI et Strawberry ensemble ?
FastAPI et Strawberry sont complémentaires dans l’architecture d’une API GraphQL moderne :
- FastAPI joue le rôle de serveur web : il reçoit les requêtes HTTP/WS, gère le routage, la sécurité, la documentation, et l’intégration avec l’écosystème Python (middlewares, dépendances, etc.).
- Strawberry gère toute la logique GraphQL : il définit le schéma (types, queries, mutations, subscriptions), résout les requêtes GraphQL, et expose l’interface interactive GraphiQL.
Comment ça s’interconnecte ?
- Strawberry fournit un schéma GraphQL Python.
- FastAPI expose ce schéma sur une route (ex :
/graphql
) grâce àGraphQLRouter
. - Toute requête GraphQL (query, mutation, subscription) passe par FastAPI, qui la transmet à Strawberry pour exécution.
Responsabilités dans l’architecture :
- FastAPI : transport, sécurité, configuration serveur, intégration avec d’autres services (auth, logs, etc.)
- Strawberry : logique métier GraphQL, validation des requêtes, génération du schéma, documentation GraphQL
Cette séparation permet de bénéficier du meilleur des deux mondes : la puissance de FastAPI pour l’API et l’écosystème Python, et la flexibilité de Strawberry pour GraphQL.
Initialisation du projet Python
Pour démarrer un projet Python proprement, on utilise Poetry qui gère les dépendances et l’environnement virtuel.
1. Création du projet et du fichier pyproject.toml
Dans le terminal :
poetry new exemple-graphql-fastapi
cd exemple-graphql-fastapi
Cela crée la structure de base du projet et un fichier pyproject.toml
qui centralise la configuration :
[tool.poetry]
name = "exemple-graphql-fastapi"
version = "0.1.0"
description = "Exemple d'API GraphQL avec FastAPI et Strawberry"
authors = ["Votre Nom <email@example.com>"]
[tool.poetry.dependencies]
python = ">=3.9,<4.0"
fastapi = "^0.110.0"
uvicorn = "^0.29.0"
strawberry-graphql = "^0.220.0"
requests = "^2.32.4"
websockets = "^15.0.1"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
2. Installation des dépendances
Toujours dans le dossier du projet :
poetry install
Cela crée un environnement virtuel isolé et installe toutes les dépendances nécessaires.
Astuce : Pour activer l’environnement virtuel Poetry dans votre shell, utilisez
poetry env activate
.
Mise en place du serveur FastAPI (main.py)
Le fichier main.py
est le point d’entrée de l’application. Il configure FastAPI et expose le schéma GraphQL fourni par Strawberry sur une route dédiée.
Créez un fichier main.py
à la racine du projet avec le contenu suivant :
from fastapi import FastAPI
from strawberry.fastapi import GraphQLRouter
from schema import schema
app = FastAPI()
graphql_app = GraphQLRouter(schema)
app.include_router(graphql_app, prefix="/graphql")
FastAPI()
instancie le serveur web.GraphQLRouter(schema)
crée une route GraphQL à partir du schéma Strawberry.app.include_router(...)
expose l’API GraphQL sur/graphql
.
Remarque : Ce fichier ne contient aucune logique métier, il sert uniquement à brancher le schéma GraphQL sur le serveur HTTP. Toute la logique (types, queries, mutations, subscriptions) sera définie dans
schema.py
.
Définition du schéma GraphQL : les queries (schema.py)
Pour organiser la logique métier, on crée un fichier schema.py
qui contiendra tout le schéma GraphQL : types, queries, mutations, subscriptions.
Cas d’usage fictif : gestion de piscines
Imaginons une API pour gérer un parc de piscines publiques. On souhaite exposer en lecture la liste des piscines, avec leurs caractéristiques principales (nom, localisation, capacité, horaires, etc.).
Qu’est-ce qu’une query GraphQL ?
En GraphQL, une query est une opération de lecture : elle permet au client de demander exactement les données dont il a besoin, sous la forme d’un arbre, en une seule requête HTTP. Contrairement à REST où chaque endpoint correspond à une ressource ou une action, GraphQL expose un unique endpoint /graphql
et c’est la query qui décrit la forme et la profondeur des données attendues.
- Une query interroge le schéma GraphQL pour obtenir des objets, des listes ou des champs précis.
- Le serveur exécute la query et retourne uniquement les champs demandés, dans la structure voulue.
Exemple de query côté client :
query {
pools {
name
city
}
}
Réponse typique du serveur :
{
"data": {
"pools": [
{"name": "Aquaparc", "city": "Paris"},
{"name": "Blue Lagoon", "city": "Lyon"}
]
}
}
Exemple minimal de queries dans schema.py
Créez un fichier schema.py
à la racine du projet :
import strawberry
from typing import List
@strawberry.type
class Pool:
name: str
city: str
capacity: int
# Données fictives pour l'exemple
data = [
Pool(name="Aquaparc", city="Paris", capacity=200),
Pool(name="Blue Lagoon", city="Lyon", capacity=150),
]
@strawberry.type
class Query:
@strawberry.field
def pools(self) -> List[Pool]:
return data
schema = strawberry.Schema(query=Query)
- On définit un type
Pool
(nom, ville, capacité). - On crée une liste de piscines fictives.
- On expose une query
pools
qui retourne la liste des piscines.
Remarque : Ce schéma est minimal pour illustrer la structure. On pourra l’enrichir ensuite (filtres, mutations, etc.).
Ajouter des données : les mutations GraphQL
Après les queries (lecture), GraphQL permet aussi de modifier les données via des mutations. Une mutation est l’équivalent d’une opération d’écriture (création, modification, suppression) dans le schéma.
Qu’est-ce qu’une mutation ?
- Une mutation GraphQL permet au client de demander une modification de l’état du serveur (ajout, mise à jour, suppression d’un objet).
- Comme pour les queries, le client choisit les champs à retourner dans la réponse.
- Les mutations sont regroupées dans une classe
Mutation
dans le schéma Strawberry.
Exemple de mutation côté client :
mutation {
addPool(name: "Piscine Soleil", city: "Marseille", capacity: 120) {
name
city
capacity
}
}
Réponse typique du serveur :
{
"data": {
"addPool": {
"name": "Piscine Soleil",
"city": "Marseille",
"capacity": 120
}
}
}
Exemple minimal de mutation dans schema.py
On enrichit le schéma pour permettre d’ajouter une piscine :
import strawberry
from typing import List
@strawberry.type
class Pool:
name: str
city: str
capacity: int
# Données fictives pour l'exemple
data = [
Pool(name="Aquaparc", city="Paris", capacity=200),
Pool(name="Blue Lagoon", city="Lyon", capacity=150),
]
@strawberry.type
class Query:
@strawberry.field
def pools(self) -> List[Pool]:
return data
@strawberry.type
class Mutation:
@strawberry.mutation
def add_pool(self, name: str, city: str, capacity: int) -> Pool:
pool = Pool(name=name, city=city, capacity=capacity)
data.append(pool)
return pool
schema = strawberry.Schema(query=Query, mutation=Mutation)
- On définit une classe
Mutation
avec une méthodeadd_pool
. - Cette mutation prend des arguments (name, city, capacity), crée une nouvelle piscine, l’ajoute à la liste, et la retourne.
- On passe la mutation au schéma Strawberry.
Remarque : En production, on utiliserait une base de données au lieu d’une liste Python, mais ce modèle illustre la mécanique GraphQL.
Temps réel avec GraphQL : les subscriptions (WebSocket)
En plus des queries (lecture) et des mutations (écriture), GraphQL propose un troisième concept : les subscriptions. Les subscriptions permettent au client de s’abonner à des événements côté serveur et de recevoir des notifications en temps réel, généralement via WebSocket.
Qu’est-ce qu’une subscription ?
- Une subscription GraphQL permet au client de recevoir automatiquement des mises à jour dès qu’un événement se produit (ex : ajout d’une piscine).
- La connexion se fait via WebSocket, ce qui permet au serveur de pousser les données vers le client sans que celui-ci ait à interroger en boucle.
- Les subscriptions sont utiles pour le temps réel : notifications, chat, monitoring, etc.
Exemple de subscription côté client :
subscription {
poolAdded {
name
city
}
}
À chaque fois qu’une piscine est ajoutée, le serveur envoie automatiquement les infos de la nouvelle piscine à tous les clients abonnés.
Exemple minimal de subscription dans schema.py
On enrichit le schéma pour notifier en temps réel l’ajout d’une piscine :
import asyncio
import strawberry
from typing import List, AsyncGenerator
@strawberry.type
class Pool:
name: str
city: str
capacity: int
# Données fictives pour l'exemple
data = [
Pool(name="Aquaparc", city="Paris", capacity=200),
Pool(name="Blue Lagoon", city="Lyon", capacity=150),
]
subscribers: List[asyncio.Queue] = []
@strawberry.type
class Subscription:
@strawberry.subscription
async def pool_added(self) -> AsyncGenerator[Pool, None]:
queue = asyncio.Queue()
subscribers.append(queue)
try:
while True:
pool = await queue.get()
yield pool
finally:
subscribers.remove(queue)
@strawberry.type
class Query:
@strawberry.field
def pools(self) -> List[Pool]:
return data
@strawberry.type
class Mutation:
@strawberry.mutation
def add_pool(self, name: str, city: str, capacity: int) -> Pool:
pool = Pool(name=name, city=city, capacity=capacity)
data.append(pool)
# Notifier les abonnés
for queue in subscribers:
queue.put_nowait(pool)
return pool
schema = strawberry.Schema(query=Query, mutation=Mutation, subscription=Subscription)
- On définit une classe
Subscription
avec une méthodepool_added
qui écoute les nouveaux ajouts. - Lorsqu’une piscine est ajoutée via la mutation, tous les abonnés sont notifiés en temps réel.
- Le schéma Strawberry inclut maintenant la subscription.
Remarque : Pour tester les subscriptions, il faut utiliser un client compatible WebSocket (ex : GraphiQL, Apollo, ou un script Python avec
websockets
).