Anthony Giniers

@antogyn

@aginiers

GraphQL part 1 :

Introduction

https://slides.com/antogyn/graphql

Bastien Chares

@charesbast

@papybastou

GraphQL, c'est quoi ?

GraphQL est un langage de requête pour des données de type graphe

  • Débuté par Facebook en 2012
  • Open-source depuis 2015
  • Spécification et implémentations standards maintenues par Facebook : serveur Node.js, client React (Relay)
  • Écosystème jeune mais très actif
  • Utilisé par Facebook, GitHub, Pinterest, Coursera, Shopify, Yelp...

Alternative à REST

Falcor vs GraphQL ?

Adoption : GraphQL grand vainqueur

Un exemple simple

{
  user(id: 123) {
    id,
    name,
    profilePicture(size: SMALL) {
      uri
    }
  }
}
{
  "user": {
    "id": 123,
    "name": "Anthony Giniers",
    "profilePicture": {
      "uri": "http://xebia.fr/ag50.jpg",
    }
  }
}
  • Son id
  • Son nom
  • Sa photo de profil en taille "SMALL"
  • Mais uniquement l'uri

Pour le user d'id "123", on veut :

Les principes de base de GraphQL

- Hiérarchique

Une requête GraphQL est une liste hiérarchique de champs

{
  user(id: 123) {
    id,
    name,
    profilePicture(size: SMALL) {
      uri
    }
  }
}
{
  "user" : {
    "id": 123,
    "name": "Anthony Giniers",
    "profilePicture": {
      "uri": "http://xebia.fr/ag50.jpg",
    }
  }
}

→ Les données ont la même forme que la requête

→ Elles sont accessibles en une seule requête

- Hiérarchique

Je veux récupérer le dernier post de mon dernier ami

{
  me {
    friends(last: 1) {
      posts(last: 1) {
        body
      }
    }
  }
}

{
  "me": {
    "friends": [{
      "posts": [{
        "body": "poudre 2 perlimpinpin",
      }],
    }]
  }
}
  • GET /me/friends?last=1
  • GET /users/:id/posts?last=1

En REST ?

GET /me/friends/posts?last_friends=1&last_posts=1 ??

- Fortement typé

{
  user(id: 123) {
    id,
    name,
    profilePicture(size: SMALL) {
      uri
    }
  }
}
type Query {
  user(id: Int): User
}
  • Outils qui valident nos queries pendant le développement
  • Garanties sur la forme et la nature de la réponse
type User {
  id: Int!
  name: String
  profilePicture(size: Size): Media
}
type Media {
  uri: String
}
enum Size {
  SMALL
  LARGE
}
query {
  user(id: 123) {
    id,
    name,
    profilePicture(size: SMALL) {
      uri
    }
  }
}
{
  user(id: 123) {
    id,
    name,
    profilePicture(size: SMALL) {
      uri
    }
  }
}

- Requêtes construites par le client

Les spécifications sont encodées dans le client

Centré sur le produit (“product centric”)

Le langage de requête répond aux besoins des vues et des ingénieurs front-ends

- Rétrocompatible

{
  user(id: 123) {
    id,
    name,
  }
}
type User {
  id: Int
  name: String @deprecated
  identity: Identity
}

type Identity {
  name: String
}
{
  user(id: 123) {
    id,
    identity {
      name
    }
  }
}
type User {
  id: Int
  name: String
}

- Introspectif

{
  "__schema": {
    "types": [
      {
        "name": "User",
        "fields": [
          {
            "name": "id",
            "type": {
              "name": "Int"
            }
          },
          {
            "name": "name",
            "type": {
              "name": "String"
            }
          },
          {
            "name": "profilePicture",
            "type": {
              "name": "Media"
            }
          }
        ]
      }
      ...
    ]
  }
}
type User {
  id: Int
  name: String
  profilePicture: Media
}
{
  __schema {
    types {
      name
      fields {
        name
        type {
          name
        }
      }
    }
  }
}

Le typage fort et cette capacité d'introspection permet l'intégration d'outils puissants

  • Génération d'interfaces fortement typées à partir d'un schéma GraphQL
  • Découverte et navigation d'API
  • Clients externes intelligents

→ GraphiQL

Par exemple :

  • Récupérer mes 5 derniers repositories publics
  • Afficher leur dernière pull request
  • Ajouter un commentaire à une pull request

Queries vs Mutations

Le verbe http n'a pas d'importance avec GraphQL (généralement, on utilise du POST)

Cependant, on distingue les Queries des Mutations (équivalents de Query/Command du CQRS)

type Query {
  user(id: String!): User
}
type Mutation {
  createUser(name: String!): User
}
query {
  user(id: 123) {
    id,
    name
  }
}
mutation {
  createUser(name: "toto") {
    id,
    name
  }
}
mutation createToto {
  createUser(username: "toto") {
    id
  }
}
mutation createAnyUser($username: String!) {
  createUser(username: $username) {
    id
  }
}
{
  "username": "toto"
}

Variables

=> Requêtes statiques réutilisables

Variable $username

de type String!

/users/antogyn/repos?sort=pushed&direction=desc&page=1

Et en REST ?

https://api.github.com/

Récupérer les 5 derniers repos :

La dernière pull request :

/repos/antogyn/xke-graphql-github/pulls?page=1

Rajouter un commentaire :

/repos/antogyn/xke-graphql-github/issues/3/comments

x5 !!!

Quand utiliser GraphQL ?

  • Des données en graphe
  • API consommée par du front
  • Besoin de limiter le nombre de connections côté client (=mobile)
  • Utilisation d'une lib client reconnue (notamment à cause du cache)
  • Régulièrement des nouveaux besoins front

Bonus points :

Pain points

- Authentification

- File upload

Et c'est compliqué à mettre en place ?

Non.

(petit temps d'adaptation, mais le gain de temps et de confort en vaut la peine)

Merci !

Questions ?