Documenter mon API

Introduction

Quand on est un intermittent du développement, il y a quelque chose de super compliqué : se souvenir ce que l’on a fait la dernière fois et que chaque modification ne casse pas tout …

Pour le moment, je palliais aux soucis en :

  • Committant souvent : me permet de revenir voir ce que j’ai fait,
  • Mettant en place un maximum de tests unitaires : ce qui peut-être frustrant quand on prototype mais bon.

Il reste un dernier souci : euh … l’API elle attend quoi déjà ?

Bref … faut documenter. Mais bon tant qu’à faire j’aimerais bien ne pas y passer trop de temps car bon : c’est quand même du dev perso / jetable !

Swagger

Dans les différents projets sur lesquels j’interviens, la documentation des API Rest est réalisé via Swagger ou un équivalent (Nelmio en php/symfony).

Ici, je ne vais repartir des outils proposés comme l’éditeur, la génération etc car … le mal est fait : l’API existe …

Alors autant dire que des solutions, il en existe plusieurs … et pour certaines, il existe même différentes combinaisons. Donc, j’ai fait des choix …

Swagger-jsdoc / Swagger-ui-express

Présentation

  • swagger-jsdoc  : permet d’utiliser la syntaxe JSDoc pour générer la documentation au format swagger,
  • swagger-ui-express : permet d’ajouter une route qui va exposer la documentation sous la forme d’une interface Swagger-ui. Ici dédié à Express.

Mise en place

Je vous passe les npm install habituel pour la mise en place directe.

Il faut commencer par mettre un peu de doc sur le service. L’idée est bien d’utiliser la documentation faîte sur les méthodes des contrôleurs directement :

/**
     * @swagger
     * /api/zones:
     *    get:
     *      description: Return all the zone
     */
    public getAll = async (req: IAppRequest, res: Response) => {
       const appResponse: AppResponse<any> = await ZoneService.getAll();
       return res.status(appResponse.code).json(appResponse);
    } // getAll

Ensuite, j’ai crée un fichier ~/src/config.doc.ts dont le but est de centraliser la mise en place de la documentation. Le fichier contient la configuration de la génération de la documentation par swagger-jsoc :

    private static options = {
        swaggerDefinition: {
          info: {
            title: "The Beer Project - API",
            version: "1.0.0",
            description: "API Rest for the Beer Project",
          },
        },
        // Uniquement les fichiers controllers
        apis: ["src/controllers/*"],
      };

    private static specs = swaggerJSDoc(ConfigDoc.options);

Puis, une fonction qui enregistre la route au niveau de l’application :

/**
     * Ajoute la route de la documentation
     * @param app
     */
    public static addDocRoute(app: any) {
        app.use("/api/docs", swagger.serve, swagger.setup(ConfigDoc.specs));
    }

Cette fonction utilise swagger-ui-express pour servir la route (swagger.serve) et passe les éléments générés par swagger-jsdoc en paramètre.

Test

Un petit npm start puis direction http://localhost:3000/api/doc et :

C’est déjà pas mal. Test ? Là au début, j’ai été un peu déçu car je n’ai eu aucune réponse … Le souci ne venait pas du code en tant que tel mais de la documentation. Pour que l’interface, gère une réponse, il faut lui fournir l’info :

/**
     * @swagger
     * /api/zones:
     *    get:
     *      description: Return all the zone
     *      responses:
     *        200:
     *         description: OK
     *         schema:
     *           type: object
     */
    public getAll = async (req: IAppRequest, res: Response) => {
       const appResponse: AppResponse<any> = await ZoneService.getAll();
       return res.status(appResponse.code).json(appResponse);
    } // getAll

Et là :

Bilan

Cà marche mais il faut doubler l’information et tout documenter manuellement …

TSOA

Présentation

En naviguant à droite et à gauche, j’ai fini par tomber sur ce projet : TSOA. Le principe me plaît car il semble qu’il soit possible de faire d’une pierre deux coups :

  • Des décorateurs qui définissent l’action,
  • Les décorateurs servent également à la documentation.

Et j’aime bien ce genre de principe.

Mise en place

Alors la documentation bien que longue ne contient pas de [Get Started] donc j’ai un galéré à savoir comment mettre en place tout le système et je ne suis même pas sûr d’avoir tout bon …

