Fermer

octobre 19, 2020

Comment créer votre première API REST avec Fastify


Fastify est un framework conçu pour le développement web back-end. Il offre une alternative plus légère aux frameworks d'API Node.js plus lourds, tels que Hapi et Express. Depuis juillet 2020, Fastify a publié sa troisième version du framework.

Cette troisième version est dotée de capacités de validation améliorées pour vérifier les requêtes entrantes et sortantes, en tant que paramètres de requête. De plus, la troisième version du framework consolide ses revendications de débit comme étant le framework Node.js le plus rapide par rapport à Koa, Resitfy, Hapi et Express. Plus d'informations peuvent être trouvées sur la page des benchmarks .

Fastify a gagné beaucoup de popularité en raison de sa conception légère. Cependant, une grande attention est portée à son écosystème de plugins . Fastify a adopté l'idée que tout est un plugin, alors qu'avec JavaScript, tout est un objet. Cela vous permet d'encapsuler rapidement les fonctionnalités de votre projet sous forme de plug-in et de les distribuer afin que d'autres projets puissent utiliser votre code.

Commençons avec ce didacticiel. Vous apprendrez les aspects suivants de Fastify:

  • Comment configurer votre première API Fastify
  • Comment définir les routes d'API Fastify
  • Comment ajouter une validation de schéma aux requêtes
  • Comment charger et utiliser les plugins Fastify
  • Comment définir les hooks Fastify

Configuration requise et installation

Pour suivre ce tutoriel, vous aurez besoin de:

  1. la dernière version de Node.js
  2. un outil pour envoyer des requêtes, tel que cURL ou Postman

Ensuite, assurez-vous de créer un projet Node.js vide. Si vous n'en avez pas encore, vous pouvez utiliser la commande suivante pour configurer votre projet:

 npm  init -y

Enfin, nous voulons ajouter cette dépendance Fastify à notre projet:

 npm  i fastify --save

Tout va bien? Créons notre configuration API de base à l'étape suivante.

Étape 1: Configuration API de base

Commençons par créer notre configuration API de base. Pour commencer, nous devons créer un nouveau fichier appelé index.js dans la racine de notre projet:

 touch  index.js

Ensuite, ajoutons la configuration de base du serveur. Copiez le code ci-dessous:


 const  app  =   require  ( 'fastify' )  ( {
    logger :   true 
} ) 


app .  get  ( '/'   function   ( req  reply )   {
    réponse .  envoyer  ( { bonjour :   'world'  } ) 
} ) 


