Code Monkey home page Code Monkey logo

graphql-workshop's Introduction

GraphQL Workshop for Best Of Web

alt Logo Best of Web

Introduction

Ce workshop préparé au sein de JS-Republic par Michael Romain et Mathieu Breton a pour but de vous apprendre à utiliser GraphQL.

D'une durée approximative de 3h, ce workshop vous guidera étape par étape dans la migration d'un blog basique fait avec une API REST vers une implémentation full GraphQL. Chaque partie débutera par une courte présentation faite par l'animateur du workshop afin d'expliquer les points qui seront traités dans celle-ci, puis les candidats suivront l'énoncé pour accomplir la partie en question. Une fois l'étape terminée, l'animateur répondra aux questions et passera à la partie suivante.

Chaque étape vous démontrera les avantages (et inconvénients) de GraphQL comparé à REST pour les mêmes besoins. Ce workshop est conçu pour des développeurs JavaScript, débutants en GraphQL.

Pour commencer, assurez-vous d'avoir les pré-requis ci-dessous puis procéder à l'installation du projet de workshop. Une description du projet vous attends une fois l'installation terminée.

Pré-requis

Pour suivre ce workshop, vous aurez besoin :

  • De connaissances confirmées dans le langage JavaScript, en NodeJS et en développement Front-End.
  • D'une prémière expérience avec les API REST.
  • De NodeJS installé en version 6.14.2 et plus. Dans un soucis de compatibilité, l'implémentation back-end fonctionne avec la version 6.* de Node, version la plus vielle actuellement encore maintenue. Si vous utilisez nvm, vous pouvez faire un nvm use à la racine du projet pour passer directement dans la bonne version de NodeJS.
  • D'un éditeur de code. Visual Studio Code fait désormais référence.

Installation

Une fois n'est pas coutume, nous récupérons ce projet depuis Github et installerons ses dépendances :

git clone https://github.com/js-republic/graphql-workshop.git
cd graphql-workshop
npm install

Il ne reste plus qu'à le démarrer :

npm start

Votre navigateur s'ouvre à l'adresse http://localhost:3000, vous devriez découvrir cette interface :

alt Interface du blog

Prennez quelques instants pour vous familiariser avec le blog en l'état. Vous remarquerez notament que pour l'instant il communique avec le back-end via l'API REST.

Description du projet du workshop :

Le projet est organisé comme suit :

.
├── ...
├── blog.sqlite                   <-- Fichier de base de données SQlite du blog
├── migrations                    <-- Dossier contenant les scripts d'initialisation SQL
├── public                        <-- Dossier publique exposé sur localhost:3000
│   ├── index.html
│   └── ...
├── server                        <-- Sources du serveur en NodeJS exposant les données
│   ├── ...
│   ├── route                     <-- Dossier contenant les routes exposées par le serveur
│   │   ├── graphql.js            <-- Script pour exposer les données en GraphQL (à modifier)
│   │   ├── rest.js               <-- Script pour exposer les données en REST
│   │   └── ...
│   └── service
│       └── index.js              <-- Service qui permet d'accéder et modifier les données en base
└── src                           <-- Sources du front en React (architecture create-react-app)
    ├── ...
    ├── clients                   <-- Dossier contenant les routes exposées par le serveur
    │   ├── rest.js               <-- Script permettant la récupération et manipulation des données via REST
    │   └── graphq.js             <-- Script permettant la récupération et manipulation des données via GraphQL (à modifier)
    └── components
        └── ...

Quand le projet est démarré (via npm start) deux tâches sont lancées en parallèle :

Si vous faites ce workshop hors de la session Best Of Web, nous vous invitons à d'abord prendre connaissance du début de cette présentation jusqu'à la diapositive Premier exercice : https://slides.com/mbreton/graphql-workshop

Les données sont enregistrées dans SQLite, sous la forme d'un fichier blog.sqlite à la racine du projet. Si vous souhaitez réinitialiser vos données, il vous suffit de supprimer ce fichier et redémarrer.

Excercices

Familliarisation avec GraphQL

Dans cette première partie, vous allez vous familiariser avec le requêtage GraphQL et l'implémentation côté serveur pour lire des données.

Présentation des points abordés : https://slides.com/mbreton/graphql-workshop#/1

