6/12/2022
tech
This is some text inside of a div block.
How to write an introduction email with 5 samples and template
Introduction emails are critical in the business world. In this guide we walk you through each step of the process and provide 5 examples.
JUN 26, 2023
produit

GraphQL / Postgres / Hasura / Next.js : la stack GPHN

6/12/2022
scroll to content
GraphQL / Postgres / Hasura / Next.js : la stack GPHN
linkedin
twitter
Title document

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.

Merci ! C’est dans la boîte :)
Une erreur est arrivée ! Veuillez Recommencer.

Title document

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.

Julien Fournier - Tech Lead & Coordinateur d'agence

Next.js : le framework React nouvelle génération

Next.js est un framework React open source créé par Vercel qui vient apporter tout un cadre de travail à la librairie React et des fonctionnalités supplémentaires. Lorsque nous utilisons React, nous avons souvent besoin d'outils externes afin de réaliser certaines tâches, comme React-Router ou React Intl, qui sont déjà intégrés dans Next.js.

Et surtout, un site web créé via React est très difficile à référencer par les "crawlers" (les robots de Google et autres) car React est une librairie rendue côté client, c'est-à-dire que le contenu est chargé uniquement via Javascript après le chargement initial de la page. Les robots voient souvent une page blanche lors de la lecture du code source du site.

Next.js répond à cette problématique et permet donc de réaliser un site web SEO Friendly grâce à sa fonction de rendu côté serveur, appelée Server-Side Rendering (SSR). C'est ce qui fait sans doute sa plus grande force.

Dans le cadre de ce rendu, chaque page va être générée côté serveur pour chaque requête utilisateur. Si un appel API est nécessaire, il sera fait à chaque fois pour récupérer les données avant de les renvoyer au client.

Les avantages du SSR :

  • Les données sont toujours fraîches
  • Le site peut avoir une infinité de pages

Les inconvénients :

  • Absence d'un gestionnaire d'état global intégré, par conséquent nous aurons également besoin de Redux, MobX (ou autre)
  • Le déploiement est plus complexe, car il faut NodeJS pour lancer le serveur

Lors de la création de votre site web, vous pourrez par exemple :

  • Utiliser le rendu côté serveur pour les pages qui ont besoin d’être indexées par les moteurs de recherche (SEO Friendly)
  • Utiliser le rendu côté client pour la partie d'administration car ces pages n'ont pas besoin d’être référencées (No SEO Friendly)
  • Utiliser la génération statique pour les pages dont le contenu ne change pas souvent et qui a aussi besoin d’être indexé par les moteurs de recherche (SEO Friendly)

Quelques exemples de fonctionnalités intégrées à Next.js :

  • Un système de routing très simple à utiliser
  • Création de pages statiques très rapides et optimisées pour le SEO
  • Optimisation automatique des images
  • Internationalisation
  • Zéro configuration
  • Rendu côté serveur si on en a besoin
  • Support de Typescript et Sass
  • Rechargement rapide
  • Création d'une API directement depuis Next.js
  • Etc.

Qui l'utilise ?

Twitch, Netflix Jobs, Github Copilot, Nike, Binance, Auth0, Playstation, Material UI, Lego, Docker, Deliveroo, ... Voir plus

GraphQL : le langage de requête

GraphQL est un langage de requêtage d’API développé par Facebook. Tout comme REST, GraphQL est une méthode d’implémentation d’API répondant à des standards.

GraphQL vs REST

Il existe 5 grands points différenciant les deux types d’API :

  • Nombre de routes

Dans une API REST, chaque route est prévue pour renvoyer un certain type de données. Il est usuel de définir des routes GET, POST, UPDATE, DELETE pour chaque table présente dans la base de données.

Dans GraphQL, une seule route est nécessaire. Toutes les requêtes sont envoyées à la même route et cette dernière est capable de traiter toutes les demandes. En réalité, il faut deux routes et non pas une. Une en GET et une en POST.

  • Over-fetching / Under-fetching

Dans une implémentation REST, chaque route renvoie une certaine structure de données qui est fixe. Même si le client n’a pas besoin de connaître l’âge d’un utilisateur, l’API le renverra pour chaque profil utilisateur, car c’est ce pourquoi elle a été programmée. Ici, l’API a le pouvoir.