app .  écoute  ( 3000   ( err  adresse )   =>   { 
     si   ( err )   {
        app .  log .  error  ( err ) 
        processus .  exit  ( 1 ) 
    } 
    app .  log .  info  ( ` server écoutant sur  $ { adresse } "  ) 
} ) 

Il se passe deux ou trois choses ici. Nous chargeons d'abord l'objet d'application Fastify et activons la journalisation. Ensuite, nous déclarons une route racine qui répond avec une réponse JSON. La dernière partie de l'extrait de code montre que nous écoutons sur le port 3000 pour que l'application reçoive des demandes.

Vérifions si la configuration de base de votre serveur fonctionne. Tout d'abord, nous devons démarrer le serveur en exécutant le fichier index.js :

 node index.js

Ensuite, accédez à http: // localhost: 3000 dans votre navigateur. Vous devriez voir la réponse suivante:

 {
     "hello" :   "world" 
} 

Succès? Passons à l’étape 2 pour définir différentes routes CRUD.

Étape 2: définir des routes CRUD

Une API est inutile avec uniquement des routes GET. Définissons d'autres itinéraires pour gérer les blogs. Par conséquent, créons les itinéraires suivants:

  • GET all blogs sur / api / blogs
  • GET one blog at / api / blogs /: id
  • POST add blog at / api / blogs
  • PUT update blog à / api / blogs /: id
  • SUPPRIMER supprimer le blog à / api / blogs /: id

La première chose à faire est de créer un contrôleur de blog.

Étape 2.1: Créer un contrôleur de blogs

À conserver notre code propre, définissons un dossier controller à la racine du projet. Ici, nous créons un fichier appelé blogs.js .

Ce fichier contient des données de démonstration pour éviter de compliquer ce tutoriel avec une intégration de base de données. Par conséquent, nous utilisons un tableau contenant des objets de blog qui contiennent chacun un champ ID et titre.

De plus, nous définissons les différents gestionnaires pour toutes les routes ci-dessus dans ce fichier. Un gestionnaire accepte toujours un paramètre req (request) et reply . Le paramètre request est utile pour accéder aux paramètres de la requête ou aux données du corps de la requête.

Ajoutez le code suivant à votre fichier /controller/blogs.js :


 let  blogs  = [19659038] [
     {
        id :   1 
        title :   'Ceci est une expérience' 
    } 
     {
        id :   2 
        title :   'Fastify est plutôt cool' 
    } 
     {
        id :   3 
        title :   'Juste un autre blog, oui!' 
    } 
] 


 const   getAllBlogs   =   async   ( req  ] réponse )   =>   {
     retour  blogs
} 

 const   getBlog   =   async   ( req  reply )   =>   {[19659059] const  id  =   Number  ( req .  params .  id )  
     const  blog  =  blogs .  find  ( blog   =>  blog .  id   ===  ] id ) 
     retour  blog
} 

 const   addBlog   =   async   ( req  reply )   =>   {[19659059] const  id  =  blogs .  length   +   1  
     const  newBlog  =   {
        id 
        title :  req .  body .  title 
    } 

    blogs .  push  ( newBlog ) 
     return  newBlog
} 

 const   updateBlog   =   async   ( req  reply )   =>   {[19659059] const  id  =   Number  ( req .  params .  id ) 
    blogs  =  blogs .  carte  ( blog   =>   {
         if   ( blog .  id   ===  id )   {
             return   {
                id 
                title :  req .  body .  title 
            } 
        } 
    } ) 

     return   {
        id 
        title :  req .  body .  title 
    } 
} 

 const   deleteBlog   =   async [19659038] ( req  reply )   =>   {
     const  id  =   Number  ( ] req .  params .  id ) 

    blogs  =  blogs .  filtre  ( blog   =>  blog .  id  ! ==  ] id ) 
     return   { msg :   ` Blog avec ID  $ { id }  [19659026] est supprimé  `  } 
} 

module .  exportations   =   {
    getAllBlogs 
    getBlog 
    addBlog 
    updateBlog 
    deleteBlog
} 

Notez comment nous pouvons accéder au paramètre de requête pour des routes telles que / api / blogs /: id via req.params.id . Pour les routes POST et PUT, nous pouvons accéder au corps de la requête via req.body .

À l'étape 2.2, nous allons connecter les gestionnaires de route aux objets de route.

Étape 2.2: Définir les itinéraires de blog et le contrôleur de couple de blogs

Encore une fois, pour garder notre code propre, définissons un dossier routes dans la racine du projet. Ici, nous créons un fichier appelé blogs.js . Ce fichier contient l'objet routes pour nos routes de blog:

 mkdir  routes
 cd  routes
 touchez  blogs.js

Heureusement, Fastify nous permet de définir un tableau contenant des objets route. Ici, nous pouvons coupler les gestionnaires que nous avons définis précédemment aux différentes routes. N'oubliez pas d'exiger le contrôleur de blogs. Jetons un œil:

 const  blogController  =   require  ( '../ controller / blogs' ) ; 

 const  ] routes  =   [ {
        méthode :   'GET' 
        url :   '/ api / blogs' 
        gestionnaire :  blogController .  getAllBlogs 
    } 
     {
        méthode :   'GET' 
        url :   '/ api / blogs /: id' 
        gestionnaire :  blogController .  getBlog 
    } 
     {
        méthode :   'POST' 
        url :   '/ api / blogs' 
        gestionnaire :  blogController .  addBlog 
    } 
     {
        méthode :   'PUT' 
        url :   '/ api / blogs /: id' 
        gestionnaire :  blogController .  updateBlog 
    } 
     {
        méthode :   'DELETE' 
        url :   '/ api / blogs /: id' 
        gestionnaire :  blogController .  deleteBlog 
    } 
] 
module .  exportations   =  routes

Nous avons maintenant défini tous les itinéraires. Cependant, Fastify ne connaît pas ces itinéraires. L'étape suivante montre comment enregistrer des itinéraires avec votre objet d'application Fastify.

Étape 2.3: Enregistrer des itinéraires Fastify

Dans cette étape, nous allons enregistrer les itinéraires Fastify vers l'objet d'application. Tout d'abord, nous chargeons toutes les routes du blog. Ensuite, nous bouclons sur toutes les routes pour les enregistrer une par une:


 const  app  =   require  ( 'fastify' )  ([19659025] {
    logger :   true 
} ) 


app .  get  ( '/'   function   ( req  reply )   {
    réponse .  envoyer  ( { bonjour :   'world'  } ) 
} ) 


 const  blogRoutes  =   requiert  ( './ routes / blogs' ) 
blogRoutes .  forEach  ( ( route  index )   =>   {
    app .  route  ( route ) 
} ) 


app .  écoute  ( 3000   ( err  adresse )   =>   { 
     si   ( err )   {
        app .  log .  error  ( err ) 
        processus .  exit  ( 1 ) 
    } 
    app .  log .  info  ( ` server écoutant sur  $ { adresse } "  ) 
} ) 

Terminé? Il est temps de valider si les itinéraires du blog fonctionnent. Lancez le serveur en utilisant node index.js et visitez http: // localhost: 3000 / blogs / 1 pour obtenir le premier blog à partir des données de démonstration. Vous devriez voir le résultat suivant:

 {
     "id" :   1 
     "title" :   "This is an experiment" [19659031]} 

Tout va bien? Apprenons à l'étape 3 comment ajouter la validation de schéma aux demandes et aux réponses.

Étape 3: Ajout de la validation de schéma

Cette étape vous apprend à ajouter la validation de schéma à votre projet. Nous pouvons utiliser la clé schema dans notre définition de routes pour passer un schéma de validation à une route particulière.

Commençons par définir un schéma pour la route / api / blogs /: id pour valider le paramètre de requête et la réponse. Exigences?

  1. : le paramètre id doit être de type chaîne
  2. La réponse doit contenir un objet avec deux propriétés id (entier) et titre (chaîne )

Ajoutez l'objet de validation suivant à votre fichier routes / blogs.js :

 const  getBlogValidation  =   {
        paramètres :   {
            id :   { type :   'string'  } 
        } 
        réponse :   {
             200 :   {
                type :   'objet' 
                propriétés :   {
                    id :   { type :   'integer'  } 
                    title :   { type :   'string'  } 
                } 
            } 
        } 
} 

Pour connecter l'objet de validation à notre route, nous devons définir la clé de schéma. Recherchez la route / api / blogs /: id dans le tableau routes et modifiez l'objet en conséquence:

 ... 
 {
    méthode :   'GET' 
    url :   '/ api / blogs /: id' 
    schéma :  getBlogValidation 
    handler :  blogController .  getBlog 
} 
 ... 

Faisons de même pour ajouter un blog POST / api / blogs . Ici, nous voulons vérifier si l'objet req.body contient un paramètre title . Jetons un coup d'œil:

 const  addBlogValidation  =   {
    carrosserie :   {
        type :   'objet' 
        requis :   [
             'title' 
        ] 
        propriétés :   {
            title :   { type :   'string'  } 
        } 
    } 
    réponse :   {
         200 :   {
            type :   'objet' 
            propriétés :   {
                id :   { type :   'integer'  } 
                title :   { type :   'string'  } 
            } 
        } 
    } 
} 

Ensuite, nous devons relier l'objet de validation à la bonne route:

 ... 
 {
    méthode :   'POST' 
    url :   '/ api / blogs' 
    schéma :  addBlogValidation 
    handler :  blogController .  addBlog 
} 
 ... 

Pour vérifier notre validation, récupérons le blog avec l'ID 3. Ouvrez votre navigateur à l'adresse http: // localhost: 3000 / api / blogs / 3 . Vous devriez voir la réponse suivante:

 {
     "id" :   3 
     "title" :   "Juste un autre blog, oui!" 
} 

Maintenant, faisons une erreur et changeons la validation params pour le champ id de sting à object comme ceci: [19659263] const getBlogValidation = {
paramètres : {
id : { type : 'objet' }
}
réponse : {
200 : {
type : 'objet'
propriétés : {
id : { type : 'integer' }
title : { type : 'string' }
}
}
}
}

Lorsque vous demandez la même ressource à votre API, vous recevrez le message d'erreur suivant.

 {
     "statusCode" :   400 
     "error" [19659088]:   "Bad Request" 
     "message" :   "params.id should be object" 
} 

Voyez-vous l'erreur? Bien! Revenons au changement de la chaîne pour éviter les erreurs futures et passons à l'étape suivante.

Étape 4: Charger les plugins Fastify

Ici, utilisons le riche écosystème de plugins de Fastify ]. Vous pouvez trouver des plugins qui vous aident dans diverses tâches, telles que les intégrations de bases de données ou les configurations d'autorisation. Pourquoi passeriez-vous du temps à rédiger une autorisation à partir de zéro alors que vous pouvez utiliser les plugins Fastify? Souvent, vous souhaitez rechercher des packages en dehors de l'écosystème de Fastify qui vous aident à résoudre certains problèmes ou certaines tâches. Cependant, en fournissant un riche écosystème de plugins, Fastify devient une solution unique qui améliore définitivement l'expérience des développeurs!

