Comment utiliser TypeScript pour créer une API de nœud avec Express –
   
Qu'on le veuille ou non, JavaScript aide les développeurs à alimenter Internet depuis 1995. Depuis cette époque, l'utilisation de JavaScript passait de simples améliorations de l'expérience utilisateur à des applications complexes fonctionnant en pile complète utilisant Node.js sur le serveur et l'un des nombreux frameworks. sur un client tel que Angular, React ou Vue.
Aujourd'hui, la construction d'applications JavaScript à l'échelle reste un défi. De plus en plus d'équipes se tournent vers TypeScript pour compléter leurs projets JavaScript.
Les applications serveur Node.js peuvent également tirer parti de l'utilisation de TypeScript. Le but de ce didacticiel est de vous montrer comment construire une nouvelle application Node.js à l'aide de TypeScript et Express.
L'affaire de TypeScript
En tant que développeur Web, j'ai depuis longtemps cessé de résister à JavaScript et je me suis développé pour l'apprécier sa flexibilité et son omniprésence. Les fonctionnalités linguistiques ajoutées à ES2015 et aux versions ultérieures ont considérablement amélioré son utilité et réduit les frustrations liées à l'écriture d'applications.
Cependant, les projets JavaScript plus volumineux nécessitent des outils tels qu'ESLint pour détecter les erreurs courantes et une plus grande discipline pour saturer la base de code d'essais utiles. Comme pour tout projet logiciel, une culture d'équipe saine comprenant un processus de révision par des pairs peut améliorer la qualité et éviter les problèmes susceptibles de se glisser dans un projet.
Le principal avantage de l'utilisation de TypeScript est de détecter davantage d'erreurs avant leur mise en production. facilite le travail avec votre base de code.
TypeScript n'est pas un langage différent. C’est un surensemble flexible de JavaScript avec des façons de décrire des types de données facultatifs. Tout JavaScript «standard» et valide est également valide TypeScript. Vous pouvez utiliser autant de ressources que vous le souhaitez.
Dès que vous ajoutez le compilateur TypeScript ou un plugin TypeScript à votre éditeur de code préféré, la sécurité et la productivité procurent des avantages immédiats. TypeScript peut vous alerter des fonctions et propriétés mal orthographiées, détecter la transmission des types d'arguments incorrects ou du nombre d'arguments aux fonctions incorrect, et fournir des suggestions plus complètes de complétion automatique.
Construire une application d'inventaire de la guitare avec TypeScript et Node.js
Parmi les guitaristes, il y a une blague que tout le monde devrait comprendre .
Q: «De combien de guitares avez-vous besoin de ?"
A: “ n + 1. Toujours un de plus. ”
 Dans ce tutoriel, vous allez créer une nouvelle application Node.js pour suivre un inventaire des guitares. En résumé, ce didacticiel utilise  Node.js  avec  Express  EJS  et  PostgreSQL  au dos, .  Materialise  et  Axios  sur le front-office,  Okta  pour l'enregistrement et l'autorisation de compte, et  TypeScript  pour régir les JavaScripts! [19659002] 
Créez votre projet Node.js
Ouvrez un terminal (Mac / Linux) ou une invite de commande (Windows) et tapez la commande suivante:
 node --version
Si vous obtenez une erreur ou si la version de Node.js que vous possédez est inférieure à la version 8, vous devrez installer Node.js. Sur Mac ou Linux, je vous recommande d’installer d’abord nvm et d’utiliser nvm pour installer Node.js. Sous Windows, je vous recommande d'utiliser Chocolatey .
Après vous être assuré d'avoir une version récente de Node.js installée, créez un dossier pour votre projet.
 mkdir guitar-inventory
cd guitare-inventaire
 Utilisez  npm  pour initialiser un fichier  package.json .
 npm init -y
Bonjour, monde!
 Dans cet exemple d'application,  Express  est utilisé pour servir des pages Web et implémenter une API. Les dépendances sont installées en utilisant  npm . Ajoutez Express à votre projet avec la commande suivante:
 npm install express
Ouvrez ensuite le projet dans l’éditeur de votre choix
Si vous n’avez pas encore d’éditeur de code favori, j’utilise et recommande Code Visual Studio . VS Code prend en charge de manière exceptionnelle JavaScript et Node.js, tels que l’achèvement de code intelligent et le débogage, et une vaste bibliothèque d’extensions gratuites fournies par la communauté.
 Créez un dossier nommé  src . Dans ce dossier, créez un fichier nommé  index.js . Ouvrez le fichier et ajoutez le code JavaScript suivant:
 const express = require ("express");
const app = express ();
port constant = 8080; // port par défaut pour écouter
// définir un gestionnaire de route pour la page d'accueil par défaut
app.get ("/", (req, res) => {
    res.send ("Hello world!");
});
// démarre le serveur Express
app.listen (port, () => {
    console.log (`le serveur a démarré à http: // localhost: $ {port}`);
});
 Ensuite, mettez à jour  package.json  pour indiquer à  npm  de savoir comment exécuter votre application. Modifiez la valeur de la propriété  principale  pour qu'elle pointe sur  src / index.js  et ajoutez un script  start  à l'objet  scripts . [19659030] "main": "src / index.js",
   "scripts": {
     "start": "node.",
     "test": "echo " Erreur: aucun test spécifié  "&& exit 1"
   },
Maintenant, depuis le terminal ou la ligne de commande, vous pouvez lancer l'application.
 npm run start