Ennoncé :

  1. Rendez-vous dans le ficher server/route/graphql.js pour y ajouter un type Query posts permettant de récupérer une liste de Post.

    Découvrer la solution ici
    // ...
    const schema = buildSchema(`
    type Post {
      id: ID!
      title: String!
      content: String!
    }
    type Query {
      posts: [Post]
    }
    `);
    // ...
    
  2. Ajouter un resolver correspondant à la Query que venez d'ajouter. Vous pouvez vous appuyer sur la fonction getPosts du script server/service/index.js déjà importé dans server/route/graphql.js. Petite subtilité, cette fonction retourne une promesse. (plus d'information sur les resolvers asynchrones ici)

    Découvrer la solution ici
    // ...
    const schema = buildSchema(`
    type Post {
      id: ID!
      title: String!
      content: String!
    }
    type Query {
      posts: [Post]
    }
    `);
    router.use(
        graphqlHTTP({
            schema,
            rootValue: {
            posts() {
                return service.getPosts();
            }
            },
            graphiql: true
        })
    );
    // ...
    

Vous devez maintenant pouvoir requêter la liste des articles via GraphQL dans GraphiQL.

Comment requêter les données ?
    {
        posts {
            id
            title
            content
        }
    }
    

Graphql, partie client

Nos données désormais disponibles via GraphQL sur notre serveur, il est temps de les afficher !

Présentation des points abordés : https://slides.com/mbreton/graphql-workshop#/2

Ennoncé :

  1. Aller dans le fichier src/clients/graphql.js. Ce fichier est responsable de toutes les requêtes GraphQL envoyées par le front vers le backend. Implémenter la fonction getPosts pour l'instant vide afin de charger l'id, le title et le content des articles :

    export async function getPosts() {}

    Vous pouvez utiliser la librairie axios pour faire vos appels HTTP. Vérifier que vous avez bien implémeté la fonction en retournant sur le blog http://localhost:3000 voir que la liste des articles se charge bien avec l'intérupteur en mode GraphQL, sinon regarder la console :)

    Découvrer la solution ici
    export async function getPosts() {
        const {
            data: {
                data: { posts }
            }
        } = await axios.post("/graphql", {
            query: `{
            posts {
                id
                title
                content
            }
            }`
        });
        return posts;
    }
    

Retour sur le typage

Vous ne l'aurez pas manqué, il n'y a plus les commentaires ! Et cela est normal, ils n'existent pas dans notre schéma.

Nous confirmons des points déjà vus juste avant dans cette partie.

Ennoncé :

  1. Retournez dans server/route/graphql.js pour y ajouter un type Comment dans le schéma. Ce type Comment contiendra une propriété id que représente son identifiant unique et une propriété content qui représente le texte qu'elle contient. Ces deux proriétés doivent être obligatoires. Une fois ce type créé, ajouter une propriété comments dans Post qui contiendra la liste du type fraichement créé.

    Découvrer la solution ici
    // ...
    const schema = buildSchema(`
    type Post {
      id: ID!
      title: String!
      content: String!
      comments: [Comment]!
    }
    type Comment {
      id: ID!
      content: String!
    }
    type Query {
      posts: [Post]
    }
    `);
    // ...
    

    Vous pouvez vérifier dans GraphiQL que l'on peut bien désormais récupérer les commentaires avec les posts. Cela est possible notament car service.getPosts() retourne en vérité une liste d'objet Post comprenant les Comment qui vont avec.

  2. Il ne reste plus qu'à modifier la requête de la fonction getPosts du fichier src/client/Graphql.js pour y ajouter le chargement des commentaires (et de toute le ses propriétés) en même temps que celui des Posts.

    Découvrer la solution ici
        export async function getPosts() {
            const { data: { data: { posts } } } = await axios.post("/graphql", {
                query: `{ posts { id title content comments { id content } } }`
            });
            return posts;
        }
    

Comparez maintenant les appels réseaux du blog en mode REST et en mode GraphQL. Qu'observe-t'on ?

Nous venons de mettre le doigt sur une des grandes forces de GraphQL : le requêtage multiple

Là où REST impose que chaque ressource doit être derrière une URL GraphQL permet de récupérer plusieurs entitées, liées ou non, en une seul requête.

Création d'un commentaire via GraphQL

Nous savons désormais exposer, et lire de la donnée au travers de GraphQL, voyons maintenant comment nous pouvons la modifier par se biais. Pour l'instant, quand vous êtes en mode GraphQL, l'ajout d'article ne fonctionne pas.

Présentation des points abordés : https://slides.com/mbreton/graphql-workshop#/3

