Comment créer une API Secure Node.js GraphQL

Publié: 2022-03-11

Dans cet article, nous visons à présenter un guide rapide sur la façon de créer une API Node.js GraphQL sécurisée.

Certaines questions qui peuvent venir à l'esprit pourraient être :

  • Quel est le but d'utiliser une API GraphQL ?
  • Qu'est-ce qu'une API GraphQL ?
  • Qu'est-ce qu'une requête GraphQL ?
  • Quel est l'avantage de GraphQL ?
  • GraphQL est-il meilleur que REST ?
  • Pourquoi utilisons-nous Node.js ?

Toutes ces questions sont valables, mais avant d'y répondre, nous devrions nous plonger dans un bref aperçu de l'état actuel du développement Web :

  • Presque toutes les solutions que vous trouverez aujourd'hui utilisent une sorte d'interface de programmation d'application (API).
  • Même si vous n'utilisez qu'un réseau social, comme Facebook ou Instagram, vous êtes toujours connecté à un frontal qui consomme une API.
  • Si vous êtes curieux, vous constaterez que presque tous les services de divertissement en ligne utilisent un type d'API différent, y compris des services comme Netflix, Spotify et YouTube.

Dans pratiquement tous les scénarios, vous trouverez une API que vous n'avez pas besoin de connaître en détail, par exemple, vous n'avez pas besoin de savoir comment elles ont été construites, et vous n'avez pas besoin d'utiliser la même technologie qu'avant capable de l'intégrer dans votre propre système. L'API fournie vous permet d'offrir un moyen de communiquer entre les services dans une norme commune que le service et le client peuvent communiquer sans avoir à dépendre d'une pile technologique spécifique.

Avec une API bien structurée, il est possible d'avoir une API solide, maintenable et évolutive qui peut servir plusieurs types de clients et d'applications frontales.

Cela dit, qu'est - ce que l'API GraphQL ?

GraphQL est un langage de requête pour les API, développé pour un usage interne dans Facebook et publié pour un usage public en 2015. Il prend en charge la lecture, l'écriture et les mises à jour en temps réel. Il est également open source et est couramment comparé à REST et à d'autres architectures. Il est, en quelques mots, basé sur :

  • Requêtes GraphQL - Cela permet au client de lire et de manipuler la manière dont les données doivent être reçues.
  • Mutations GraphQL - Voici comment écrire des données sur le serveur. C'est la convention GraphQL sur la façon d'écrire des données dans le système.

Bien que cet article soit censé démontrer un scénario simple mais réaliste sur la façon de créer et d'utiliser les API GraphQL, nous ne fournirons pas une introduction détaillée à GraphQL. La raison est simple, car l'équipe GraphQL fournit une documentation complète et répertorie plusieurs bonnes pratiques dans leur Introduction à GraphQL.

Qu'est-ce qu'une requête GraphQL ?

Comme décrit précédemment, une requête est la manière dont un client peut lire et manipuler les données de l'API. Vous pouvez transmettre le type d'un objet et sélectionner le type de champs que vous souhaitez recevoir en retour. Une requête simple ressemblerait à ceci :

 query{ users{ firstName, lastName } }

Dans cette requête, nous essayons d'atteindre tous les utilisateurs à partir du schéma de nos utilisateurs, mais nous ne recevons que firstName et lastName . Le résultat de cette requête serait comme, par exemple :

 { "data": { "users": [ { "firstName": "Marcos", "lastName": "Silva" }, { "firstName": "Paulo", "lastName": "Silva" } ] } }

C'est assez simple pour l'utilisation du client.

Quel est le but de l'utilisation d'une API GraphQL ?

Le but de la création d'une API est la possibilité d'avoir un logiciel en tant que service qui peut être intégré par d'autres services externes. Même si votre application est consommée par un seul front-end, vous pouvez considérer ce front-end comme un service externe, et pour cela, vous pourrez travailler dans différents projets lorsque la communication entre les deux est assurée via l'API.

Si vous travaillez dans une grande équipe, celle-ci peut être scindée pour créer une équipe front-end et back-end, permettant aux deux d'utiliser la même technologie et de faciliter leur travail. Lors de la conception d'une API, il est important de choisir la meilleure solution pour le projet et ce qui vous rapproche de la solution souhaitée.

Dans cet article, nous nous concentrerons sur un squelette pour construire une API qui utilise GraphQL.

GraphQL est-il meilleur que REST ?

C'est peut-être un peu une échappatoire, mais je n'y peux rien : ça dépend .