Si tout se passe bien, ce message devrait être écrit sur la console.
 Le serveur a été démarré à l'adresse http: // localhost: 8080.
 Lancez votre navigateur et accédez à  http: // localhost: 8080 . Vous devriez voir le texte «Hello world!»
 
Remarque: pour arrêter l'application Web, vous pouvez revenir au guide ou à l'invite de commande et appuyer sur
CTRL + C..
Configurez votre projet Node.js pour utiliser TypeScript
 La première étape consiste à ajouter le compilateur TypeScript. Vous pouvez installer le compilateur en tant que dépendance de développeur à l'aide de l'indicateur  - save-dev .
 npm install --save-dev typescript
 L'étape suivante consiste à ajouter un fichier  tsconfig.json . Ce fichier indique à TypeScript comment compiler (transpiler) votre code TypeScript en code JavaScript simple.
 Créez un fichier nommé  tsconfig.json  dans le dossier racine de votre projet et ajoutez la configuration suivante:
 {
    "compilerOptions": {
        "module": "commonjs",
        "esModuleInterop": true,
        "cible": "es6",
        "noImplicitAny": true,
        "moduleResolution": "noeud",
        "sourceMap": true,
        "outDir": "dist",
        "baseUrl": ".",
        "chemins": {
            "*": [
                "node_modules/*"
            ]
        }
    },
    "inclure": [
        "src/**/*"
    ]
}
 Sur la base de ce fichier  tsconfig.json le compilateur TypeScript compilera tous les fichiers se terminant par  .ts  qu'il trouve dans le dossier  src . et stockez les résultats dans un dossier nommé  dist . Node.js utilise le système de module CommonJS, la valeur du paramètre  module  est donc  commonjs . En outre, la version cible de JavaScript est ES6 (ES2015), qui est compatible avec les versions modernes de Node.js.
 C'est également une excellente idée d'ajouter  tslint  et de créer un  tslint.json  qui indique à TypeScript comment lint votre code. Si vous ne connaissez pas les éléments, c'est un outil d'analyse de code qui vous avertit des problèmes potentiels de votre code, autres que les problèmes de syntaxe.
 Installez  tslint  en tant que dépendance du développeur.
 npm install - -save-dev dactylographiée tslint
 Créez ensuite un nouveau fichier dans le dossier racine nommé fichier tslint.json puis ajoutez la configuration suivante:
 {
    "defaultSeverity": "erreur",
    "étend": [
        "tslint:recommended"
    ],
    "jsRules": {},
    "règles": {
        "fin de virgule": [ false ]
    },
    "rulesDirectory": []
}
 Ensuite, mettez à jour votre  package.json  pour qu'il remplace  main  par le nouveau dossier  dist  créé par le compilateur TypeScript. Ajoutez également quelques scripts pour exécuter TSLint et le compilateur TypeScript juste avant de démarrer le serveur Node.js.
 "main": "dist / index.js",
  "scripts": {
    "prebuild": "tslint -c tslint.json -p tsconfig.json --fix",
    "build": "tsc",
    "prestart": "npm run build",
    "start": "node.",
    "test": "echo " Erreur: aucun test spécifié  "&& exit 1"
  },
 Enfin, modifiez l'extension du fichier  src / index.js  de  .js  à  .ts l'extension TypeScript, puis exécutez le script de démarrage. .
 npm run start
Remarque: Vous pouvez exécuter TSLint et le compilateur TypeScript sans démarrer le serveur Node.js à l'aide de
npm run build.
Erreurs TypeScript
Oh no! Vous remarquerez peut-être tout de suite quelques erreurs enregistrées sur la console.
 ERREUR: /Users/reverentgeek/Projects/guitar-inventory/src/index.ts[12, 5]: Les appels à 'console.log' ne sont pas autorisés. .
src / index.ts: 1: 17 - erreur TS2580: Impossible de trouver le nom 'require'. Avez-vous besoin d'installer des définitions de type pour le noeud? Essayez `npm i @ types / node`.
1 const express = require ("express");
                  ~~~~~~~