Tout commence par un npm install tsoa puis il faut créer le fichier tsoa.json qui va permettre de définir deux choses :

  • L’emplacement des contrôleurs : routes,
  • L’emplacement de la documentation générée : swagger.
{
    "swagger": {
        "outputDirectory": "./src/swagger",
        "entryFile": "./src/app.ts"
    },
    "routes": {
        "entryFile": "./src/app.ts",
        "routesDir": "./src/routes"
    }
}

Le projet va aller lire les sources et pour cela, il lui faut un point d’entrée « entryFile » qui peut-être votre fichier contenant la description de votre application.

Une fois cela fait, il faut aller modifier le contrôleur pour ajouter des décorateurs. Dans mon cas, j’ai ajouté @Route et @Get :

/**
 * Controller pour zone controller
 */
@Route("/tsoa/v1/zones")
export class TSOAZoneController {

    @Get()
    public async getZones(): Promise<IZone[]> {
        const appResponse: AppResponse<any> = await ZoneService.getAll();
        return new Promise<IZone[]>((resolve, reject) => {
            if (appResponse.success) {
                resolve(appResponse.data);
            } else {
                reject(appResponse.message);
            }
        });
    }

}

Premier petit truc : pour éviter des erreurs, il faut ajouter une entrée dans le fichier tsconfig.json :

 "experimentalDecorators": true

Sinon, les décorateurs ne passent pas.

Comme pour les autres contrôleurs, il faut l’ajouter dans le fichier d’entrée (app.ts dans mon cas):

// Oui le nom est pour test :o) 
import { TSOAZoneController } from "./controllers/api-tsoa.zone.controller";

Maintenant, il faut lancer une commande qui va générer un fichier contenant toutes les routes. Et oui, rien de magique ! C’est du code généré !

$> tsoa routes
$> tsoa swagger

La première va générer un fichier routes.ts dans le répertoire pointé par routeDir et le deuxième va générer un fichier swagger.json dans le répertoire paramétré plus haut.

Premier souci

Alors, un premier souci lors du lancement de la commande. Désolé, je n’ai pas la capture mais en gros: il n’arrivait à déterminer les types de mon objet. En fait, dans mon cas, ma classe hérité de Mongoose.Document et çà : il n’aime pas. Il faut des objets tout simple. J’ai fait les modifications et hop çà marche !

Plus d’informations ici.

Nouvelle génération

J’ai bien mon fichier de route et mon fichier swagger.json.

Pour le fichier de route, il faut l’enregistrer dans mon fichier app.ts (normal). Dans l’ordre :

  • Il faut importer le fichier de route généré juste avant : import { RegisterRoutes } from "./routes/routes";
  • Via l’export RegisterRoutes, on le laisse enregistrer ses routes : RegisterRoutes(this.app as express.Express);

La documentation indique qu’il est intéressant d’utiliser le package methodOverride pour ajouter des verbes supplémentaires. Enfin …. elle le dit pas mais c’est dans les exemples de code.

Test

On lance et miracle : ça marche.

Documentation

Pour la documentation, il y a encore un peu de travail mais pas tant que cela par rapport à ce que l’on a fait avant. En fait, il faut modifier la commande qui récupère la documentation pour qu’elle aille directement lire le fichier swagger.json généré :

/**
     * Ajoute la route de la documentation
     * @param app
     */
    public static addDocRoute(app: any) {
        // Version JSODC
        app.use("/api/jsDocs", swagger.serve, swagger.setup(ConfigDoc.specs));
        // Version TSOA
        app.use("/swagger.json", express.static(__dirname + "/swagger/swagger.json"));
        app.use("/api/tsoa", swagger.serve, swagger.setup(swaggerJSON));
    }

Et bim, ça marche. On profite même de la récupération des documentations réalisées directement sur les entités :

Générer à la volée

Alors par contre souci : il faut que cela rentre dans mon build de dev car sinon, je serais jamais à jour. Pour cela, deux nouvelles entrées dans le package json :

"watch-tsoa": "onchange 'src/**/*tsoa*.ts' -- npm run tsoa",
"tsoa": "tsoa routes && tsoa swagger"

La première appelle la deuxième si quelques choses dans mes contrôleurs et l’autre appelle les commandes TSOA.

Bilan

C’est pas tout mal … J’aime bien le principe qu’une information serve deux fois …

Mais il reste pas mal de choses à valider :

  • Gestion des POST, PUT & Co …
  • Et surtout la sécurité !!!

Bilan de la journée

Clairement la première solution est pratique pour un projet dans lequel tout est déjà en place. On vient vraiment documenter. Donc je vais la privilégier dans ce cas.