GraphQL est une approche qui s'adapte très bien à plusieurs scénarios. REST est une approche d'architecture qui a également fait ses preuves dans plusieurs scénarios. De nos jours, il existe des tonnes d'articles qui expliquent pourquoi l'un est meilleur que l'autre ou pourquoi vous ne devriez utiliser que REST au lieu de GraphQL. Et aussi, de nombreuses façons d'utiliser GraphQL en interne tout en conservant les points de terminaison de l'API en tant qu'architecture basée sur REST.

Le meilleur conseil serait de connaître les avantages de chaque approche, d'analyser la solution que vous créez, d'évaluer à quel point votre équipe est à l'aise avec la solution et d'évaluer si vous serez en mesure ou non de guider votre équipe pour apprendre et se mettre à niveau. accélérez rapidement avant de choisir entre les approches.

Cet article est plus un guide pratique qu'une comparaison subjective de GraphQL et REST. Si vous souhaitez lire une comparaison détaillée des deux, je vous suggère de consulter un autre de nos articles, GraphQL vs REST - Un didacticiel GraphQL.

Dans l'article d'aujourd'hui, nous nous concentrerons sur la création d'une API GraphQL à l'aide de Node.js.

Pourquoi utilisons-nous Node.js ?

GraphQL a plusieurs bibliothèques différentes que vous pouvez utiliser. Pour les besoins de cet article, nous avons décidé d'utiliser JavaScript avec Node.js en raison de leur utilisation généralisée et du fait que Node.js permet aux développeurs d'utiliser une syntaxe frontale familière pour le développement côté serveur.

Il est également utile de comparer avec notre approche avec une API basée sur REST, similaire à celle qui a été démontrée dans un autre article du blog Toptal Engineering : Création d'une API REST sécurisée dans Node.js. Cet article présente également l'utilisation de Node.js avec Express pour développer une API REST squelette qui vous permettra de comparer certaines différences entre ces deux approches. Node.js a également été conçu avec des applications réseau évolutives, une communauté mondiale et plusieurs bibliothèques open source que vous pouvez trouver sur le site Web npm.

Cette fois-ci, nous allons montrer comment créer une API squelette avec GraphQL, Node.js et Express !

Tutoriel pratique sur GraphQL

Comme indiqué précédemment, nous allons construire une idée de squelette pour l'API GraphQL, et vous devrez connaître les bases de Node.js et Express avant de continuer. Le code source du projet réalisé pour cet exemple GraphQL est disponible ici.

Nous allons gérer deux types de ressources :

  • Les utilisateurs, pour lesquels nous allons gérer un CRUD de base.
  • Produits, pour lesquels nous aurons un peu de détail pour montrer davantage la puissance de GraphQL.

Les utilisateurs contiendront la structure suivante :

  • identifiant
  • Prénom
  • nom de famille
  • e-mail
  • le mot de passe
  • permissionLevel

Les produits contiendront la structure suivante :

  • identifiant
  • Nom
  • la description
  • le prix

En ce qui concerne la norme de codage, nous allons utiliser TypeScript pour ce projet. Dans le fichier source, vous pourrez tout configurer pour commencer à coder avec TypeScript.

Codez !

Tout d'abord, assurez-vous que la dernière version de Node.js est installée. Au moment de la publication, la version actuelle est 10.15.3, selon Nodejs.org.

Initialisation du projet

Commençons dans un nouveau dossier que nous pouvons nommer node-graphql . Là, nous pouvons ouvrir un terminal ou une console Git CLI et démarrer la magie en utilisant la commande suivante : npm init .

Configurer nos dépendances et TypeScript

Pour accélérer le processus, le remplacement de votre package.json par ce qui suit dans notre référentiel Git doit contenir toutes les dépendances nécessaires :

 { "name": "node-graphql", "version": "1.0.0", "description": "", "main": "dist/index.js", "scripts": { "tsc": "tsc", "start": "npm run tsc && node ./build/app.js" }, "author": "", "license": "ISC", "dependencies": { "@types/express": "^4.16.1", "@types/express-graphql": "^0.6.2", "@types/graphql": "^14.0.7", "express": "^4.16.4", "express-graphql": "^0.7.1", "graphql": "^14.1.1", "graphql-tools": "^4.0.4" }, "devDependencies": { "tslint": "^5.14.0", "typescript": "^3.3.4000" } }

Avec le package.json mis à jour, appuyez à nouveau sur le terminal et utilisez : npm install . Il installera toutes les dépendances nécessaires pour exécuter cette API GraphQL dans Node.js et Express.

La prochaine étape consiste à configurer notre mode TypeScript. Nous avons besoin d'un fichier appelé tsconfig.json dans notre dossier racine avec les éléments suivants :

 { "compilerOptions": { "target": "ES2016", "module": "commonjs", "outDir": "./build", "strict": true, "esModuleInterop": true } }

La logique du code pour cette configuration sera présente dans le dossier de l'application. Là, nous pouvons créer un fichier app.ts et pour les tests de base, y ajouter le code suivant :

 console.log('Hello Graphql Node API tutorial');

