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.
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
insérez le code suivant.
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