Par contre, j’ai une nouvelle API à faire (enfin … disons que j’ai envie) et je vais essayer de pousser TSOA.

Mais ça … c’est pour un autre demain.

NodeJS, Cloud, tout ça …

Présentation

Depuis quelques semaines, je « travaille » sur NodeJS pour tester ce que cela peut donner dans un projet. L’idée étant comme d’habitude d’avoir une vision des concepts sans aller (malheureusement) jusqu’à l’expertise …

L’objectif du jour est de voir comment je pourrais héberger une application NodeJS dans le cloud … Pourquoi ? Parce que !

Lecture, recherche & co

Liens

Comme pour chaque journée de ce type, cela commence par de la lecture :). Les différents liens :

AWS – Amazon

Juste une petite note sur un point que j’ai pas du bien comprendre :

Les coûts s’élèveront généralement à environ 27,42 USD/mois dans les limites de l’offre gratuite d’AWS.

L’offre gratuite à donc un coût ? 🙂

Grâce à l’application de calcul, je pense que l’option gratuite intègre en fait un mode par réduction mais j’aime bien être mauvaise langue 🙂

Azure

Dans le même sens, Azure demande un numéro de carte pour créer un compte. On va faire confiance à Micro$oft …

Base de données

Présentation

Les différents services proposent des systèmes de stockage de données. Mais comme l’idée c’est éventuellement de tester différents et que j’ai pas envié à chaque fois de remplir la base, je vais passer par un autre système : https://mlab.com/ (qui finalement lui stocke sur le cloud).

Pourquoi MLab ?

Honnêtement, le choix … a été fait de manière … un peu arbitraire :). En fait, c’est la plateforme qui a été présentée dans plusieurs tutoriaux donc.

Je sais qu’il existe une plateforme proposée directement par les créateurs de MongoDB : MongoDB Atlas. Mais bon … pas bien vu la différence …

Création du compte

La création du compte est comme toutes les créations de compte : simple :). Il faut juste bien faire attention à sélectionner « Sand Box » pour ne pas avoir des frais tout de suite :). Je suis parti sur Amazon …

Le reste c’est vraiment du clic-clic mais au bout, j’obtiens une chaîne de connexion vers ma « base de données » mongodb : mongodb://:@ds117965.mlab.com:17965/. A noter que pour accéder à la base, il faut créer un compte spécifique différent de celui qui gère mLab.

Mise en place

Dernière chose : il faut mettre en place dans l’application, le lien vers cette base de données ! Pour anticiper un peu les choses, j’ai créer un fichier de config pour la production qui contient les éléments suivants :


const crypto = require('crypto').randomBytes(256).toString('hex');

const config = {
    app: {
        PORT: process.env.PORT || 3000
        , secret: crypto
    }
    , db: {
        uri: process.env.MOGODB || 'mongo:27017'
        , user: ''
        , pwd: ''
        , name: process.env.DATABASE
    }
}

module.exports = config;

En regardant, les différentes documentations, j’ai vu qu’il était possible de créer des variables de paramétrages qui doivent ensuite permettre d’être exploité dans l’application. Ainsi, j’évite d’avoir mes mots de passes dans le fichier de config …

Tests

Mise en place d’une commande spécifique : "build:prod": "NODE_ENV=prod MOGODB=':@ds117965.mlab.com:17965' DATABASE= PORT=3000 supervisor app.js", et après un enregistrement et une saisie :

Bilan

Honnêtement, je me disais que cela allait être simple et force est de constater que cela l’a été. Bon, il reste à déployer cela sur une plateforme Cloud. Par contre, j’espère ne pas avoir trop besoin de manipuler la base car ce n’est pas hyper simple avec l’interface de mLab. Heureusement, je peux configurer et accéder depuis l’application Robo3T …

Heroku

Pour commencer, je vais essayer de déployer l’application sur la plateforme Heroku. J’ai trouvé que c’était à priori, la plateforme la plus simple mais bon … je peux me tromper. Pour commencer, j’ai vraiment fait au plus simple en suivant le guide présent ici :

  • Création d’un compte (il faut des comptes et des mots de passes),
  • Installation d’un CLI (c’est la mode ça aussi, les cli…),
  • J’ai pas cloné l’application : j’ai la mienne. D’ailleurs avant d’aller plus loin, je vais cloner mon appli dans un autre répertoire histoire de voir si j’ai pas des fichiers en trop
  • Initialisé l’application : heroku create et récupéré les infos sur les urls. A noter que cela met directement à jour la conf git pour intégrer un repo distant,
  • Pousser le code : git push heroku master.