Dans le cas de GraphQL, la route ne renvoie QUE les données que le client demande. Si le client n’a pas l’utilité de connaître l’âge d’un utilisateur alors l’API ne renverra pas l’âge pour chaque utilisateur. Dans ce cas-ci l’API adapte sa réponse en fonction de la demande du client. Ici, le client a le pouvoir.

  • Syntaxe simple

Un élément particulièrement intéressant de l’approche GraphQL est la syntaxe des requêtes car la requête envoyée correspond au format de la réponse attendue. Ce qui donne des requêtes simples, logiques et claires.

Exemple de requête permettant de récupérer les attributs author_id, first_name et last_name d'une table authors :

Requête
Requête

Cette requête nous permet de récupérer la réponse suivante :

Réponse
Réponse

  • Nombre de requêtes nécessaire pour obtenir les données souhaitées

À savoir que GraphQL est un bon choix architectural si le site web et sa structure de données font appel à de nombreuses requêtes. C'est également intéressant lorsque les objets retournés ont beaucoup de propriétés et de nombreuses relations avec d'autres objets.

Avec une API Rest, si nous souhaitons requêter un film pour obtenir ses détails, ses commentaires et l'auteur de chaque commentaire, il nous faudra plusieurs requêtes distinctes.

Avec GraphQL, cela peut être effectué de façon plus programmatique, et permettre au client de requêter les seules informations souhaitées au final.

Exemple :

GraphQL se base sur des schémas pour connaître le format des données qu’il va servir. Ces schémas sont décrits dans un simple fichier texte.

Exemple :

Exemple schéma
Exemple schéma

L'exemple de schéma ci-dessus décrit un objet author qui contient trois champs:  author_id, first_name et last_name.

Nous pouvons faire de même avec des fonctions permettant d’interagir avec l’API en définissant leurs prototypes.

Exemple de prototype de type Query :

Exemple de prototype de type Query
Exemple de prototype de type Query

Les prototypes de type Query correspondent à des fonctions de récupération simple d’information (comme des GET).

Ici, nous indiquons que l’API peut renvoyer une liste d’auteurs et qu’elle accepte des paramètres de recherche, author_id, first_name et last_name.

Exemple de prototype de type Mutation :

Exemple de prototype de type mutation
Exemple de prototype de type mutation

Les prototypes de type Mutation correspondent aux fonctions d’altération de la base de données (comme des POST, UPDATE ou DELETE). Ici, l'API permet d'ajouter un auteur, de mettre à jour les informations d’un auteur ou bien de supprimer une entrée author.

Hasura : le moteur d'API GraphQL en temps réel et instantané

Présentation

Hasura est un produit open source depuis 2018 qui accélère considérablement le développement en nous donnant des API GraphQL ou REST avec une autorisation intégrée sur nos données, instantanément.

Hasura facilite l'accès aux données, en composant instantanément une API GraphQL qui s'appuie sur des bases de données et des services afin que l'équipe de développeurs (ou les consommateurs d'API) deviennent immédiatement productifs. La nature même de GraphQL et l'approche dynamique d'Hasura facilitent l'intégration et l'itération.

Le moteur d'événements de Hasura permet d'adopter la technologie "cloud-native" sans avoir à s'inquiéter de la mise à l'échelle des éléments non fonctionnels, de la fiabilité et des garanties de livraison.

Les développeurs peuvent facilement construire une logique d'entreprise qui publie et consomme des événements, qui réagit aux changements de données ou qui est programmée en fonction du temps.