src / index.ts: 6: 17 - erreur TS7006: le paramètre 'req' a implicitement un type 'quelconque'.
6 app.get ("/", (req, res) => {
                  ~~~
 Les deux erreurs les plus courantes que vous pouvez voir sont les erreurs de syntaxe et les informations de type manquantes. TSLint considère que l'utilisation de  console.log  constitue un problème pour le code de production. La meilleure solution consiste à remplacer les utilisations de console.log par un cadre de journalisation tel que  winston . Pour l'instant, ajoutez le commentaire suivant à  src / index.ts  pour désactiver la règle.
 app.listen (port, () => {
    // tslint: disable-next-line: no-console
    console.log (`le serveur a démarré à http: // localhost: $ {port}`);
});
 TypeScript préfère utiliser la syntaxe du module  import  sur  Requiert vous commencerez donc par modifier la première ligne de  src / index.ts  de:
 const express = require ("express");
à:
 import express de "express";
Trouver les bons types
Pour aider les développeurs de TypeScript, les auteurs de bibliothèques et les contributeurs à la communauté publient des bibliothèques associées appelées fichiers de déclaration TypeScript . Les fichiers de déclaration sont publiés dans le référentiel open source DefinitelyTyped ou se trouvent parfois dans la bibliothèque JavaScript d'origine.
Mettez à jour votre projet afin que TypeScript puisse utiliser les déclarations de type de Node.js et Express.
 ] npm installer --save-dev @ types / noeud @ types / express
Ensuite, réexécutez le script de démarrage et vérifiez qu'il n'y a plus d'erreur.
 npm run start
Créez une meilleure interface utilisateur avec Materialise et EJS
Votre application Node.js a bien démarré, mais n'est peut-être pas la plus belle qui soit. Cette étape ajoute Materialise un framework CSS moderne basé sur la conception de matériaux de Google, et Modèles de JavaScript incorporés (EJS), un langage de modèles HTML pour Express. Materialise et EJS constituent une bonne base pour une interface utilisateur bien meilleure.
Commencez par installer EJS en tant que dépendance.
 npm install ejs
 Ensuite, créez un nouveau dossier sous  / src  nommé  vues . Dans le dossier  / src / views créez un fichier nommé  index.ejs . Ajoutez le code suivant à  /src/views/index.ejs .
    
    
     Inventaire des guitares  
    
    
    
    
         Inventaire des guitares 
         arrow_forward  Lancez-vous! 
    
 Mise à jour  /src/index.ts  avec le code suivant: 
 import express de "express";
importer le chemin de "chemin";
const app = express ();
port constant = 8080; // port par défaut pour écouter
// Configurer Express pour utiliser EJS
app.set ("vues", chemin.join (__dirname, "vues"));
app.set ("moteur de vue", "ejs");
// définir un gestionnaire de route pour la page d'accueil par défaut
app.get ("/", (req, res) => {
    // rendre le modèle d'index
    res.render ("index");
});
// démarre le serveur express
app.listen (port, () => {
    // tslint: disable-next-line: no-console
    console.log (`le serveur a démarré à http: // localhost: $ {port}`);
});
 Ajouter un script de génération d'actif pour Typescript
 Le compilateur TypeScript consiste à générer les fichiers JavaScript et à les copier dans le dossier  dist . Cependant, il ne copie pas les autres types de fichiers que le projet doit exécuter, tels que les modèles de vue EJS. Pour ce faire, créez un script de construction qui copie tous les autres fichiers dans le dossier  dist .
 Installez les modules nécessaires et les déclarations TypeScript à l'aide de ces commandes.
 npm install --save-dev ts -node shelljs fs-extra nodemon rimraf npm-run-all
npm installer --save-dev @ types / fs-extra @ types / shelljs
 Voici un bref aperçu des modules que vous venez d'installer.
-  ts-node . Utilisé pour exécuter des fichiers TypeScript directement.
-  shelljs . Utilisé pour exécuter des commandes de shell telles que copier des fichiers et supprimer des répertoires.
-  fs-extra . Module qui étend le module du système de fichiers Node.js (-  fs ) avec des fonctionnalités telles que la lecture et l'écriture de fichiers JSON.
-  rimraf . Permet de supprimer récursivement les dossiers.
-  npm-run-all . Utilisé pour exécuter plusieurs scripts-  npm de manière séquentielle ou parallèle
-  nodemon . Un outil pratique pour exécuter Node.js dans un environnement de développement. Nodemon surveille les fichiers pour les modifications et redémarre automatiquement l'application Node.js lorsque des modifications sont détectées. Plus besoin d'arrêter et de redémarrer Node.js!
 Créez un nouveau dossier à la racine du projet nommé  tools . Créez un fichier dans le dossier  tools  nommé  copyAssets.ts . Copiez le code suivant dans ce fichier.
 import * as shell depuis "shelljs";
// Copier tous les modèles de vue
shell.cp ("-R", "src / vues", "dist /");
 Mise à jour des scripts npm
 Mettez à jour les scripts   dans  package.json  avec le code suivant.
 "scripts": {
    "clean": "rimraf dist / *",
    "copy-assets": "outils ts-node / copyAssets",
    "peluche": "tslint -c tslint.json -p tsconfig.json --fix",
    "tsc": "tsc",
    "build": "npm-run-all clean lint tsc copy-assets",
    "dev: start": "npm-run-all build start",
    "dev": "nodemon --watch src -e ts, ejs --exec npm lancer dev: start",
    "start": "node.",
    "test": "echo " Erreur: aucun test spécifié  "&& exit 1"
  },
 Remarque: Si vous ne connaissez pas bien les scripts  npm ils peuvent être très puissants et utiles pour tout projet Node.js. Les scripts peuvent être enchaînés de plusieurs manières. Une façon de chaîner les scripts consiste à utiliser les préfixes  pre  et  post . Par exemple, si vous avez un script intitulé  start  et un autre intitulé  prestart l'exécution de  npm run start  sur le terminal sera exécutée pour la première fois  prestart  et  seulement  commence à fonctionner.
 Lancez maintenant l'application et naviguez jusqu'à http: // localhost: 8080.
 npm run dev
 
 La page d'accueil commence à être plus belle! Bien entendu, le bouton  Get Started  conduit à un message d'erreur décevant. Pas de soucis!
 Un meilleur moyen de gérer les paramètres de configuration dans Node.js
 Les applications Node.js utilisent généralement des variables d’environnement pour la configuration. Cependant, la gestion des variables d'environnement peut être une corvée.  dotenv .
 Installez  dotenv  en tant que dépendance de projet.
 npm install dotenv
npm installer --save-dev @ types / dotenv
 Créez un fichier nommé  .env  dans le dossier racine du projet et ajoutez le code suivant:
 # Défini en production lors du déploiement en production.
NODE_ENV = développement
Configuration du serveur # Node.js
SERVER_PORT = 8080
 Remarque: Lorsque vous utilisez un système de contrôle de code source tel que  git  n'ajoutez pas le fichier  .env  au contrôle de source. Chaque environnement nécessite un fichier personnalisé  .env . Il est recommandé de documenter les valeurs attendues dans le fichier  .env  du projet README ou dans un fichier séparé  .env.sample .
 Maintenant, mettez à jour  src / index .ts  pour utiliser  dotenv  pour configurer la valeur du port du serveur d’application.
 import dotenv de "dotenv";
importer express de "express";
importer le chemin de "chemin";
// initialise la configuration
dotenv.config ();
// le port est maintenant disponible pour l'exécution de Node.js
// comme s'il s'agissait d'une variable d'environnement
const port = process.env.SERVER_PORT;
const app = express ();
// Configurer Express pour utiliser EJS
app.set ("vues", chemin.join (__dirname, "vues"));
app.set ("moteur de vue", "ejs");
// définir un gestionnaire de route pour la page d'accueil par défaut
app.get ("/", (req, res) => {
    // rendre le modèle d'index
    res.render ("index");
});
// démarre le serveur express
app.listen (port, () => {
    // tslint: disable-next-line: no-console
    console.log (`le serveur a démarré à http: // localhost: $ {port}`);
});
 Vous utiliserez  .env  pour obtenir beaucoup plus d'informations sur la configuration à mesure que le projet se développe.
 Ajoutez facilement l'authentification aux nœuds et aux expressions
 Ajouter l'enregistrement de l'utilisateur et la connexion (authentification) à toute application est pas une tâche banale. La bonne nouvelle est qu'Okta rend cette étape très facile. Pour commencer, créez un compte développeur gratuit avec Okta. Tout d'abord, accédez à  developer.okta.com  et cliquez sur le bouton  Créer un compte gratuit ou cliquez sur le bouton  Inscription .
 
 Après avoir créé votre compte, cliquez sur le lien  Applications  en haut, puis cliquez sur  Ajouter une application .
  . ]