Le dernier point permet d’avoir une trace du déploiement et j’ai déjà détecté un ou deux « soucis » : Resolving node version 6.x... & This app may not specify any way to start a node process. Pour corriger ce point, il faut préciser dans package.json :


  "engines" : {
     "node" : ">=8.5.0" 
     , "npm" : ">=5.3.0"
  },

  • Lancement en sélectionnant bien le mode free : heroku ps:scale web=1 ,
  • Ouverture de la page : BOUM !!

Bon pour le moment, pas de panique. Je pense que le souci vient d’un souci de config car je n’ai pas paramétré la chaîne de connexion etc… Effectivement, après la configuration des variables, les choses marchent beaucoup mieux :

La dernière chose que je voulais faire : pouvoir publier sans pour autant être obligé de saisir un login / mot de passe. C’est assez simple et les docs sont ici :

La boulette

Alors comment dire : la boulette! Pour tester, le passage par l’environnement pour la configuation, j’ai voulu tester en mettant une commande supplémentaire dans package.json. Que j’ai bien gentillement commité ! Bravo ! Allez, c’est parti pour un changement de mot de passe.

Azure

Début

Ayant un collègue qui ne jure que par Azure donc bon … on va essayer !

Mise en place

Comme pour Heroku, il existe une page qui décrit les premières actions à réaliser pour déployer une application web. Je vais gentiment suivre les indications :).

  • Création d’un compte (nan mais sérieux : j’ai combien de compte ?)
  • Accès au Shell : c’est un peu long …
  • Création d’un compte de déploiement. Le résultat est un peu déconcertant car tous les champs sont à null …
  • Création d’un groupe de ressources : si j’ai bien compris, c’est un conteneur qui permet de regrouper différents outils proposer dans la plateforme
  • Création d’un plan pour la future application. Ici, on ne crée pas encore l’application mais le « plan » que l’on met dans le groupe et qui définit les ressources que l’on souhaite utiliser.
  • Création de l’application : la on va créer l’application …
  • Configuration pour le déploiment …
  • Push et test : mini Boom 🙂

Encore une fois, j’ai pas configuré les variables de configuration. Une fois cela fait : l’application fonctionne bien et je retrouve bien mes données.

Bilan

J’étais peut-être fatigué mais j’ai trouvé le déploiement azure fastidieux … C’était long et la commande Shell a planté plusieurs fois …

Amazon

Pas eu le temps …

Bilan

J’ai une application déployée de manière simultanée sur deux environnements différents mais avec la même base de données. Les deux plateformes sont fonctionnelles mais je trouve Heroku plus simple de prise en main mais je pense qu’on doit pouvoir aller plus loin avec Azure. Bon maintenant, faut que je surveille le trafic 😀 !

Votre PassPort !

PassPort

PassPort est un middleware NodeJs qui s’occupe d’authentifier un utilisateur. Comme je fais du NodeJS depuis quelques temps et qu’après quelques recherches, je me suis rendu compte que ce middelware était assez populaire : c’est parti pour aujourd’hui !

Objectifs

Comprendre et mettre en place PassPort dans un projet « existant ». Je dis « existant » car c’est vraiment un tout début de quelque chose.

Un peu de lecture …

Comme d’habitude, je commence par un peu de Lecture et de Visionnage. Cf. les liens

C’est parti !

Dépendances

Dans le cadre de mon projet, j’ai besoin d’installer différentes dépendances :

  • passport : le middleware utilisé ici,
  • passport-local : la stratégie qui sera employée,
  • connect-flash : gestion de message via une session,
  • bcrypt-nodejs : pour la sécurisation des mots de passe
  • cookie-parser : le nom est assez clair,
  • express-session : idem.

Précision sur les stratégies : un élément intéressant de Passport est qu’il met à disposition différents moyen de s’identifier et intègre par exemple des moyens de connexion via un compte Google, Facebook ou autres. Ici, je me mets en mode local pour commencer.

Premières configurations

Quelques premiers petites configurations :


app.use(
        session({ 
            secret: config.app.secret 
            , resave: false
            , saveUninitialized: false
        })
    ); // session info
app.use(passport.initialize());
app.use(passport.session()); // Passage de express-session à Passport qui va s'en servir dans notre cas pour stocker les infos
app.use(flash()); // C'est connect-flash qui sera utilisé pour stocker des messages dans les sessions