Par notre configuration, nous pouvons maintenant exécuter npm start et attendre une construction et être en mesure de tester que tout fonctionne correctement. Dans votre console de terminal, vous devriez voir notre "Tutoriel de l'API Hello GraphQL Node". Dans la scène arrière, la configuration compile essentiellement le code TypeScript en JavaScript pur, puis exécute notre construction dans le dossier de build .

Configurons maintenant un squelette de base pour notre API GraphQL. Pour démarrer notre projet, nous allons ajouter trois importations de base :

  • Express
  • Express-graphql
  • Outils Graphql

Commençons à tout assembler :

 import express from 'express'; import graphqlHTTP from 'express-graphql'; import {makeExecutableSchema} from 'graphql-tools';

Maintenant, nous devrions pouvoir commencer à coder un peu. La prochaine étape consiste à gérer notre application dans Express et la configuration de base de GraphQL comme :

 import express from 'express'; import graphqlHTTP from 'express-graphql'; import {makeExecutableSchema} from 'graphql-tools'; const app: express.Application = express(); const port = 3000; let typeDefs: any = [` type Query { hello: String } type Mutation { hello(message: String) : String } `]; let helloMessage: String = 'World!'; let resolvers = { Query: { hello: () => helloMessage }, Mutation: { hello: (_: any, helloData: any) => { helloMessage = helloData.message; return helloMessage; } } }; app.use( '/graphql', graphqlHTTP({ schema: makeExecutableSchema({typeDefs, resolvers}), graphiql: true }) ); app.listen(port, () => console.log(`Node Graphql API listening on port ${port}!`));

Ce que nous faisons c'est :

  • Activation du port 3000 pour notre application serveur Express.
  • Définir les requêtes et les mutations que nous voulons utiliser comme exemple rapide.
  • Définir comment les requêtes et les mutations vont fonctionner.

OK, mais que se passe-t-il pour les typeDefs et les résolveurs, ainsi que la relation avec les requêtes et les mutations ?

  • typeDefs - La définition de notre schéma de ce que nous pouvons attendre des requêtes et des mutations.
  • Résolveurs - Au lieu d'attendre des champs ou des paramètres requis, nous définissons ici les fonctions et les comportements du fonctionnement des requêtes et des mutations.
  • Requêtes - Les « gets » que nous voulons lire à partir du serveur.
  • Mutations - Nos demandes qui vont affecter toutes les données que nous avons sur notre propre serveur.

Maintenant, lançons à nouveau npm start pour voir ce que nous avons là. Nous nous attendrions à ce que l'application s'exécute avec le message suivant : Node Graphql API listening on port 3000 !

Nous pouvons maintenant essayer d'interroger et de tester l'API GraphQL sur notre propre serveur via : http://localhost:3000/graphql

Tutoriel GraphQL : test du serveur

Super, maintenant nous pouvons écrire notre première requête qui a été définie comme "bonjour".

Tutoriel GraphQL : première requête

Notez que la façon dont nous l'avons défini au typeDefs , la page peut nous aider à construire la requête.

C'est très bien, mais comment pouvons-nous changer la valeur ? mutations !

Voyons maintenant ce qui se passe lorsque nous modifions notre valeur en mémoire avec une mutation :

Tutoriel GraphQL : démonstration de la mutation

Nous pouvons maintenant effectuer des opérations CRUD de base avec notre API GraphQL Node.js. Avançons avec notre code maintenant.

Des produits

Pour les produits, nous utiliserons un module appelé produits. Afin de simplifier cet article, nous allons utiliser une base de données en mémoire uniquement à des fins de démonstration. Nous allons définir un modèle et un service pour gérer les produits.

Notre modèle sera basé comme suit :

 export class Product { private id: Number = 0; private name: String = ''; private description: String = ''; private price: Number = 0; constructor(productId: Number, productName: String, productDescription: String, price: Number) { this.id = productId; this.name = productName; this.description = productDescription; this.price = price; } }

Le service qui communiquera avec GraphQL sera défini comme :

 export class ProductsService { public products: any = []; configTypeDefs() { let typeDefs = ` type Product { name: String, description: String, id: Int, price: Int } `; typeDefs += ` extend type Query { products: [Product] } `; typeDefs += ` extend type Mutation { product(name:String, id:Int, description: String, price: Int): Product! }`; return typeDefs; } configResolvers(resolvers: any) { resolvers.Query.products = () => { return this.products; }; resolvers.Mutation.product = (_: any, product: any) => { this.products.push(product); return product; }; } }

Utilisateurs

