Fermer

janvier 21, 2019

Construisez votre premier routeur dans le nœud avec Express –

ES6 en action: let et const


Cet article a été publié à l'origine sur sur le blog des développeurs d'Okta . Merci de votre soutien aux partenaires qui rendent SitePoint possible.

Si vous avez réalisé un développement Web avec Node au cours des dernières années, vous avez probablement utilisé Express. Même si vous ne l'avez pas utilisé directement, de nombreux frameworks destinés à simplifier encore le développement Web sont toujours basés sur Express.

L'une des fonctionnalités clés d'Express est la possibilité de créer des itinéraires. Une combinaison infinie d'URL peut atteindre le même serveur Express, et les itinéraires vous permettent de déterminer quelles URL exécutent quel morceau de code. Vous pouvez avoir des paramètres et des caractères génériques pour ne pas avoir à déclarer explicitement chaque extrémité.

Dans ce didacticiel, je vais vous expliquer comment créer un serveur et vous apprendre tout ce que vous devez savoir sur les itinéraires dans Express. [19659005] Qu'est-ce qu'une route dans Express?

Les routes déterminent quelles données doivent être fournies avec une adresse URL quelconque. Prenons comme exemple le serveur de fichiers le plus élémentaire. Supposons que vous ayez une structure de fichier de:

 files /
├── images /
│ ├── cat.png
├── ├── dog.jpg
└── └── pig.bmp
└── texte /
    ├── LISEZMOI.md
    └── todo.txt

Vous pourriez alors exécuter un serveur HTTP simple qui servira automatiquement ces fichiers et créera un index pour les répertoires. Il n’ya pas de fichiers / index.html mais le serveur génère toujours une page Web et diffuse du contenu en fonction des fichiers de ce dossier. Si vous allez dans /images/cow.gif vous obtiendrez une erreur 404 – même s'il n'y a pas de fichier, il sert toujours quelque chose .

 npm install -g serveur http
fichiers cd
serveur http

 Démonstration de File Server

Dans Express, un itinéraire consiste en une méthode un chemin et un de gestionnaire .

Méthodes, chemins et gestionnaires, Oh My!

La méthode peut être n’importe quel verbe HTTP, tel que GET (pour récupérer du contenu – c’est ce que la plupart des pages Web utiliser) ou POST (pour envoyer du contenu au serveur – ceci est courant avec les formulaires HTML). Si vous le souhaitez, vous pouvez également indiquer que vous souhaitez que Express gère le même chemin pour toutes les méthodes.

Le chemin est une chaîne ou une expression régulière décrivant l'URL relative. Si vous travaillez avec la racine de votre application, cela décrit l’URL absolue. Un chemin peut être défini de plusieurs manières.

  • Chaînes simples : Une chaîne de '/' indique que vous souhaitez utiliser cette route à la racine de votre routeur. Une chaîne de '/ asdf' couvrirait le chemin / asdf
  • Caractères génériques : La chaîne peut également contenir quelques caractères génériques, qui ressemblent à une expression régulière, mais sont un peu limité:
    • ? : Un ? dit que le caractère précédent est facultatif. Le chemin '/ Joh? N' couvrirait à la fois / Jon et / John
    • + : A + indique que le le caractère précédent peut être répété autant de fois que vous le souhaitez, mais doit l'être au moins une fois. Un chemin de '/ ni + ce' couvrirait / nice ainsi que / niiiiiiiiiiiiiiiiice
    • * : A * dit le caractère précédent est facultatif et peut être répété autant de fois que vous le souhaitez. Un chemin de '/ wow! *' correspondrait à / wow / wow! ou même / wow !!!!!!! !!!!!
    • () : Vous pouvez également appliquer des caractères génériques à un groupe de caractères. '/ (ha) +' correspondrait à / ha / haha ​​ et / hahahahaha mais pas / hah
  • Expressions régulières : Si vous souhaitez aller au-delà des caractères génériques de base, vous pouvez utiliser des expressions régulières. Avec / ^ / (stylo -)? ((Pin)? Pomme -) + stylo $ / vous pouvez faire correspondre / stylo-pomme / stylo-ananas ou / stylo-ananas-pomme-stylo .
  • Paramètres : Une autre fonctionnalité très utile est la possibilité d'avoir des paramètres sur votre itinéraire. Cela vous permet de fournir facilement des URL RESTful avec des portions dynamiques. Un chemin de '/ posts /: postId' correspond non seulement à / posts / 42 mais la demande contient une variable params.postId avec une valeur de '42' .