Pour le secret, il est calculé à chaque chargement de l’application : const crypto = require('crypto').randomBytes(256).toString('hex');. Cela m’évite d’avoir une phrase en dur dans le code.

Enregistrement

Le principe est assez « simple » : il faut créer paramétrer la stratégie de manière à ce que Passport puisse se charger du passage des informations. Les différents tutos et la documentation présentent bien ce qu’il y a à faire. Un galère quand même (qui m’a bien fait perdre quelques bonnes minutes) : les champs de formulaire doivent paramétré avec name et pas uniquement id …

Pour la mise en place, j’ai suivi le conseil d’un des exemples, j’ai crée un fichier qui contient les différentes méthodes dédiés à Passport : passport.js. C’est dans celui-ci que j’ai centralisé :

  • Les fonctions de sérialization et désérialization : nécessaire pour le stockage en session ou la récupération,
  • La fonction d’enregistrement
  • La fonction de login

Quelques exemples de code :
Une configuration passport pour l’enregistrement :


    /**
     * Enregistrement de l'utilisateur
     */
    passport.use('local-register'
            , new LocalStrategy({
                    passReqToCallback : true
                }
                , function(req, email, password, done){
                    process.nextTick(function() {
                        // Gestion du compte
                        var newAccount = new Account();
                        newAccount.email = email;
                        newAccount.username = req.param('username');
                        newAccount.password = password; // pas besoin de crypté ici, c'est géré (normalement) par un hook sur la classe Account

                        // Save
                        newAccount.save( (err, newAccountSaved) => {
                            if(err) throw err; // TODO : améliorer la gestion d'erreur
                            return done(null, newAccountSaved);
                        });
                    }); // /process.nextTick
                } // /function(req, email, password, done){
        ) // new LocalStrategy
    ); // /local-register

L’enregistrement de la route


router.post('/register', passport.authenticate('local-register', {
    successRedirect : '/people', 
    failureRedirect : '/register', 
    failureFlash : true // Pour afficher les messages d'erreur
}));

Login

Fonctionne de la même manière mais adapté au login :

  • Enregistrement d’une stratégie « local-login »
  • Ajout d’une route

Bilan

Bilan mitigé. D’un côté, il y a des choses intéressantes qui sont gérés comme la mise à disposition du User directement dans la requête (même s’il faut gérer la récupération manuellement). D’un autre côté, finalement, tout est géré manuellement. Passport vient juste simplifier (et c’est déjà beaucoup) l’intégration dans l’application.

Je pense que pour bien voir l’intérêt, il faut sans doute intégrer d’autres stratégie mais çà : c’est pour un autre demain.

[Angular][NodeJS] Gestion des routes

Présentation

Un point qui peut devenir « embêtant » quand on associe Angular & NodeJs et que NodeJS « sert » l’application Angular: la gestion des routes.

En effet, comment faire la différence entre une route qui doit être gérée par NodeJS (l’API) et une route qui est gérée par Angular ? Il ne faudrait pas qu’un utilisateur reçoivent une erreur 404 de la part de NodeJs alors qu’il essaye d’accéder à une URL gérée par Angular.

Solution : ce qui n’est pas géré par Node renvoie vers Angular


app.get('*', (req, res) => {
    res.sendFile(path.join( __dirname + '/client/dist/index.html' ));
});

Cette route doit être intégrée après les différentes routes gérées dans NodeJS.

MEAN ? What’s that MEAN ? (Part 2)

Présentation

Suite de la semaine dernière …

Gestion du jeton

La semaine dernière, pour gérer la sécurité, JWT a été mis en place dans le projet via JSonWebToken et le code suivant dans le fichier contenant les routes de la partie authentification :


    /**
     * "Middleware" qui va intercepter les services AVANT certaines routes pour valider
     * que l'utilisateur est bien connecté
     */
    router.use((req, res, next) => {
        // Récupération du token
        const token = req.headers['authorization']; 
        // !token ?
        if (!token) { res.json({ success: false, message: 'No token provided' }); return; } 

        // Le token ayant été "crée" par jwt, on lui demande de recommencer le travail :)
        jwt.verify(token, config.secret, (err, decoded) => {
            if (err) { res.json({ success: false, message: 'Token invalid: ' + err }); return ;}

            // Ajout de ce qui a été décode (user._id) pour utilisation dans la suite du process
            req.decoded = decoded; 
            // Passage à la méthode suivante
            next(); 
        });
    });

.