Pour les utilisateurs, nous suivrons la même structure que le module produits. Nous aurons un modèle et un service pour les utilisateurs. Le modèle sera défini comme :

 export class User { private id: Number = 0; private firstName: String = ''; private lastName: String = ''; private email: String = ''; private password: String = ''; private permissionLevel: Number = 1; constructor(id: Number, firstName: String, lastName: String, email: String, password: String, permissionLevel: Number) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.email = email; this.password = password; this.permissionLevel = permissionLevel; } }

Pendant ce temps, notre service ressemblera à :

 const crypto = require('crypto'); export class UsersService { public users: any = []; configTypeDefs() { let typeDefs = ` type User { firstName: String, lastName: String, id: Int, password: String, permissionLevel: Int, email: String } `; typeDefs += ` extend type Query { users: [User] } `; typeDefs += ` extend type Mutation { user(firstName:String, lastName: String, password: String, permissionLevel: Int, email: String, id:Int): User! }`; return typeDefs; } configResolvers(resolvers: any) { resolvers.Query.users = () => { return this.users; }; resolvers.Mutation.user = (_: any, user: any) => { let salt = crypto.randomBytes(16).toString('base64'); let hash = crypto.createHmac('sha512', salt).update(user.password).digest("base64"); user.password = hash; this.users.push(user); return user; }; } }

Pour rappel, le code source est disponible à l'utilisation depuis ce lien.

Nous pouvons maintenant jouer et tester notre code. npm start . Nous aurons le serveur fonctionnant sur le port 3000. Nous pouvons maintenant accéder à GraphQL pour tester à http://localhost:3000/graphql.

Essayons une mutation pour ajouter un article à notre liste de produits :

Démonstration de la mutation Node.js GraphQL

Pour tester si cela a fonctionné, nous allons maintenant utiliser une requête pour les produits, mais ne recevant que id , name et price :

 query{ products{ id, name, price } } The response will be: { "data": { "products": [ { "id": 100, "name": "My amazing product", "price": 400 } ] } }

Et c'est tout; le produit fonctionne comme prévu. Maintenant, nous pouvons jouer et changer de terrain si nous le voulons. Vous pouvez essayer d'ajouter une description :

 query{ products{ id, name, description, price } }

Maintenant, nous pouvons avoir les descriptions de nos produits. Essayons les utilisateurs maintenant.

 mutation{ user(id:200, firstName:"Marcos", lastName:"Silva", password:"amaz1ingP4ss", permissionLevel:9, email:"[email protected]") { id } }

Et une requête ressemblera à :

 query{ users{ id, firstName, lastName, password, email } }

Avec une réponse comme :

 { "data": { "users": [ { "id": 200, "firstName": "Marcos", "lastName": "Silva", "password": "kpj6Mq0tGChGbZ+BT9Nw6RMCLReZEPPyBCaUS3X23lZwCCp1Ogb94/oqJlya0xOBdgEbUwqRSuZRjZGhCzLdeQ==", "email": "[email protected]" } ] } }

Et maintenant notre squelette GraphQL est prêt ! Il y a des tonnes d'étapes à partir d'ici vers une API utile et entièrement fonctionnelle, mais le noyau de base est maintenant défini.

Résumé et réflexions finales

Même tranchant pour raccourcir, l'article est assez volumineux avec beaucoup d'informations de base concernant le développement d'une API GraphQL Node.js.

Passons en revue ce que nous avons couvert jusqu'à présent :

  • Utilisation de Node.js avec Express et GraphQL pour créer une API GraphQL ;
  • Utilisation de base de GraphQL ;
  • Utilisation de base des requêtes et des mutations ;
  • Approche de base pour créer des modules pour votre projet ;
  • Tester notre API GraphQL ;

Pour nous concentrer davantage sur le côté développement des choses, nous avons évité plusieurs éléments importants qui peuvent être brièvement résumés comme suit :

  • Validations pour les nouveaux articles ;
  • Gérer correctement les erreurs avec un service d'erreur générique ;
  • Valider les champs qu'un utilisateur peut utiliser à chaque requête avec un service générique ;
  • Ajoutez un intercepteur JWT pour sécuriser l'API ;
  • Gérez le hachage du mot de passe avec une approche plus efficace ;
  • Ajouter des tests unitaires et d'intégration ;

N'oubliez pas que nous avons le code source complet sur ce lien Git. N'hésitez pas à utiliser, bifurquer, ouvrir des problèmes, faire des demandes d'extraction et jouer avec ! Veuillez noter que toutes les normes et suggestions faites dans cet article ne sont pas gravées dans la pierre.

Ce n'est qu'une des nombreuses approches qui peuvent être utilisées pour commencer à concevoir votre propre API GraphQL. Assurez-vous également de lire et d'explorer GraphQL plus en détail, en apprenant ce qu'il a à offrir et comment il peut encore améliorer vos API.