De nombreuses fonctionnalités

  • Effectuer des requêtes puissantes : filtrage intégré, pagination, recherche de modèles, insertion en masse, mise à jour, suppression de mutations
  • Fonctionne avec des bases de données existantes et actives : il suffit de la faire pointer vers une base de données existante pour obtenir instantanément une API GraphQL prête à l'emploi
  • Temps réel : convertir n'importe quelle requête GraphQL en une requête en direct à l'aide d'abonnements
  • Fusionner des schémas distants : accéder à des schémas GraphQL personnalisés pour la logique métier via un seul point de terminaison du moteur GraphQL. (En savoir plus)
  • Étendre avec des actions : écrire des API REST pour étendre le schéma de Hasura avec une logique métier personnalisée
  • Déclencher des webhooks ou des fonctions sans serveur : sur les événements d'insertion/mise à jour/suppression de Postgres (en savoir plus)
  • Déclencheurs planifiés : exécuter une logique métier personnalisée à des moments précis à l'aide d'une configuration cron ou d'un événement ponctuel.
  • Contrôle d'accès précis : contrôle d'accès dynamique qui s'intègre à notre système d'authentification (par exemple : auth0, firebase-auth)
  • Interface utilisateur d'administration et migrations : Admin UI et migrations de schémas inspirées de Rails
  • Bases de données prises en charge : PostgreSQL (et ses variantes), MS SQL Server et Big Query. Prise en charge de plus de bases de données à venir
  • Création de seeds et de migrations : les migrations permettent de répliquer les modifications dans notre schéma de base de données de manière sécurisée et les seeds permettent ensuite la création d'un "faux" ensemble de données dans la base de données

Avec Hasura nous avons donc une interface utilisateur qui nous permet de gérer notre base de données, de créer des rôles et ainsi de leur donner des droits sur chaque colonne de chaque table.

Étant donné qu'un CRUD API basé sur notre base de données est auto-généré, il est également possible de tester des requêtes GraphQL via l'explorateur API :

Explorateur API
Explorateur API

Si nous avons des appels API à effectuer depuis notre site web vers des services externes (ex : Mapbox, Google, Stripe, ou tout autre service), il est possible de créer des schémas distants via Apollo Server (ou autre) de façon à ce qu'ils soient fusionnés avec Hasura et que l'on ait toujours qu'un seul endpoint à appeler (notre endpoint Hasura) :

Schémas distants
Schémas distants

Hasura permet également de déporter une partie de la logique métier en dehors de notre site web afin qu'elle soit gérée par Hasura grâce aux actions :

Actions
Actions