En commençant le travail sur de nouvelles routes, j’ai constaté que l’accès aux routes demandait également le token. Ce que je n’avais pas identifié c’était que l’appel à router.use impliquant que ce test serait réalisé sur TOUTES les routes qui seraient définies après son ajout.

Donc comme les toutes sont enregistrés comme tel :


app.use('/authentification', authentication);
app.use('/blogs', blog);

toutes les routes « blogs » sont protégées. C’est bon à savoir et à garder dans un coin de la tête quand sur une application tu as une partie privée et publique …

MEAN ? What’s that MEAN ?

Introduction

Alors encore une fois, je rattrape mon retard technologique … Depuis plusieurs semaines (mois ?), je tombe régulièrement sur des articles / blog parlant de MEAN. Comme l’objectif de mes journées Off ou R&D est de découvrir, découvrons MEAN !

MEAN

Depuis des données, j’utilise LAMP et plus spécifiquement LAMPS : Linux, Apache, MySQL, PHP & Symfony :). MEAN se veut une autre plateforme composé de Mongo, Express, Angular(JS ou pas) et NodeJS.

Une petite description de chaque composant :

  • MongoDB : « base de données » NoSQL de type documentaire,
  • Express : Framework web pour NodeJS qui permet de créer des applications complètes ou des APIs,
  • AngularJS ou Angular : FrameWork Front End bien connu,
  • NodeJS : un runtime JS qui permet de faire tourner un serveur, d’exécuter des procédures, etc… Sa force est d’être non bloquant, performant. Il est associé à l’outil npm qui est une référence pour la gestion des dépendance (entre-autres)

BeerEDex

J’ai trouvé un tuto « rigolo » pour débuter pas forcément avec MEAN mais avec MEN (MongoDB, Express & NodeJS). Le sujet : faire un Pokedex ! Bon, moi, j’ai fait un BeerEDex ! Les liens :

Les éléments intéressants :

  • Mongoose : Un ODM pour MongoDB qui simplifie l’accès à la base MongoDB. C’est bien un ODM car MongoDB est base de données documentaires,
  • Nunjucks : Un framework de template qui (je trouve) ressemble beaucoup à Twig utilisé via Symfony,
  • Multer : Librairie qui permet de gérer les formulaires multipart/form-data qui vient compléter Express

Un peu de Docker

Sur la base du lien (ici), je me suis fait un fichier Docker pour être capable d’avoir une machine « web/nodejs » qui communique avec mongod en arrière plan. Pour ceux que cela vaut, mon fichier docker-compose :


version: "2"
services:
  web:
    image: devbieres/nodejs8
    volumes:
      - ./:/app
    ports:
      - "3000:3000"
    links:
      - mongo
    stdin_open: true
    tty: true
  mongo:
    image: mongo
    ports:
       - "27017:27017"
    volumes:
       - ./data:/data/db

Les différences avec le lien sont que :

  • j'utilise ma propre image nodejs
  • je mappe mongo avec un répertoire locale
  • je mets des options pour que la machine node reste en arrière plan

Blog

Allez c'est parti ! J'ai trouvé une série vidéo qui propose de créer un blog (as usual :))

  • Nodemon : Outil qui surveille les modifications dans le code et relance le serveur node/express. J'aurais aimé y pensé pendant BeerEDex 🙂
  • Génération d'un "secret" : const crypto = require('crypto').randomBytes(256).toString('hex');
  • La nouvelle version (4) d'Angular propose des messages d'erreur beaucoup plus clair en console comme via la page
  • require avec param : require('./routes/authentication')(router). Ce qui permet dans le module appelé : module.exports = (router) => { ... }
  • BodyParser : un gentil module d'express qui s'occupe de "parser" les données renvoyer par le front pour nous rendre les choses plus simples. Sympa !
  • BCrypt : librairie pour chiffrer et pas stocker les mots de passe en clair (ce qui est mal !)
  • NPM Cors : gestion des CROSS ORIGIN
  • JSONWebToken : Pour la gestion des tokens JWT du côté Back. Le truc bête qui fait perdre 5 minutes : les token se basent sur un secret qui est généré à chaque fois que le serveur est relancé ... donc les anciens tokens d'il y a deux minutes ne servent à rien.
  • Angular 2 Flash Messages: Petite librairie qui gère des messages simples envoyés à l'utilisateur
  • BootSwatch : Theme pour Boostrap
  • How to - Hoverable DropDown : comment faire simplement un bouton drop down

Liens