. ]
 Choisissez ensuite une  application Web  et cliquez sur  Suivant .
 
 Entrez un nom pour votre application, telle que comme  Inventaire Guitare . Vérifiez que le numéro de port est identique à celui configuré pour votre application Web locale. Cliquez ensuite sur  Terminé  pour terminer la création de l'application.
 
 Copiez-collez le code suivant dans votre fichier  .env . [19659114] # Okta configuration
 OKTA_ORG_URL = https: // {votreOktaDomain}
 OKTA_CLIENT_ID = {votreClientId}
 OKTA_CLIENT_SECRET = {votreClientSecret}
 Dans la console d’application Okta, cliquez sur l’onglet  Général  de votre nouvelle application, et trouvez au bas de la page une section intitulée «Informations d’identité du client». Copiez l’ID client  puis  Valeurs du secret client  et collez-les dans votre fichier  .env  pour remplacer  {votreClientId}  et  {votreClientSecret} respectivement.
 
 Activer l'enregistrement en libre-service
 L'une des fonctionnalités intéressantes d'Okta permet aux utilisateurs de votre application de créer un compte. Par défaut, cette fonctionnalité est désactivée, mais vous pouvez l'activer facilement. Tout d’abord, cliquez sur le menu  Utilisateurs  et sélectionnez  Enregistrement .
 