Une note rapide sur les plugins: vous pouvez créer vos propres plugins pour encapsuler les fonctionnalités. De plus, vous pouvez charger ces plugins dans votre objet d'application Fastify. Par défaut, Fastify chargera d'abord les plugins de l'écosystème Fastify . Ensuite, les plugins personnalisés sont chargés.

Ok, soyons pratiques! Je voudrais utiliser le plugin fastify-env qui vous aide à charger les variables d'environnement et à définir les valeurs par défaut pour chaque variable. Par conséquent, ajoutons cette dépendance à notre projet:

 npm   install  --save fastify-env

Ensuite, nous pouvons charger la dépendance après avoir chargé l'objet d'application Fastify dans le fichier index.js . Votre fichier index.js ressemble à ceci:


 const  app  =   require  ( 'fastify' )  ([19659025] {
    logger :   true 
} ) 


 const  fastifyEnv  =   require  ( 'fastify-env' ) [19659565] const  options  =   {
    confKey :   'config' 
    schéma :   {
        type :   'objet' 
        requis :   [ 'PORT' ] 
        propriétés :   {
             PORT :   {
                type :   'string' 
                 default :   1000 
            } 
        } 
    } 
} 

app
    .  register  ( fastifyEnv  options ) 
    .  ready  ( ( err  ])   =>   {
         if   ( err )   console .  error  ( err  ) 

         console .  log  ( app .  config ) 
        
    } ) 


