4 min read

Introduction à GraphQL avec Python

Introduction à GraphQL avec Python

Tout comme nous l'avions fait pour la mise en place d'une API Rest en Python avec Falcon, nous allons aujourd'hui mettre en place une application GraphQL avec le framework Django.

A quoi sert GraphQL?

Publié en Open Source par Facebook en 2015, GraphQL est une syntaxe décrivant la procédure à suivre pour demander des données. Elle est généralement utilisée pour charger des données d’un serveur vers un client. GraphQL a trois caractéristiques principales:

  • Il permet au client de spécifier exactement les données dont il a besoin
  • Il facilite l'agrégation des données provenant de plusieurs sources.
  • GraphQL n'est pas lié à un moteur de stockage spécifique

Concurrent direct des API REST, GraphQL permet en un seul point de récupérer un ensemble de données provenant de différentes sources. En considérant une application qui permet de récupérer auteurs et articles de blog il faudrait considérer une url pour récupérer les auteurs, une autre pour récupérer les articles de blog. Avec GraphQL, une seule URL est nécessaire comme nous allons le voir.

Mise en place de  Django et Graphene

Afin de comparer plus facilement API REST et GraphQL, nous allons reprendre le modèle de gestion de interventions utilisé dans notre article consacré aux API avec Falcon. Nous utilisons Django comme framework et Graphene, une librairie pour construire des API GraphQL.
Dans un terminal, créez un nouvel environnement et activez le:

virtualenv -p python3 intervention_with_graphql
source intervention_with_graphql/bin/activate

Passons désormais à l'installation des bibliothèques nécessaires:

pip install django graphene-django
django-admin startproject demo_graphql
cd demo_graphql
python manage.py migrate
python manage.py runserver

À ce stade, notre projet est créé et l'url http://127.0.0.1:8000/ présente la page par défaut de Django.

Page d'accueil du framework Django

Une dernière configuration nous permet d'utiliser la librairie graphene dans notre application. Dans le fichier demo_graphql/settings.py, recherchez la variable INSTALLED_APPS et ajoutez graphene_django:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'graphene_django',
]

GRAPHENE = {
    'SCHEMA': 'demo_graphql.schema.schema',
}

Mise en place d'une application de gestion des interventions

Dans le précédent chapitre, nous avons mis en place la structure de notre projet grâce à Django. Nous allons donc désormais créer une application pour gérer les interventions, une autre pour les intervenants.
Commençons par créer une application pour les interventions

python manage.py startapp interventions

Un nouveau répertoire a été créé avec un ensemble de fichiers. Il nous faut désormais définir notre modèle:

from django.db import models

class Intervention(models.Model):
    title = models.CharField(max_length=180)
    description = models.TextField(blank=True)

Avant de pouvoir exploiter ce modèle, il nous faut prévenir Django de l'existence de notre application. Pour cela, on ajoute le nom de notre application dans la variable INSTALLED_APPS du fichier demo_graphql/settings.py.

INSTALLED_APPS = [
...

	'interventions',
]

Nous pouvons désormais créer les tables dans la base de données

python manage.py makemigrations
python manage.py migrate

Avec GraphQL, un Type est un objet pouvant contenir plusieurs champs. Chaque champ est calculé via des résolveurs, qui renvoie une valeur. Une collection de types s'appelle un Schema. Chaque schema possède un type spécial appelé requête pour obtenir des données du serveur et une mutation pour envoyer des données au serveur.
Nous pouvons donc créer notre schema dans un fichier schema.py situé dans à la racine de notre application:

import graphene
from graphene_django import DjangoObjectType

from .models import Intervention


class InterventionType(DjangoObjectType):
    class Meta:
        model = Intervention


class Query(graphene.ObjectType):
    interventions = graphene.List(InterventionType)

    def resolve_interventions(self, info, **kwargs):
        return Intervention.objects.all()

Dans ce fichier, nous avons créé un nouveau Type avec un resolveur pour retourner les interventions.
Un nouveau fichier schema.py situé à la racine de notre projet, hérite du schema de notre application des interventions et nous permet de cloisonner et maintenir nos développements.

import graphene

import interventions.schema


class Query(interventions.schema.Query, graphene.ObjectType):
    pass


schema = graphene.Schema(query=Query)

Il nous reste une dernière étape avant de pouvoir requêter les données présentes en base, il s'agit de spécifier l'url sur laquelle GraphiQL est disponible.
GraphiQL est l'implémentation de référence de GraphQL IDE, un projet officiel de la Fondation GraphQL. C'est donc une interface qui nous permet de créer nos requêtes.
Pour cela, il convient de spécifier notre url dans le fichier urls.pysitué à la racine de notre projet:

from django.contrib import admin
from django.urls import path

from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView


urlpatterns = [
    path('admin/', admin.site.urls),
    path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))),

Nous pouvons désormais nous rendre sur http://127.0.0.1:8000/graphql/ et effectuer nos premières requêtes.

Effectuer des requêtes avec GraphQL

Il est désormais très facile de remonter nos interventions. Dans le panneau de gauche, l'éditeur permet de sélectionner les objets que nous souhaitons récupérer.
Voici par exemple comment récupérer les identifiants de l'ensemble des interventions:

Bien entendu, nous pouvons aller plus loin et exploiter l'ensemble des données disponibles pour chaque interventions:

Voila, nous avons réalisé nos premières requêtes avec GraphQL ! Vous pouvez désormais ajouter, supprimer ou modifier des champs au modèle et les récupérer via GraphiQL.

Dans un prochain article, nous complexifierons nos modèles et découvrirons les mutations, utiles pour la création d'objets ainsi que les filtres pour nous permettre de récupérer des entrées spécifiques.