La méthode et le chemin sont essentiels pour savoir quand faire quelque chose, mais le gestionnaire est la fonction de rappel qui est appelée dans ces cas. Un gestionnaire reçoit une demande une réponse et un rappel next et ces arguments sont généralement écrits sous la forme (req, res, next) ..

  • Requête ( req ) : La requête contient toutes sortes d'informations sur les informations demandées par l'utilisateur. À partir de là, vous pouvez accéder au chemin, aux paramètres, aux en-têtes et à une multitude d'autres choses. Pour tout ce qui concerne une demande, vous pouvez consulter la référence API
  • Réponse ( res ) : La réponse est la façon dont vous renvoyez des informations à l'utilisateur. Le moyen le plus simple de renvoyer des données est la méthode .send (par exemple res.send ('Hello, world!') ), mais il existe de nombreuses autres méthodes. Encore une fois, vous pouvez trouver toutes les méthodes dans la référence API
  • Prochain rappel ( suivant ) : La fonction suivante vous permet d’utiliser plusieurs manutentionnaires pour le même itinéraire. Vous pouvez utiliser un gestionnaire pour traiter les informations. Une fois terminé, il peut appeler next () pour indiquer que vous pouvez passer au gestionnaire suivant. Si vous transmettez une chaîne, une erreur que vous pouvez localiser ailleurs ou afficher à l'utilisateur est renvoyée (par exemple, next ("Vous devez être authentifié pour accéder à cette route") ). [19659027] Qu'est-ce qu'un routeur dans Express?

    Maintenant que vous êtes un peu plus familiarisé avec les itinéraires, en quoi cela diffère-t-il d'un routeur? Vous pouvez considérer un routeur comme un ensemble de routes. Cela peut être un moyen utile d’organiser différentes sections de votre application.

    Lorsque vous utilisez un routeur, vous pouvez penser en termes de chemin racine, même si vous allez utiliser ce routeur à partir d’un sous-chemin. Par exemple, supposons que vous ayez une API pour gérer les messages. Vous pouvez avoir un routeur avec un chemin '/' vers GET tous les messages ou un POST un nouveau message. Vous pourriez avoir un autre chemin '/: id' vers GET ou PUT (modifier) ​​un message spécifique.

    Votre application pourrait alors prendre ce routeur et hébergez-le à / messages avec app.use ('/ messages', messageRouter) . Le routeur lui-même n'a pas à se soucier de son chemin global et peut même être utilisé dans plusieurs routes (par exemple, / messages / textes et . /email).

    Créez une application simple avec un routeur dans un nœud avec Express

    Assez parlé déjà… passons à un code réel. Pour commencer, créez un dossier qui contiendra tout votre code. Configurez ensuite un dossier package.json pour faciliter la gestion des dépendances. Vous pouvez utiliser npm init pour ce faire. Vous devez également installer Express .

     mkdir mon-premier-routeur.
    cd mon-premier-routeur
    npm init -y
    npm install express@4.16.4 hbs@4.0.1
    

    Créez un fichier index.js avec le code suivant:

    index.js

     const express = require ('express')
    const path = require ('path')
    
    const app = express ()
    
    app.set ('vues', chemin.join (__ nom de répertoire, 'vues'))
    app.set ('moteur de visualisation', 'hbs')
    
    app.get ('/', (req, res) => {
      res.render ('index', {
        titre: 'Bonjour tout le monde!',
        contenu: 'comment ça va?'
      })
    })
    
    const port = process.env.PORT || 3000
    app.listen (port, () => console.log (`App qui écoute sur le port $ {port}`))
    

    Cela indique à Express d'utiliser le Guidon ( hbs ) comme moteur de visualisation. Il utilise le chemin intégré de Node pour lui indiquer le répertoire contenant les vues. Le chemin / indique de rendre la page à l'aide de index.hbs ce qui mettra le contenu dans un paragraphe ( p ) .

    Pour vous assurer qu'Express dispose des modèles à restituer, créez un nouveau dossier appelé views puis créez un nouveau fichier appelé layout.hbs . Lorsque vous indiquez à Express de rendre une vue, il convertit d'abord layout.hbs et place le contenu de la vue dans la balise {{{body}}} . Cela vous permet de configurer un squelette pour l'application. Voici du code HTML de base utilisant Bootstrap qui vous donnera un style agréable sans avoir à écrire de code CSS. Cela rendra également le titre passé dans le contexte de votre parcours / .

    views / layout.hbs

    
    
      
        
        
        
    
        
        
    
         {{title}} 
      
      
        

    { {title}}

    {{{body}}}     
      %MINIFYHTML6173a6a62eae69ec43b15b95293f214714%

    Vous aurez également besoin de créer une vue index.hbs qui sera simplement fondamentale pour l'instant:

    views / index.hbs

    {{content}}

    Pour faciliter le développement, vous pouvez installer nodemon avec:

     npm install --save-dev nodemon@1.18.4
    

    Modifiez ensuite votre fichier package.json afin que l'entrée "scripts" inclue un script de début avec nodemon. . Ainsi, vous pourrez simplement exécuter npm start et votre serveur redémarrera automatiquement à chaque modification:

     "scripts": {
      "start": "nodemon".
    }
    

    Maintenant, dans votre terminal, si vous tapez npm start vous démarrez le serveur. Vous pouvez ensuite aller à http: // localhost: 3000 pour voir l'application en cours d'exécution.

     Démonstration de File Server

    Créer un routeur dans Express

    Eh bien, c'est ennuyeux . Pourquoi ne pas faire quelque chose d'utile? Créons une simple liste de choses à faire. Commencez par créer un routeur pour gérer une liste d'éléments. Créez un nouveau fichier appelé todo.js :

    todo.js

     const express = require ('express')
    
    routeur const = express.Router ()
    
    let todo = []
    
    router.post ('/', (req, res, next) => {
      todo = [reqbodytodo||[]]
      if (req.body.remove) todo.splice (req.body.remove, 1)
      if (req.body.new) todo.push ({})
    
      suivant()
    })
    
    router.use ('/', (req, res) => {
      res.render ('todo', {titre: 'liste de tâches', todo})
    })
    
    module.exports = routeur
    

    Vous avez ici deux gestionnaires d'itinéraire. Le premier écoute les demandes POST (signifiées par router.post ). Il remplacera la liste de tâches par une copie de tout ce qu'il reçoit du formulaire. Si le formulaire contient la propriété remove (contenant un index), il utilisera l'épissure pour supprimer l'élément situé à cet index. Si le formulaire contient la propriété new un nouvel élément sera placé dans le tableau. Après avoir modifié la liste des tâches, il appelle next () pour passer au prochain gestionnaire d'itinéraire.

    Le deuxième gestionnaire d'itinéraire est toujours utilisé (indiqué par routeur.use [). Son seul objectif est de rendre la liste des tâches à effectuer. En séparant les itinéraires de cette manière, vous pouvez toujours faire une chose, et une autre chose seulement dans certaines circonstances (dans ce cas, sur une demande POST ).

    Indiquer à l'application d'utiliser ce routeur, vous devrez ajouter quelques lignes à index.js :

    index.js

     @@ -1,11 +1,15 @@
     const express = require ('express')
     const path = require ('path')
    + const todoRouter = require ('./ todo')
    
     const app = express ()
    
     app.set ('vues', chemin.join (__ nom de répertoire, 'vues'))
     app.set ('moteur de visualisation', 'hbs')
    
    + app.use (express.urlencoded ({extended: true}))
    + app.use ('/ todo', todoRouter)
    +
     app.get ('/', (req, res) => {
       res.render ('index', {
         titre: 'Bonjour tout le monde!',
    

    Passons maintenant au modèle todo . C’est un peu plus grand, alors je l’ai gardé pour la fin. Si vous connaissez le HTML, il ne devrait pas être trop mauvais à suivre. Handlebars ajoute quelques fonctionnalités qui vous permettent d’accéder aux variables. Dans ce cas, vous utilisez un bloc {{# if}} pour rendre quelque chose de spécial s'il n'y a pas d'éléments, ainsi qu'un {{# each}} bloquer le rendu de chacun des éléments de la liste avec un minimum de balises.

    Le seul JavaScript utilisé ici sert à soumettre automatiquement le formulaire lorsque vous modifiez quelque chose. Si JavaScript était désactivé, cela fonctionnerait quand vous appuieriez sur la touche "Entrée" de votre clavier, grâce au bouton caché intitulé "Sauvegarde automatique".

    views / todo.hbs

  • {{/ each}}         
      {{autre}}         
Votre liste de choses à faire est vide
      {{/si}}     

Allez maintenant à http: // localhost: 3000 / todo et entrez des éléments dans votre liste de tâches.

 Achetez du lait

Ajoutez l'authentification de l'utilisateur au nœud

Maintenant vous avez une liste de tâches fonctionnelle. Vous avez peut-être remarqué que cela ne fonctionnerait que si vous voulez que tous les utilisateurs partagent la même liste. Si vous ajoutez une authentification, vous pouvez avoir une liste de tâches distincte pour chaque utilisateur.

L'ajout d'utilisateurs ne doit pas être une tâche ardue. En fait, cela peut être fait très simplement avec Okta. Qu'est-ce qu'Okta? pourriez-vous demander. Okta est un service cloud qui permet aux développeurs de créer, éditer et stocker de manière sécurisée les comptes d'utilisateurs et leurs données, et de les connecter à une ou plusieurs applications.

Si vous n'en avez pas encore, inscrivez-vous à un compte de développeur gratuit pour toujours .

Vous allez avoir besoin d'enregistrer des informations à utiliser dans l'application. Créez un nouveau fichier nommé .env . Entrez-y l'URL de votre organisation.

 HOST_URL = http: // localhost: 3000
OKTA_ORG_URL = https: // {votreOktaOrgUrl}

Vous aurez également besoin d'une chaîne aléatoire à utiliser comme secret d'application pour les sessions. Vous pouvez générer cela avec les commandes suivantes:

 echo -e " nAPP_SECRET =` npx -q uuid` ">> .env

Ensuite, connectez-vous à votre console de développeur, accédez à Applications puis cliquez sur Ajouter une application . Sélectionnez Web puis cliquez sur Suivant . Donnez à votre application un nom, par exemple «Mon premier routeur». Remplacez l'URI de base par http: // localhost: 3000 / et par l'URI de redirection de connexion par http: // localhost: 3000 / autorisation- code / rappel puis cliquez sur Terminé

Cliquez sur Modifier et ajoutez un URI de redirection de http: // localhost: 3000 / puis cliquez sur Sauvegardez .

 Paramètres de l'application Okta

La page que vous consultez après la création d'une application contient des informations supplémentaires que vous devez sauvegarder dans votre .env fichier. Copiez l'ID client et le secret client.

 OKTA_CLIENT_ID = {yourClientId}
OKTA_CLIENT_SECRET = {votreClientSecret}

Revenons maintenant au code. Vous devez ajouter le middleware OIDC d’Okta pour contrôler l’authentification. Il repose également sur l'utilisation de sessions. Vous devez utiliser dotenv pour lire les variables du fichier .env . Pour installer les dépendances dont vous aurez besoin, exécutez la commande suivante:

 npm install @ okta / oidc-middleware @ 1.0.1 dotenv@6.1.0 express-session@1.15.6

Modifiez maintenant votre fichier index.js . Vous allez ajouter ici les middlewares de session et OIDC, ainsi qu'un itinéraire de déconnexion afin que les utilisateurs puissent se déconnecter de l'application. Vous ajoutez également un middleware spécifiquement à la commande todoRouter ( app.use ('/ todo', oidc.ensureAuthenticated (), todoRouter) ). En ajoutant oidc.ensureAuthenticated () vous permettez à Okta de s'assurer que cet itinéraire ne peut être atteint que si un utilisateur est connecté. Si l'utilisateur n'est pas connecté et tente d'atteindre cet itinéraire, ils seront redirigés vers un site sécurisé, puis redirigés vers votre site.

index.js

 @@ -1,14 +1,46 @@
+ require ('dotenv'). config ()
+
 const express = require ('express')
 const path = require ('path')
+ const session = require ('express-session')
+ const {ExpressOIDC} = require ('@ okta / oidc-middleware')
+
 const todoRouter = require ('./ todo')

+ const oidc = new ExpressOIDC ({
+ issuer: `$ {process.env.OKTA_ORG_URL} / oauth2 / default`,
+ client_id: process.env.OKTA_CLIENT_ID,
+ client_secret: process.env.OKTA_CLIENT_SECRET,
+ redirect_uri: `$ {process.env.HOST_URL} / code d'autorisation / callback`,
+ scope: 'profil ouvert'
+})
+
 const app = express ()

+ app.use (session ({
+ secret: process.env.APP_SECRET,
+ resave: true,
+ saveUninitialized: false
+}))
+ app.use (oidc.router)
+
 app.set ('vues', chemin.join (__ nom de répertoire, 'vues'))
 app.set ('moteur de visualisation', 'hbs')

 app.use (express.urlencoded ({extended: true}))
-app.use ('/ todo', todoRouter)
+ app.use ('/ todo', oidc.ensureAuthenticated (), todoRouter)
+
+ app.get ('/ logout', (req, res) => {
+ if (req.userContext) {
+ const idToken = req.userContext.tokens.id_token
+ const to = encodeURI (process.env.HOST_URL)
+ const params = `id_token_hint = $ {idToken} & post_logout_redirect_uri = $ {to}`
+ req.logout ()
+ res.redirect (`$ {process.env.OKTA_ORG_URL} / oauth2 / default / v1 / logout? $ {params}`)
+} else {
+ res.redirect ('/')
+}
+})

 app.get ('/', (req, res) => {
   res.render ('index', {

Pour faciliter la tâche lorsqu'un utilisateur se déconnecte, ajoutez un lien vers la liste des tâches de la page d'accueil.

views / index.hbs

{{content}} [19659093] Aller à la liste des tâches

Vous pouvez également ajouter un message de bienvenue et un bouton de déconnexion à votre layout.hbs .

views / layout.hbs

 @@ -12,6 +12, 12 @@
   
   
     

{{title}}

+ {{#if userinfo}} +

+ Bienvenue, {{userinfo.given_name}}! + Cliquez ici pour vous déconnecter +

+ {{/ if}}      
       {{{corps}}}      

Pour que cela fonctionne, vous devez ajouter userinfo au contexte lors du rendu des vues.

todo.js

 --- a / todo.js
+++ b / todo.js
@@ -13,7 +13,7 @@ router.post ('/', (req, res, next) => {
 })

 router.use ('/', (req, res) => {
- res.render ('todo', {titre: 'liste de tâches', todo})
+ res.render ('todo', {titre: 'liste de choses à faire', todo, userinfo: req.userContext.userinfo})
 })

 module.exports = routeur

index.js

 @@ -43,7 +43,10 @@ app.get ('/ logout', (req, res) => {
 })

 app.get ('/', (req, res) => {
+ const {userinfo} = req.userContext || {}
+
   res.render ('index', {
+ userinfo,
     titre: 'Bonjour tout le monde!',
     contenu: 'comment ça va?'
   })

OK, vous demandez donc aux utilisateurs de se connecter avant de pouvoir modifier la liste des tâches, mais cette liste est toujours unique. Pour le scinder en une liste distincte pour chaque utilisateur, apportez un autre petit changement à todo.js .

todo.js

 @@ -2,17 +2, 21 @@ const express = require ('express')

 routeur const = express.Router ()

-let todo = []
+ const todosByUser = {}

 router.post ('/', (req, res, next) => {
- todo = [reqbodytodo||[]]
+ const todo = [reqbodytodo||[]]
   if (req.body.remove) todo.splice (req.body.remove, 1)
   if (req.body.new) todo.push ({})

+ todosByUser [req.userContext.userinfo.sub] = todo
+
   suivant()
 })

 router.use ('/', (req, res) => {
+ const todo = todosByUser [req.userContext.userinfo.sub] || []
+
   res.render ('todo', {titre: 'liste de tâches', tâches, userinfo: req.userContext.userinfo})
 })

 Démo multi-utilisateurs

En savoir plus sur les développements de nœud, express et sécurisé Web

Maintenant que vous disposez d'une liste de tâches entièrement fonctionnelle, je vous encourage à la développer davantage. Essayez de stocker les données dans une base de données, ou même laissez Okta les stocker pour vous ! Voyez si vous pouvez créer d'autres routeurs à ajouter au serveur Web.

Si vous souhaitez voir le dernier exemple de code, vous pouvez le trouver sur GitHub .

Si vous le souhaitez Pour en savoir plus sur Node and Express, consultez ces articles sur le blog des développeurs d’Okta:

Si vous avez des questions concernant cette publication, veuillez ajouter un commentaire ci-dessous. Pour un contenu plus génial, suivez @oktadev sur Twitter, comme nous sur Facebook ou abonnez-vous à sur notre chaîne YouTube .





Source link

Revenir vers le haut