app .  get  ( '/'   function   ( req  reply )   {
    réponse .  envoyer  ( { bonjour :   'world'  } ) 
} ) 


 const  blogRoutes  =   requiert  ( './ routes / blogs' ) 
blogRoutes .  forEach  ( ( route  index )   =>   {
    app .  route  ( route ) 
} ) 


app .  listen  ( app .  config .  PORT   ( err  adresse )   =>   {
     si   ( err )   {
        app .  log .  error  ( err ) 
        processus .  exit  ( 1 ) 
    } 
    app .  log .  info  ( ` server écoutant sur  $ { adresse } "  ) 
} ) 

Notez que nous devons définir un objet options qui indique au plugin fastify-env quelles variables d'environnement rechercher et quelles sont les valeurs par défaut à définir. Ici, je veux charger une variable PORT avec une valeur par défaut de 1000 .

Par défaut, le plugin fastify-env rendra toutes les variables d'environnement disponibles via l'objet d'application Fastify comme ceci: app.config.PORT . Pourquoi? Le plugin fastify-env attache les configurations chargées à la confKey qui par défaut est définie sur config . Cependant, si vous le souhaitez, vous pouvez remplacer cette clé par une autre clé.

Démarrez le projet avec node index.js et surveillez la sortie. La variable PORT doit être imprimée dans votre terminal.

Autres plugins intéressants à utiliser?

  1. fastify-auth : exécuter plusieurs fonctions d'authentification dans Fastify
  2. fastify-bearer-auth : plugin d'authentification du porteur pour Fastify [19659006{19659011] Enfin, définissons quelques crochets. Dans la documentation Fastify hooks nous pouvons lire ce qui suit. «Les hooks sont enregistrés avec la méthode fastify.addHook et vous permettent d'écouter des événements spécifiques dans l'application ou le cycle de vie des requêtes / réponses. Vous devez enregistrer un hook avant que l'événement ne soit déclenché, sinon l'événement est perdu. »

    Assurez-vous de définir des hooks avant de définir des routes:

    
     app .  addHook  ([19659026] 'onRoute'   ( routeOptions )   =>   {
         console .  log  (] `  Route enregistrée:  $ { routeOptions .  url }  ` ) 
    } ) 
    
    
    app .  get  ( '/'   function   ( req  reply )   {
        réponse .  envoyer  ( { bonjour :   'world'  } ) 
    } ) 
    

    Comme vous pouvez le voir, la fonction addHook accepte d'abord le hook que vous voulez écouter. Dans notre exemple, nous voulons écouter les nouvelles routes enregistrées avec l'application. Ensuite, la fonction de rappel accepte un argument routeOptions qui contient beaucoup d'informations, telles que l'URL de la route ou la méthode de la route.

    Des détails spécifiques pour le hook onRoute peuvent être trouvés dans la documentation.

    Commençons l'API avec node index.js pour voir quelles routes ont été enregistrées . La sortie de votre terminal doit ressembler à ceci:

     Route enregistrée: /
    Route enregistrée: / api / blogs
    Route enregistrée: / api / blogs /: id
    Route enregistrée: / api / blogs
    Route enregistrée: / api / blogs /: id
    Route enregistrée: / api / blogs /: id
    

    Vous avez le même résultat? Succès! En même temps, c'était la fin du tutoriel Fastify. Clôturons ce projet par une brève conclusion.

    Conclusion

    Fastify est un excellent projet léger qui vous permet d'utiliser son riche écosystème de plugins. Au lieu de créer des fonctionnalités à partir de zéro, vous pouvez utiliser les plugins existants. En d'autres termes, Fastify agit comme un guichet unique pour les développeurs, améliorant définitivement l'expérience des développeurs.

    Personnellement, j'aime la fonctionnalité Fastify hooks car vous pouvez écouter divers événements du cycle de vie dans votre application.

    Pour en savoir plus sur Fastify, consultez les pages de documentation suivantes:

    Vous pouvez également consulter le dépôt de cette introduction sur GitHub .




Source link