Ennoncé :

  1. Implémentons d'abord la partie serveur. Comme lors du premier exercice, rendez-vous dans server/route/graphql.js. Ajouter dans le schéma un nouveau type Mutation dans lequel il y aura une opération createComment prenant en paramètre un postId, de type ID, content de type string et retournant le type Comment.

    Découvrer la solution ici
    const schema = buildSchema(`
    type Post {
        id: ID!
        title: String!
        content: String!
        comments: [Comment]!
    }
    type Comment {
        id: ID!
        content: String!
    }
    type Query {
        posts: [Post]!
    }
    type Mutation {
        createComment(postId:ID!, content: String!): Comment
    }
    `);
    
  2. Complétons notre implémentation serveur, en ajoutant le resolver correspondant à la mutation précédement ajoutée. Cette opération pourra s'appuyer sur la fonction addNewCommentFor du service server/service/index.js.

    Découvrer la solution ici
    router.use(
        graphqlHTTP({
            schema,
            rootValue: {
                posts: () => service.getPosts(),
                createComment: params =>
        service.addNewCommentFor(params.postId, params.content)
            },
            graphiql: true
        })
    );
    
  3. Retourner dans GraphiQL, et formuler une requête graphql pour tester la mutation mise en place côté serveur. Vous devriez recevoir un résultat du type (en fonction des champs que vous choisissez de récupérer):

    {
      "data": {
        "createComment": {
          "id": "f1fbde00-696c-11e8-b3cf-bf211aef93e8",
          "content": "contentdzdzdz"
        }
      }
    }
  4. La partie serveur maintenant prête, il est temps d'ajouter le code côté front capable d'envoyer une requête de mutation au serveur. Vous l'aurez surement deviné, rendons-nous dans le fichier src/clients/graphql.js pour implémenter la fonction addNewComment :

    export async function addNewComment(newPost) {}
    Découvrer la solution ici
    export async function addNewComment(comment, postId) {
        const {
            data: {
            data: { createComment }
            }
        } = await axios.post("/graphql", {
            query: `mutation createComment($postId:ID!, $content: String!) {
            createComment(postId: $postId, content: $content) {
                id
                content
            }
            }`,
            variables: {
                postId,
                content: comment.content
            }
        });
        return createComment;
    }
    

Création d'un post via GraphQL

Allons plus loin de la mutation avec la création d'un Post.

Présentation des points abordés : https://slides.com/mbreton/graphql-workshop#/4

Ennoncé :

  1. Rendez-vous dans server/route/graphql.js. Ajouter une nouvelle Mutation dans laquel il y aura une opération createPost prennant en paramètre un newPost de type PostInput, input que vous aurez créé juste avant et qui contiendra le title et le content sous forme de text.

    Découvrer la solution ici
    const schema = buildSchema(`
        type Post {
            id: ID!
            title: String!
            content: String!
            comments: [Comment]!
        }
        input PostInput {
            title: String!,
            content: String!
        }
        type Comment {
            id: ID!
            content: String!
        }
        type Query {
            posts: [Post]!
        }
        type Mutation {
            createComment(postId:ID!, content: String!): Comment
            createPost(newPost: PostInput): Post
        }
    `);
    
  2. Comme pour l'ajout de commentaire, on ajout le resolver correspondant. Cette opération pourra s'appuyer sur la fonction addNewPost du service server/service/index.js.

    Découvrer la solution ici
    router.use(
        graphqlHTTP({
            schema,
            rootValue: {
            posts: () => service.getPosts(),
            createPost: ({ newPost }) => service.addNewPost(newPost),
            createComment: params =>
                service.addNewCommentFor(params.postId, params.content)
            },
            graphiql: true
        })
        );
    
  3. Retourner dans GraphiQL, et formuler une requête graphql pour tester la mutation mise en place côté serveur. Vous devriez recevoir un résultat du type (en fonction des champs que choisissez de récupérer):

    {
      "data": {
        "createPost": {
          "id": "f1fbde00-696c-11e8-b3cf-bf211aef93e8",
          "title": "test",
          "content": "contentdzdzdz"
        }
      }
    }
    Découvrer la solution ici
  4. Plus la peine de vous le dire, rendons-nous dans le fichier src/clients/graphql.js pour implémenter la fonction addNewPost :

    export async function addNewPost(newPost) {}
    Découvrer la solution ici
    export async function addNewPost(newPost) {
        await axios.post("/graphql", {
            query: `mutation createPost($newPost: PostInput!) {
                createPost(newPost:PostInput) {
                    id,
                    title,
                    content
                }
            }`,
            variables: {
                newPost
            }
        });
    }
    

Conclusion

Le workshop est terminé, merci de votre participation.

Points à conclure https://slides.com/mbreton/graphql-workshop#/5

graphql-workshop's People

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.