Autre fonctionnalité intéressante (uniquement disponible en mode Cloud et avec l'offre Hasura Entreprise Edition), un onglet de monitoring :

Monitoring
Monitoring

Pour en finir avec ce listing des fonctionnalités d'Hasura, l'onglet "événements" offre la possibilité de créer des déclencheurs d'événements :

Déclencheur d'évènement
Déclencheur d'évènement

Comment l'utiliser ?

Si vous souhaitez tester Hasura, il est possible de le mettre en place en quelques secondes de 2 façons différentes :

À savoir que l'offre gratuite d'Hasura Cloud est faite pour un usage personnel et la création de sites "basiques" (60 requêtes par minute et transmission de données de 1GB par mois).

En savoir plus sur les offres.

Hasura a besoin d'un accès à une base de données Postgres pour stocker ses metadonnées et déployer son moteur GraphQL. Lors de la mise en place d'Hasura en mode Cloud, il est proposé de créer une base de données sur Heroku gratuitement et très rapidement via l'interface.

Une fois l’url de connexion à la base de données spécifiée à Hasura, les tables et les données seront affichées sur l’interface.

On peut ensuite choisir quelles données seront trackées par l’API (ex : si nous n'avons pas besoin d’ouvrir une table à notre api, il est possible de choisir de ne pas la tracker), de créer les rôles et de gérer les autorisations pour chaque colonne (ex : nous pouvons dire que le rôle User n’a pas accès à telle ou telle donnée). Tout cela se fait dans la section data de l’interface Hasura.

Remarque importante : nous ne sommes pas obligés d'utiliser l'interface d'Hasura pour créer nos tables et colonnes de la base de données, il est d'ailleurs recommandé d'utiliser le système de migrations et la création de seeds de façon à gérer des données initiales.

Ensuite on peut se rendre dans la section api de l’interface Hasura pour faire des requêtes.

Qui l'utilise ?

Airbus, The Marshall Project, BBVA, Cajoo, Philips Healthcare, ... Voir plus

Mon retour d'expérience

J'ai déjà utilisé Hasura dans le cadre professionnel pour le groupe Vinci dans ma précédente entreprise, avec une stack Next.js, GraphQL et React Admin qui est désormais en production, j'ai beaucoup aimé.

Le seul défaut que je peux trouver à Hasura (si on peut vraiment appeler ça un « défaut ») c’est qu’il ne fourni pas d’interface d’administration de contenu, donc il faut la créer nous-même via un React Admin, Easy Admin, Forest Admin, en sur-mesure ou autre. À l'instar d'un outil comme Strapi qui combine à la fois l'API et l'interface d'administration.

De plus, j'aime beaucoup le fait qu'Hasura s'appuie principalement sur le gestionnaire de base de données PostgreSQL qui est selon-moi le meilleur choix possible pour créer un site web. Plus besoin de le présenter, Postgres est une valeur sûre qui a fait ses preuves depuis plus de 30 ans, il est fiable et performant. Et encore plus quand il y a des calculs et/ou de grosses requêtes à effectuer.

Pourquoi la stack GPHN ?

Next.js nous permettra d'avoir entre les mains un vrai cadre de travail avec une architecture de dossiers pré-définie, ainsi que de créer des sites internet performants et SEO Friendly (si on le souhaite) grâce au rendu côté serveur et aux diverses fonctionnalités qui lui sont intégrées.

GraphQL va nous donner la possibilité de faire de belles requêtes à notre endpoint Hasura en installant Apollo Client (c'est le plus connu mais il existe d'autres alternatives) sur notre site web et d'avoir un système de mise en cache des requêtes.

Hasura sera notre API synchronisée en temps réel à notre base de données Postgres. Hasura nous fournira un backend sur lequel effectuer toutes nos requêtes GraphQL depuis le site web ainsi que toute la gestion de rôles.

L'objectif est aussi de créer des actions afin de déléguer notre logique métier à Hasura et des schémas distants lorsqu'il s'agit d'appels vers des services externes, de façon à avoir qu'un seul et unique endpoint à appeler.

Par exemple, si nous souhaitons effectuer un appel API à Mapbox de façon à mettre en place du forward geocoding / reverse geocoding, au lieu d'appeler cette API depuis le site web, nous allons plutôt créer un schéma distant (qui est un serveur GraphQL sur-mesure) sur lequel nous allons écrire nos fonctions et ensuite donner son URL à Hasura de façon à ce qu'il fusionne ce nouveau schéma dans notre schéma existant.

🚀 Bonus : ajouter Typescript et CodeGen à notre stack  

Le but est de typer notre code javascript de façon à le rendre plus strict et d'éviter les erreurs grâce à Typescript. Cependant, la rédaction des types prend du temps et CodeGen va nous permettre de les rédiger à notre place, c'est tout simplement magique. ✨

Typescript

Définition selon Wikipedia :

TypeScript est un langage de programmation libre et open source développé par Microsoft qui a pour but d'améliorer et de sécuriser la production de code JavaScript. Il s'agit d'un sur-ensemble syntaxique strict de JavaScript (c'est-à-dire que tout code JavaScript correct peut être utilisé avec TypeScript). Le code TypeScript est transcompilé en JavaScript, et peut ainsi être interprété par n'importe quel navigateur web ou moteur JavaScript. TypeScript a été cocréé par Anders Hejlsberg, principal inventeur de C#.

TypeScript permet un typage statique optionnel des variables et des fonctions, la création de classes et d'interfaces, l'import de modules, tout en conservant l'approche non-contraignante de JavaScript. Il supporte la spécification ECMAScript 6.

En d'autres termes, il faut juste comprendre que c'est une surcouche à Javascript qui permet de le typer et même de le transpiler dans la version de Javascript de notre choix.

CodeGen

CodeGen permet de générer du code à partir de notre schéma et de nos opérations GraphQL avec une simple CLI.

Quels intérêts ?

Comme expliqué précédemment dans le point GraphQL : le langage de requête :

GraphQL se base sur des schémas pour connaitre le format des données qu’il va servir. Ces schémas sont décrits dans un simple fichier texte.

Et donc l'idée serait de générer les types TypeScript basés sur notre schéma GraphQL en instantané. Cela permettra de nous faire gagner beaucoup d'heures de travail car nous n'aurons pas à nous soucier de rédiger les types TypeScript et nous connaîtrons chaque type d'entrée / sortie de nos requêtes GraphQL.

Par exemple, admettons que nous ajoutons / supprimons / modifions une colonne dans la base de données, CodeGen détectera un changement dans notre schéma et re-générera automatiquement nos types.

Pour ce faire, il suffit d'installer la librairie CodeGen dans notre projet Next.js, de créer notre configuration dans le fichier codegen.yml à la racine du projet et de lancer la commande npm run codegen.

Voici un exemple de fichier codegen.yml :

overwrite: true schema: - https://myapp.hasura.app/v1/graphql: headers: 'x-hasura-admin-secret': 0BcZdfroG4Oi9WNMOpi0CRaUwZBsbql1SirmlQXZKSFwfBkVRYNzuzHnFmrWRO0X documents: ['./src/**/*.tsx', './src/**/*.ts'] generates: generated/graphql.tsx: plugins: - "typescript" - "typescript-operations" - "typescript-react-apollo" config: skipTypename: false withHooks: true withHOC: false withComponent: false ./graphql.schema.json: plugins: - "introspection"

Dans cet exemple nous disons à CodeGen de lire le schéma GraphQL spécifié ainsi que tous les documents GraphQL rédigés dans le dossier src et ses sous-dossiers.

La ligne 8 correspond au chemin dans lequel CodeGen va générer les types.

Les autres lignes sont des configurations supplémentaires qui permettent par exemple de dire à CodeGen d'utiliser les plugins listés.

Exemple de génération CodeGen d'une requête GraphQL en Typescript

La requête ci-dessous permet de récupérer un événement par son identifiant, il attend une variable <event_id> de type <uuid> qui est obligatoire via le <!>. 

Cette requête est écrire dans un fichier <.ts> dans le projet Next.js (un sous-dossier de <src> pour correspondre à la configuration ci-dessus) et lorsque l'on va exécuter la commande <npm run codegen>, CodeGen va écrire sa génération dans <generated/graphql.tsx>  (toujours par rapport à la configuration ci-dessus).

import { gql } from "@apollo/client"; export const GET_EVENT_BY_ID = gql` query EventById($event_id: uuid!) { event_by_pk(event_id: $event_id) { name photo_url start_date user { establishment { name } } place { location } description end_date created_at } } `;

Le résultat 👌 :

export type EventByIdQueryVariables = Exact<{ event_id: Scalars["uuid"]; }>; export type EventByIdQuery = { __typename?: "query_root"; event_by_pk?: { __typename?: "event"; name: string; photo_url?: string | null; start_date: any; description: string; end_date: any; created_at?: any | null; user: { __typename?: "user"; establishment?: { __typename?: "establishment"; name: string } | null; }; place: { __typename?: "place"; location: any }; } | null; }; export const EventByIdDocument = gql` query EventById($event_id: uuid!) { event_by_pk(event_id: $event_id) { name photo_url start_date user { establishment { name } } place { location } description end_date created_at } } `; export function useEventByIdQuery( baseOptions: Apollo.QueryHookOptions ) { const options = { ...defaultOptions, ...baseOptions }; return Apollo.useQuery( EventByIdDocument, options ); } export function useEventByIdLazyQuery( baseOptions?: Apollo.LazyQueryHookOptions< EventByIdQuery, EventByIdQueryVariables > ) { const options = { ...defaultOptions, ...baseOptions }; return Apollo.useLazyQuery( EventByIdDocument, options ); } export type EventByIdQueryHookResult = ReturnType; export type EventByIdLazyQueryHookResult = ReturnType< typeof useEventByIdLazyQuery >; export type EventByIdQueryResult = Apollo.QueryResult< EventByIdQuery, EventByIdQueryVariables >;

CodeGen a généré le typage des variables attendues par la requête, le typage de la requête, le document, des hooks et le typage de retour sans que l'on ai à les écrire nous-même, c'est donc un gros gain de temps !

linkedin

+ d’articles

Vous avez un
produit
en tête ?
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

✅ Merci ! Votre contenu est en route.
Oops ! Il y a eu une erreur... Veuillez recommencer.
Vos données sont en sécurité et vous pouvez vous désinscrire à tout moment. En soumettant ce formulaire vous acceptez d'être recontacté par nos équipes.

Heading

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

✅ Merci ! Votre contenu est en route.
Oops ! Il y a eu une erreur... Veuillez recommencer.
Vos données sont en sécurité et vous pouvez vous désinscrire à tout moment.