-  Cliquez sur le bouton  Edit .
-  Modifier  Enregistrement en libre service  à  Activé .
-  Cliquez sur le bouton  Enregistrer  au bas du formulaire.
 ![Activer l'auto-enregistrement [19659139] Sécurisez votre application Node.js </h3>
<p> La dernière étape pour sécuriser votre application Node.js consiste à configurer Express pour qu'il utilise le middleware <a href=](https://i0.wp.com/blog.arcoptimizer.com/wp-content/uploads/2018/12/1544119980_576_comment-utiliser-typescript-pour-creer-une-api-de-noeud-avec-express.jpg?w=660&ssl=1) Okta OpenId Connect (OIDC) .
 Okta OpenId Connect (OIDC) .
 npm install @ okta / session express oidc-middleware
npm install --save-dev @ types / express-session
 Ensuite, mettez à jour votre fichier  .env  pour ajouter une valeur  HOST_URL  et  SESSION_SECRET . Vous pouvez remplacer la valeur  par SESSION_SECRET  par la chaîne de votre choix.
 # configuration du serveur Node.js
SERVER_PORT = 8080
HOST_URL = http: // localhost: 8080
SESSION_SECRET = MySuperCoolAndAwesomeSecretForSigningSessionCookies
 Créez un dossier sous  src  nommé  middleware . Ajoutez un fichier au dossier  src / middleware  nommé  sessionAuth.ts . Ajoutez le code suivant à  src / middleware / sessionAuth.ts .
 import {ExpressOIDC} à partir de "@ okta / oidc-middleware";
importer une session depuis "express-session";
exportation const register = (app: any) => {
    // Créer le client OIDC
    const oidc = new ExpressOIDC ({
        client_id: process.env.OKTA_CLIENT_ID,
        client_secret: process.env.OKTA_CLIENT_SECRET,
        émetteur: `$ {process.env.OKTA_ORG_URL} / oauth2 / default`,
        redirect_uri: `$ {process.env.HOST_URL} / code d'autorisation / callback`,
        scope: "profil ouvert"
    });
    // Configurer Express pour utiliser des sessions d'authentification
    app.use (session ({
        resave: true,
        saveUninitialized: false,
        secret: process.env.SESSION_SECRET
    }));
    // Configurer Express pour utiliser le routeur client OIDC
    app.use (oidc.router);
    // ajoute le client OIDC à app.locals
    app.locals.oidc = oidc;
};
 À ce stade, si vous utilisez un éditeur de code tel que VS Code, vous pouvez voir TypeScript se plaindre du module  @ okta / oidc-middleware . Au moment d'écrire ces lignes, ce module n'a pas encore de fichier de déclaration TypeScript officiel. Pour l'instant, créez un fichier dans le dossier  src  nommé  global.d.ts  et ajoutez le code suivant:
 déclarez le module "@ okta / oidc-middleware";
 Itinéraires de refactor
 Au fur et à mesure que l'application grandit, vous ajoutez de nombreux autres itinéraires. C'est une bonne idée de définir tous les itinéraires dans une zone du projet. Créez un nouveau dossier sous  src  nommé  routes . Ajouter un nouveau fichier à  src / routes  nommé  index.ts . Ajoutez ensuite le code suivant à ce nouveau fichier:
 import * as express de "express";
exportation const register = (app: express.Application) => {
    const oidc = app.locals.oidc;
    // définir un gestionnaire de route pour la page d'accueil par défaut
    app.get ("/", (req: any, res) => {
        res.render ("index");
    });
    // définit un gestionnaire d'itinéraire sécurisé pour la page de connexion qui redirige vers / guitars
    app.get ("/ login", oidc.ensureAuthenticated (), (req, res) => {
        res.redirect ("/ guitars");
    });
    // définir un itinéraire pour gérer la déconnexion
    app.get ("/ logout", (req: any, res) => {
        req.logout ();
        res.redirect ("/");
    });
    // définir un gestionnaire d'itinéraire sécurisé pour la page guitars
    app.get ("/ guitars", oidc.ensureAuthenticated (), (req: any, res) => {
        res.render ("guitares");
    });
};
 Ensuite, mettez à jour les modules  src / index.ts  pour utiliser les modules  sessionAuth  et   que vous avez créés.
 import dotenv de "dotenv";
importer express de "express";
importer le chemin de "chemin";
importer * en tant que sessionAuth de "./middleware/sessionAuth";
importer * en tant que routes à partir de "./routes";
// initialise la configuration
dotenv.config ();
// le port est maintenant disponible pour l'exécution de Node.js
// comme s'il s'agissait d'une variable d'environnement
const port = process.env.SERVER_PORT;
const app = express ();
// Configurer Express pour utiliser EJS
app.set ("vues", chemin.join (__dirname, "vues"));
app.set ("moteur de vue", "ejs");
// Configurer l'authentification de session
sessionAuth.register (application);
// Configurer les itinéraires
routes.register (app);
// démarre le serveur express
app.listen (port, () => {
    // tslint: disable-next-line: no-console
    console.log (`le serveur a démarré à http: // localhost: $ {port}`);
});
 Créez ensuite un nouveau fichier pour le modèle d'affichage de liste de guitares à partir de  src / views / guitars.ejs  et entrez le code HTML suivant:
    
    
     Inventaire Guitar  
    
    
    
    
         Inventaire Guitar 
         Votre avenir liste des guitares! 
    
 Enfin, lancez l'application.
 npm run dev
 Remarque: pour vérifier que l'authentification fonctionne correctement, ouvrez un nouveau navigateur ou utilisez une fenêtre de navigateur privé / incognito.
 Cliquez sur le bouton  Get Started . Si tout se passe bien, connectez-vous avec votre compte Okta et Okta devrait automatiquement vous rediriger vers la page «Liste des guitares»!
 
 L'authentification fonctionne avec le profil de l'utilisateur. informations renvoyées par Okta. Le middleware OIDC associe automatiquement un objet  userContext  et une fonction  isAuthenticated ()  à chaque requête. Ce  userContext  a une propriété  userinfo  qui contient des informations qui ressemblent à l'objet suivant:
 {
  sous: '00abc12defg3hij4k5l6',
  nommer le premier Dernier',
  locale: 'en-US',
  nom_utilisateur_principal: 'account@company.com',
  prenom_nom: 'premier',
  nom_famille: 'dernier',
  zoneinfo: 'America / Los_Angeles',
  updated_at: 1539283620
}
 La première étape consiste à récupérer l'objet de profil utilisateur et à le transmettre aux vues sous forme de données. Mettez à jour le  src / routes / index.ts  avec le code suivant:
 import * comme express à partir de "express";
exportation const register = (app: express.Application) => {
    const oidc = app.locals.oidc;
    // définir un gestionnaire de route pour la page d'accueil par défaut
    app.get ("/", (req: any, res) => {
        const utilisateur = req.userContext? req.userContext.userinfo: null;
        res.render ("index", {isAuthenticated: req.isAuthenticated (), user});
    });
    // définit un gestionnaire d'itinéraire sécurisé pour la page de connexion qui redirige vers / guitars
    app.get ("/ login", oidc.ensureAuthenticated (), (req, res) => {
        res.redirect ("/ guitars");
    });
    // définir un itinéraire pour gérer la déconnexion
    app.get ("/ logout", (req: any, res) => {
        req.logout ();
        res.redirect ("/");
    });
    // définir un gestionnaire d'itinéraire sécurisé pour la page guitars
    app.get ("/ guitars", oidc.ensureAuthenticated (), (req: any, res) => {
        const utilisateur = req.userContext? req.userContext.userinfo: null;
        res.render ("guitars", {isAuthenticated: req.isAuthenticated (), user});
    });
};
 Créez un nouveau dossier sous  src / views  nommé  partiels . Créez un nouveau fichier dans ce dossier nommé  nav.ejs . Ajoutez le code suivant à  src / views / partials / nav.ejs .
 Modifiez les fichiers  src / views / index.ejs  et  src / views / guitars.ejs . Immédiatement après l'étiquette 
  
    
 Grâce à ces changements, votre application a maintenant un menu de navigation en haut qui change en fonction du statut de connexion de l'utilisateur.
 
 Créez une API avec Node et PostgreSQL
 L'étape suivante consiste à ajouter l'API à l'application Guitar Inventory. Cependant, avant de poursuivre, vous avez besoin d'un moyen de stocker des données.
 Créer une base de données PostgreSQL
 Ce tutoriel utilise  PostgreSQL . Pour faciliter les choses, utilisez  Docker  pour configurer une instance de PostgreSQL. Si Docker n'est pas déjà installé, vous pouvez suivre le guide d'installation  .
 Une fois Docker installé, exécutez la commande suivante pour télécharger le dernier conteneur PostgreSQL.
 docker pull postgres: dernier
 Exécutez maintenant cette commande pour créer une instance d'un serveur de base de données PostgreSQL. N'hésitez pas à modifier la valeur du mot de passe de l'administrateur.
 docker run -d --name guitar-db -p 5432: 5432 -e 'POSTGRES_PASSWORD = p @ ssw0rd42' postgres
 Remarque: Si PostgreSQL est déjà installé localement, vous devrez modifier le paramètre  -p  pour mapper le port 5432 sur un autre port n'entrant pas en conflit avec votre instance existante de PostgreSQL.
 Voici une brève explication des paramètres précédents de Docker.
-  -d – Le conteneur est lancé en mode démon, de sorte qu'il s'exécute en arrière-plan.
-   -name – Vous donnez Le conteneur Docker est un nom convivial, utile pour arrêter et démarrer des conteneurs.
-   -p – Ceci mappe le port 5432 de l'hôte (votre ordinateur) sur celui de son conteneur 5432. PostgreSQL, par défaut, écoute. connexions sur le port TCP 5432.
-   -e – Ceci définit une variable d'environnement dans le conteneur. Dans cet exemple, le mot de passe de l'administrateur est p @ ssw0rd42 . Vous pouvez remplacer cette valeur par n'importe quel mot de passe.
-   postgres – Ce dernier paramètre indique à Docker d'utiliser l'image postgres.
 Remarque: Si vous redémarrez votre ordinateur, vous devrez peut-être le redémarrer. récipient. Vous pouvez le faire en utilisant la commande  du menu fixe start guitar-db .
 Installez le module client PostgreSQL et entrez les déclarations à l'aide des commandes suivantes:
 npm install pg pg-promise
npm installer --save-dev @ types / pg
 Paramètres de configuration de la base de données
 Ajoutez les paramètres suivants à la fin du fichier  .env .
 # Configuration de Postgres
PGHOST = localhost
PGUSER = postgres
PGDATABASE = postgres
PGPASSWORD = p @ ssw0rd42
PGPORT = 5432
  Remarque: Si vous avez modifié le mot de passe de l'administrateur de la base de données, veillez à remplacer le mot de passe par défaut  p @ ssw0rd42  par ce mot de passe dans ce fichier. 
 Ajouter un script de génération de base de données
 Vous besoin d’un script de compilation pour initialiser la base de données PostgreSQL. Ce script doit lire un fichier  .pgsql  et exécuter les commandes SQL sur la base de données locale
 Dans le dossier  tools créez deux fichiers:  initdb.ts  et  initdb.pgsql . Copiez et collez le code suivant dans  initdb.ts .
 import dotenv de "dotenv";
importer des fs de "fs-extra";
importer {Client} de "pg";
const init = async () => {
    // lire les variables d'environnement
    dotenv.config ();
    // crée une instance du client PostgreSQL
    const client = new Client ();
    essayer {
        // se connecter au serveur de base de données local
        wait client.connect ();
        // lit le contenu du fichier initdb.pgsql
        const sql = wait fs.readFile ("./tools/initdb.pgsql", {encoding: "UTF-8"});
        // divise le fichier en déclarations séparées
        instructions const = sql.split (/;  s * $ / m);
        pour (const statement of statement) {
            if (statement.length> 3) {
                // exécute chacune des instructions
                wait client.query (statement);
            }
        }
    } catch (err) {
        console.log( err );
        throw err;
    } finally {
        // close the database client
        await client.end();
    }
};
init().then( () => {
    console.log( "finished" );
} ).catch( () => {
    console.log( "finished with errors" );
} );
Next, copy and paste the following code into initdb.pgsql.
-- Drops guitars table
DROP TABLE IF EXISTS guitars;
-- Creates guitars table
CREATE TABLE IF NOT EXISTS guitars (
    id INT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY
    , user_id varchar(50) NOT NULL
    , brand varchar(50) NOT NULL
    , model varchar(50) NOT NULL
    , year smallint NULL 
    , color varchar(50) NULL
)
Next, add a new script to package.json.
    "initdb": "ts-node tools/initdb",
Now, go to the terminal and run the new script.
npm run initdb
You should see the message finished at the console. A new table named guitars is now in your database! Any time you want to reset your database, just rerun the script.
Add API routes in Node.js
To complete the API, you need to add new routes to Express to create, query, update, and delete guitars. First, create a new file under src/routes named api.ts. Add the following code to this file.
import * as express from "express";
import pgPromise from "pg-promise";
export const register = ( app: express.Application ) => {
    const oidc = app.locals.oidc;
    const port = parseInt( process.env.PGPORT || "5432", 10 );
    const config = {
        database: process.env.PGDATABASE || "postgres",
        host: process.env.PGHOST || "localhost",
        port,
        user: process.env.PGUSER || "postgres"
    };
    const pgp = pgPromise();
    const db = pgp( config );
    app.get( `/api/guitars/all`, oidc.ensureAuthenticated(), async ( req: any, res ) => {
        essayer {
            const userId = req.userContext.userinfo.sub;
            const guitars = await db.any( `
                SELECT
                    identifiant
                    , brand
                    , model
                    , year
                    , color
                FROM    guitars
                WHERE   user_id = $[userId]
                ORDER BY year, brand, model`, { userId } );
            return res.json( guitars );
        } catch ( err ) {
            // tslint:disable-next-line:no-console
            console.error(err);
            res.json( { error: err.message || err } );
        }
    } );
    app.get( `/api/guitars/total`, oidc.ensureAuthenticated(), async ( req: any, res ) => {
        essayer {
            const userId = req.userContext.userinfo.sub;
            const total = await db.one( `
            SELECT  count(*) AS total
            FROM    guitars
            WHERE   user_id = $[userId]`, { userId }, ( data: { total: number } ) => {
                return {
                    total: +data.total
                };
            } );
            return res.json( total );
        } catch ( err ) {
            // tslint:disable-next-line:no-console
            console.error(err);
            res.json( { error: err.message || err } );
        }
    } );
    app.get( `/api/guitars/find/:search`, oidc.ensureAuthenticated(), async ( req: any, res ) => {
        essayer {
            const userId = req.userContext.userinfo.sub;
            const guitars = await db.any( `
                SELECT
                    identifiant
                    , brand
                    , model
                    , year
                    , color
                FROM    guitars
                WHERE   user_id = $[userId]
                AND   ( brand ILIKE $[search] OR model ILIKE $[search] )`,
                { userId, search: `%${ req.params.search }%` } );
            return res.json( guitars );
        } catch ( err ) {
            // tslint:disable-next-line:no-console
            console.error(err);
            res.json( { error: err.message || err } );
        }
    } );
    app.post( `/api/guitars/add`, oidc.ensureAuthenticated(), async ( req: any, res ) => {
        essayer {
            const userId = req.userContext.userinfo.sub;
            const id = await db.one( `
                INSERT INTO guitars( user_id, brand, model, year, color )
                VALUES( $[userId]$[brand]$[model]$[year]$[color] )
                RETURNING id;`,
                { userId, ...req.body  } );
            return res.json( { id } );
        } catch ( err ) {
            // tslint:disable-next-line:no-console
            console.error(err);
            res.json( { error: err.message || err } );
        }
    } );
    app.post( `/api/guitars/update`, oidc.ensureAuthenticated(), async ( req: any, res ) => {
        essayer {
            const userId = req.userContext.userinfo.sub;
            const id = await db.one( `
                UPDATE guitars
                SET brand = $[brand]
                    , model = $[model]
                    , year = $[year]
                    , color = $[color]
                WHERE
                    id = $[id]
                    AND user_id = $[userId]
                RETURNING
                    id;`,
                { userId, ...req.body  } );
            return res.json( { id } );
        } catch ( err ) {
            // tslint:disable-next-line:no-console
            console.error(err);
            res.json( { error: err.message || err } );
        }
    } );
    app.delete( `/api/guitars/remove/:id`, oidc.ensureAuthenticated(), async ( req: any, res ) => {
        essayer {
            const userId = req.userContext.userinfo.sub;
            const id = await db.result( `
                EFFACER
                FROM    guitars
                WHERE   user_id = $[userId]
                AND     id = $[id]`,
                { userId, id: req.params.id  }, ( r ) => r.rowCount );
            return res.json( { id } );
        } catch ( err ) {
            // tslint:disable-next-line:no-console
            console.error(err);
            res.json( { error: err.message || err } );
        }
    } );
};
Update src/routes/index.ts to include the new api module.
import * as express from "express";
import * as api from "./api";
export const register = ( app: express.Application ) => {
    const oidc = app.locals.oidc;
    // define a route handler for the default home page
    app.get( "/", ( req: any, res ) => {
        const user = req.userContext ? req.userContext.userinfo : null;
        res.render( "index", { isAuthenticated: req.isAuthenticated(), user } );
    } );
    // define a secure route handler for the login page that redirects to /guitars
    app.get( "/login", oidc.ensureAuthenticated(), ( req, res ) => {
        res.redirect( "/guitars" );
    } );
    // define a route to handle logout
    app.get( "/logout", ( req: any, res ) => {
        req.logout();
        res.redirect( "/" );
    } );
    // define a secure route handler for the guitars page
    app.get( "/guitars", oidc.ensureAuthenticated(), ( req: any, res ) => {
        const user = req.userContext ? req.userContext.userinfo : null;
        res.render( "guitars", { isAuthenticated: req.isAuthenticated(), user } );
    } );
    api.register( app );
};
Finally, update src/index.ts to add a new configuration option immediately following the line to create the Express application. This code enables Express to parse incoming JSON data.
const app = express();
// Configure Express to parse incoming JSON data
app.use( express.json() );
Update the User Interface with Vue, Axios, and Parcel
The API is ready. To complete the application, you need to add some code to the frontend to consume the API. You can take advantage of TypeScript with frontend code, as well.
This final step of the project uses Vue for frontend rendering, Axios for making HTTP calls to the backend API, and Parcel to both transpile TypeScript and bundle all the dependencies together into a single JavaScript file.
First, install new dependencies at the console using the following commands.
npm install axios vue materialize-css
npm install --save-dev parcel-bundler @types/axios @types/materialize-css @types/vue
Make a new folder under src named public. Make a new folder under src/public named js. Create a file under src/public/js named main.ts and add the following code.
import axios from "axios";
import * as M from "materialize-css";
import Vue from "vue";
// tslint:disable-next-line no-unused-expression
new Vue( {
    computed: {
        hazGuitars(): boolean {
            return this.isLoading === false && this.guitars.length > 0;
        },
        noGuitars(): boolean {
            return this.isLoading === false && this.guitars.length === 0;
        }
    },
    data() {
        return {
            brand: "",
            color: "",
            guitars: [],
            isLoading: true,
            model: "",
            selectedGuitar: "",
            selectedGuitarId: 0,
            year: ""
        };
    },
    el: "#app",
    methods: {
        addGuitar() {
            const guitar = {
                brand: this.brand,
                color: this.color,
                model: this.model,
                year: this.year
            };
            axios
                .post( "/api/guitars/add", guitar )
                .then( () => {
                    this.$refs.year.focus();
                    this.brand = "";
                    this.color = "";
                    this.model = "";
                    this.year = "";
                    this.loadGuitars();
                } )
                .catch( ( err: any ) => {
                    // tslint:disable-next-line:no-console
                    console.log( err );
                } );
        },
        confirmDeleteGuitar( id: string ) {
            const guitar = this.guitars.find( ( g ) => g.id === id );
            this.selectedGuitar = `${ guitar.year } ${ guitar.brand } ${ guitar.model }`;
            this.selectedGuitarId = guitar.id;
            const dc = this.$refs.deleteConfirm;
            const modal = M.Modal.init( dc );
            modal.open();
        },
        deleteGuitar( id: string ) {
            axios
                .delete( `/api/guitars/remove/${ id }` )
                .then( this.loadGuitars )
                .catch( ( err: any ) => {
                    // tslint:disable-next-line:no-console
                    console.log( err );
                } );
        },
        loadGuitars() {
            axios
                .get( "/api/guitars/all" )
                .then( ( res: any ) => {
                    this.isLoading = false;
                    this.guitars = res.data;
                } )
                .catch( ( err: any ) => {
                    // tslint:disable-next-line:no-console
                    console.log( err );
                } );
        }
    },
    mounted() {
        return this.loadGuitars();
    }
} );
Update tsconfig.json to exclude the src/public folder from the backend Node.js build process.
{
    "compilerOptions": {
        "module": "commonjs",
        "esModuleInterop": true,
        "target": "es6",
        "noImplicitAny": true,
        "moduleResolution": "node",
        "sourceMap": true,
        "outDir": "dist",
        "baseUrl": ".",
        "paths": {
            "*": [
                "node_modules/*"
            ]
        }
    },
    "include": [
        "src/**/*"
    ],
    "exclude": [
        "src/public"
    ]
}
Create a new tsconfig.json file under src/public/js and add the following code. This TypeScript configuration is to compile main.ts for use in the browser.
{
    "compilerOptions": {
        "lib": [
            "es6",
            "dom"
        ],
        "noImplicitAny": true,
        "allowJs": true,
        "target": "es5",
        "strict": true,
        "module": "es6",
        "moduleResolution": "node",
        "outDir": "../../../dist/public/js",
        "sourceMap": true
    }
}
Next, update src/index.ts to configure Express to serve static files from the public folder. Add this line after the code that configures Express to use EJS.
...
// Configure Express to use EJS
app.set( "views", path.join( __dirname, "views" ) );
app.set( "view engine", "ejs" );
// Configure Express to serve static files in the public folder
app.use( express.static( path.join( __dirname, "public" ) ) );
Update src/views/guitars.ejs to add the Vue application template and a reference to the js/main.js file.
    
    
    Guitar Inventory 
    
    
    
    
    
        
            
                Guitar list
                
                    
                        
                            Year 
                            Brand 
                            Model 
                            Color 
                             
                    
                    
                        
                            
                                
                             
                         
                    
                
                No guitars yet!
            
            
                Add a guitar
                
            
            
                
                
            
        
    
     
Finally, update package.json to add a new parcel script, update the build script, and add a new alias section for Vue. The alias section points Parcel to the correct Vue file to bundle with src/public/js/main.ts.
  "scripts": {
    "clean": "rimraf dist/*",
    "copy-assets": "ts-node tools/copyAssets",
    "lint": "tslint -c tslint.json -p tsconfig.json --fix",
    "tsc": "tsc",
    "parcel": "parcel build src/public/js/main.ts -d dist/public/js",
    "build": "npm-run-all clean lint tsc copy-assets parcel",
    "dev:start": "npm-run-all build start",
    "dev": "nodemon --watch src -e ts,ejs --exec npm run dev:start",
    "start": "node .",
    "initdb": "ts-node tools/initdb",
    "test": "echo "Error: no test specified" && exit 1"
  },
  "alias": {
    "vue": "./node_modules/vue/dist/vue.common.js"
  },
Now, restart the build and take your new web application for a spin!
npm run dev

Learn More About Node and TypeScript
This tutorial only scratches the surface of what you can do with Node.js and TypeScript. Below are more resources to explore.
You can find the completed Guitar Inventory project on GitHub.
Follow us for more great content and updates from our team! You can find us on TwitterFacebookand LinkedIn. Des questions? Hit us up in the comments below.
 
  
   
 
Source link 
