NodeJS & MongoDB
NodeJS & MongoDB
Présentation
NodeJS & MongoDB
Présentation
NodeJS est une librairie standard de Javascript qui permet d'écrire des applications sur notre machine, notamment de serveurs
Vous pouvez retrouver la documentation officiel ici
NodeJS & MongoDB
Présentation
MongoDB est une base de données (noSQL) qui enregistre des documents JSON mais ne permet pas de relation !
Vous pouvez retrouver la documentation officiel ici
NodeJS & MongoDB
Les premiers pas
NodeJS & MongoDB
Premiers pas
Le point d'entrée d'une application Javascript (nodejs, DOM, etc ...) c'est le fichier package.json
Ce fichier contient les informations de notre programme, ainsi que ces dépendances. Il est généré grâce à NPM avec la commande
npm init -yNodeJS & MongoDB
{
"name": "tuto",
"version": "1.0.0",
"description": "Nodejs tutorielle",
"main": "src/index.js",
"type": "module",
"scripts": {
"start": "nodemon src/index.js",
"test": "jest --watch --setupFiles dotenv/config",
"preinstall": "node bin/copy-past-env.js"
},
"dependencies": {
"cross-env": "^7.0.3",
...
}
}
Voici à quoi ressemble un package.json
NodeJS & MongoDB
{
"name": "tuto",
"version": "1.0.0",
"description": "Nodejs tutorielle",
"main": "src/index.js",
"type": "module",
"scripts": {
"start": "nodemon src/index.js",
"test": "jest --watch --setupFiles dotenv/config",
"preinstall": "node bin/copy-past-env.js"
},
"dependencies": {
"cross-env": "^7.0.3",
...
}
}
Voici les informations de votre projet
(type: module correspond à la nouvelle syntax es6 pour les imports et exports)
NodeJS & MongoDB
{
"name": "tuto",
"version": "1.0.0",
"description": "Nodejs tutorielle",
"main": "src/index.js",
"type": "module",
"scripts": {
"start": "nodemon src/index.js",
"test": "jest --watch --setupFiles dotenv/config",
"preinstall": "node bin/copy-past-env.js"
},
"dependencies": {
"cross-env": "^7.0.3",
...
}
}
Tout les scripts de démarrage et de test de notre application.
Pour lancer un scripts il suffit de faire
npm run <nomDuScript>
NodeJS & MongoDB
{
"name": "tuto",
"version": "1.0.0",
"description": "Nodejs tutorielle",
"main": "src/index.js",
"type": "module",
"scripts": {
"start": "nodemon src/index.js",
"test": "jest --watch --setupFiles dotenv/config",
"preinstall": "node bin/copy-past-env.js"
},
"dependencies": {
"cross-env": "^7.0.3",
...
}
}
Ces lignes correspondent au dépendances, ce sont des librairies (package) installé depuis "internet" afin que notre projet fonctionne corréctement
NodeJS & MongoDB
# Instale un paquet, et rajoute une ligne dans "dependencies"
# de notre package.json
$ npm install fastify
# Install tout les paquets spécfifié dans le package.json
$ npm install
# Supprime une dépendance
$ npm remove fastify
# Lance le script "start"
$ npm start
# Lance le script "test"
$ npm testIl est possible à tout moment d'utiliser NPM pour différentes actions :
NodeJS & MongoDB
Fastify
NodeJS & MongoDB
Fastify c'est une librairie (package) qui permet de construire des API web facilement
Les avantages de fastify sont les suivants :
- rapide
- léger
- il comprend les json schémas
- extensible
vous retrouverez la documentation de fastify en ligne !
NodeJS & MongoDB
Pour installer fastify, rien de plus simple
# Installation de fastify
$ npm install fastifyNodeJS & MongoDB
Utiliser fastify
// Importation du package "fastify"
import fastify from 'fastify'
// Création d'une application. L'option
// logger permet d'afficher dans la console
// les logs du serveur
const app = fastify({ logger: true })
// On démarre l'application sur un port
// et un Host donnée :
app.listen(4545, 'localhost')
NodeJS & MongoDB
Attacher des routes à fastify
// Déclaration d'une GET /hello
app.get('/hello', { options }, async () => {
return 'Hello World'
})
// Déclaration d'une POST /hello
app.post('/hello', { options }, async () => {
return 'Hello World'
})
// Déclaration d'une PATCH /hello
app.patch('/hello', { options }, async () => {
return 'Hello World'
})
// Déclaration d'une PUT /hello
app.put('/hello', { options }, async () => {
return 'Hello World'
})
// Déclaration d'une DELETE /hello
app.delete('/hello', { options }, async () => {
return 'Hello World'
})
NodeJS & MongoDB
Attacher des routes avec paramètres
// Déclaration d'une GET /hello
app.get('/hello/:name', { options }, async (request) => {
// Accéde au paramètre de la route nommé "name"
return `Hello ${request.params.name}`
})Vous pouvez en apprendre plus sur les paramètres de routes juste ici
NodeJS & MongoDB
Request et Reply
NodeJS & MongoDB
En fastify il est possible de récupérer les informations de la requête grâce à l'objet request. Il est passé en premier paramètre à toutes nos routes
app.post('/categories', async (request) => {
// Nous pouvons accéder au body de la request
const titre = request.body.titre
// On peut accéder aux headers de la request
const contentType = request.headers.contentType
// Les query strings
const page = request.query.page
})NodeJS & MongoDB
En fastify il est possible de récupérer des paramètres de notre route
app.patch('/categories/:id', async (request) => {
// Nous pouvons accéder au paramètre de la route
const id = request.params.id
})NodeJS & MongoDB
En fastify il est possible de définir des schemas (json schemas)
Ces schemas nous permettent de de définir la forme d'une Requête et d'une Réponse HTTP
NodeJS & MongoDB
Schematiser le "body" d'une requête
app.post('/categories', {
schema: {
body: {
type: 'object',
required: [ 'titre' ],
properties: {
titre: {
type: 'string'
}
}
}
}
}, async () => {
})NodeJS & MongoDB
Schematiser les query string
app.get('/categories', {
schema: {
querystring: {
type: 'object',
properties: {
page: {
type: 'number'
},
limit: {
type: 'number'
}
}
}
}
}, async () => {
})NodeJS & MongoDB
Schematiser les réponses
app.get('/categories', {
schema: {
response: {
200: {
type: 'array',
items: {
type: 'object',
required: [ '_id', 'titre' ],
properties: {
_id: { type: 'string' },
titre: { type: 'string'},
},
},
}
}
}
}, async () => {
})NodeJS & MongoDB
MongoDB
NodeJS & MongoDB
MongoDB est une base de données non relationel
Elle n'utilise pas SQL mais plutôt se base sur le format JSON
L'api de mongo est utilisable nativement en javascript
NodeJS & MongoDB
Les avantages d'une tel de base données sont les suivants:
- Rapide en écriture et lécture
- Simple à prendre en main
- N'échoue jamais (ne sort quasiment jamais d'erreur)
- Natif en javascript
NodeJS & MongoDB
Les désavantages d'une tel de base données sont les suivants:
- Non consistant (nous ne pouvons pas nous assurer de la forme de nos données)
- Non relationnelle (il est impossible d'attacher un document à un autre document ou alors très lent)
- Toute la logique est applicative (aucune logique dans la base de données)
NodeJS & MongoDB
Pour utiliser mongodb il est recommandé d'installer le driver nodejs
# Installation du driver mongodb pour nodejs
$ npm install mongodbNodeJS & MongoDB
Pour utiliser mongo il nous faut nous connecter à la base pour cela nous utilisons une URL de connexion
import mongo from 'mongodb'
async function start() {
// Connéction à la base de données,
// de recevons un client
const client = await mongo.MongoClient.connect(
'mongodb://<username>:<password>@<host>:<port>'
)
// Nous pouvons facilement récupérer une base de données
const db = client.db('nomDeLaBDD')
}NodeJS & MongoDB
Afin d'utiliser la base de données dans nos routes fastify, nous pouvons "décorer" notre application :
import fastify from 'fastify'
import mongo from 'mongodb'
async function start() {
// Création d'une application fastify
const app = fastify({ logger: true })
// Connéction à la base de données,
// de recevons un client
const client = await mongo.MongoClient.connect(
'mongodb://<username>:<password>@<host>:<port>'
)
// Nous pouvons facilement récupérer une base de données
const db = client.db('nomDeLaBDD')
// Nous décorons l'application en ajoutant la clef
// "db"
app.decorate('db', db)
// Pour accéder à la base de données il suffit de faire:
// app.db
}NodeJS & MongoDB
En mongo il est possible d'éfféctuer une recherche, vous pouvez utiliser toute une série d'opérateur
// Récupération de tout les documents d'une collection
const documents = await db
.collection('nomDeLaCollection')
.find()
.toArray()
// Nous pouvons filtrer ces documents
const doc2 = await db
.collection('books')
.find({ titre: 'Harry Potter' })
.toArray()
const dc3 = await db
.collection('books')
.find({ titre: { $regex: /^Harry/ } })
.toArray()NodeJS & MongoDB
Il est possible de récupérer un seul document
import mongo from 'mongodb'
// Nous récupérons un document par son ID
const doc = await db.collection('books').findOne({
// Ne pas oublié d'utiliser mongo.ObjectId
// dans nos recherche, sinon l'id ne peut correspondre
_id: mongo.ObjectId('KKDHFKS728238')
})
// Nous récupérons un document par l'un de ces champs
const john = await db.collection('users').findOne({
email: "john.doe@mail.com"
})NodeJS & MongoDB
Il est possible d'insérer une ou plusieurs données
const result = await db.collection('categories').insertOne({
titre: 'Ma catégorie'
})
// Ici result est un objet qui contient de statistique
// sur l'insertion de notre / nos documents :
result.insertedId // Retourne l'id du document tout just inséré
result.insertedCount // Retourne le nombre de document inséré
// Il est possible d'insérer plusieurs résultat à la fois
const result = await db.collection('categories').insertMany([
{ titre: 'Nature' },
{ titre: 'Science' },
])
// Nous pouvons récupérer tous les ids insérés
// dans la base de données sous forme de tableaux
// de string
result.insertedIdsNodeJS & MongoDB
Il est possible de mettre à jour des documents
import mongo from 'mongodb'
const result = await db.collection('categories').updateOne(
// Le premier paramètre correspond aux filtres
// de l'élément que nous voulons mettre ç jour
// Ici l'élément avec l'id données
{ _id: mongo.ObjectId('DJFKDH275623') },
// Le deuxième paramètre correspond au champs que nous
// mettons à jour
{ $set: { titre: 'Mise à jour du titre', description: 'coucou' } },
)NodeJS & MongoDB
Il est possible de supprimer des documents
import mongo from 'mongodb'
const result = await db.collection('categories').deleteOne(
// Le premier paramètre correspond aux filtres
// de l'élément que nous voulons mettre ç jour
// Ici l'élément avec l'id données
{ _id: mongo.ObjectId('DJFKDH275623') },
)NodeJS & MongoDB
Il est possible de personnalisé la réponse HTTP grâce à l'objet Reply. Il est envoyé en second paramètre de toutes nos routes
app.post('/categories', async (request, reply) => {
// Nous pouvons changer le status code
reply.code(201)
// Nous pouvons ajouter des en-tête HTTP
reply.header('Powered-By', 'fastify')
})NodeJS & MongoDB
Les plugins
NodeJS & MongoDB
Les plugins sont un système permettant de séparer notre code en plusieurs modules (fichier js)
// src/routes/categories.js
export default async function categoriesPlugin(app) {
app.get('/categories', async () => {
...
})
}NodeJS & MongoDB
On exporte un plugin fastify :
Le premier paramètre correspond à l'application fastify
// src/routes/categories.js
export default async function categoryPlugin(app, opts) {
app.get('/categories', async () => {
...
})
}NodeJS & MongoDB
On exporte un plugin fastify :
Le second paramètre correspond aux options du plugins
// src/routes/categories.js
export default async categoryPlugin(app, opts) {
app.get('/categories', async () => {
...
})
}NodeJS & MongoDB
Ici nous pouvons utiliser fastify et déclarer des routes, schemas, decorators ...
Attention ! Done doit être appelé à la fin du plugin !
// src/routes/categories.js
export default async function categoryPlugin(app, opts) {
app.get('/categories', async () => {
...
})
}NodeJS & MongoDB
Une fois notre plugin écrit, il est possible dans l'enregistrer :
// src/index.js
import fastify from 'fastify'
import monPlugin from './routes/categories.js'
async function start() {
const app = fastify({ logger: true })
// Nous enregistrons notre plugin
app.register(monPlugin)
}NodeJS & MongoDB
Nous enregistrons un plugin avec les options "opt1, opt2, opt3"
// src/index.js
import fastify from 'fastify'
import monPlugin from './routes/categories.js'
async function start() {
const app = fastify({ logger: true })
// Nous enregistrons notre plugin
app.register(monPlugin, {
opt1: true,
opt2: 'foo',
opt3: 'bar',
})
}NodeJS & MongoDB
Les Schemas
NodeJS & MongoDB
En fastify il est possible de déclarer des schemas réutilisable
Pour cela, il faut installer fastify-plugin afin de pouvoir déclarer des schémas globaux à toute notre application
NodeJS & MongoDB
Installation de fastify plugin
$ npm install fastify-pluginNodeJS & MongoDB
Nous pouvons écrire un plugin fastify pour nos schémas :
// src/schemas/categories.js
export default (app, opts, done) => {
app.addSchema({
$id: 'category',
type: 'object',
required: [ 'titre' ],
properties: {
titre: { type: 'string' },
},
})
done()
}NodeJS & MongoDB
Une fois écrit, notre plugin doit être enregistré :
// src/index.js
import fastify from 'fastify'
import fp from 'fastify-plugin'
import categorySchema from './schemas/categories.js'
async function start() {
const app = fastify({ logger: true })
app.register(fp(categorySchema))
}NodeJS & MongoDB
Il nous faut pas oublier de "wrapper" notre plugin dans "fp", sinon nos schémas ne seront pas accessible depuis l’extérieur du plugin
// src/index.js
import fastify from 'fastify'
import fp from 'fastify-plugin'
import categorySchema from './schemas/categories.js'
async function start() {
const app = fastify({ logger: true })
app.register(fp(categorySchema))
}NodeJS & MongoDB
Pour réutiliser un schema, il suffit de renseigner la clefs "$ref"
// src/routes/categories
export default (app, opts, done) => {
app.post(
'/categories',
{ schema: { body: { $ref: 'category' } } },
async () => {
..
}
)
done()
}NodeJS & MongoDB
On renseigne le schéma avec l'id "category" sur notre body
// src/routes/categories
export default (app, opts, done) => {
app.post(
'/categories',
{ schema: { body: { $ref: 'category' } } },
async () => {
..
}
)
done()
}NodeJS & MongoDB
NodeJS & MongoDB
Nodemon est un petit outil javascript (package) qui nous permet de redémarrer notre serveur à chaque modification de fichier !
NodeJS & MongoDB
Installation
$ npm install nodemonNodeJS & MongoDB
Mise en place
// package.json
{
...
"scripts": {
"start": "nodemon src/index.js",
...
},
...
}
NodeJS & MongoDB
Nous spécifions "nodemon" suivie de notre fichier principal d'application
// package.json
{
...
"scripts": {
"start": "nodemon src/index.js",
...
},
...
}
NodeJS & MongoDB
La Configuration
NodeJS & MongoDB
La configuration nous permet de définir des données variable en fonction des machines !
En fonction de notre poste d'installation ou du serveur et bien certaines données doivent changé (ex: l'url de connexion à la base de données)
NodeJS & MongoDB
La configuration s’effectue via des variables d’environnement afin de respecter les « Twelve Factors App »
NodeJS & MongoDB
Ces variables d’environnement sont déclaré dans un fichier nommé '.env' à la racine de notre projet
Attention !
- Ce fichier ne doit jamais être versionné
- On peut cependant versionné un fichier standard `.env.dist`
NodeJS & MongoDB
Afin d'utiliser ce fichier `.env` en nodejs il nous installer le package dotenv
$ npm install dotenvNodeJS & MongoDB
Une fois le paquet installé, il faut l'importer et lancé la fonction "config"
// src/index.js
import dotenv from 'dotenv'
dotenv.config()
// Nous pouvons maintenant accéder aux
// variables déclarer dans le fichier `.env`
// grâce à
process.env.MA_VARIABLENodeJS & MongoDB
Authentification Via JWT
NodeJS & MongoDB
L'auth. JWT fonctionne grâce à un sytstème de token (le fameux JSON Web Token)
NodeJS & MongoDB
Afin de mettre en place une authentification JWT il nous un plugin fastify : fastify-jwt
$ npm install fastify-jwtNodeJS & MongoDB
Afin d'utiliser le plugin il nous l'enregistrer dans notre application :
// src/index.js
import fastify from 'fastify'
import fastifyJwt from 'fastify-jwt'
async function start() {
const app = fastify({ logger: true })
app.register(fastifyJwt, {
secret: 'clef utilisé pour crypter notre token'
})
}NodeJS & MongoDB
On enregistre le plugin fastify-jwt en lui spécifiant le "secret" utilisé pour crtypter notre token
// src/index.js
import fastify from 'fastify'
import fastifyJwt from 'fastify-jwt'
async function start() {
const app = fastify({ logger: true })
app.register(fastifyJwt, {
secret: 'clef utilisé pour crypter notre token'
})
}NodeJS & MongoDB
Grâce à ce plugin nous pouvons générer un JWT
// src/routes/users.js
export default (app, opts, done) => {
// Création de la route d'authentification
app.post(
'/authenticate',
{ schema: { body: { $ref: 'credential' } } },
async (request, reply) => {
// On récupére et on valide l'utilisateur
const user = // Récupération + Validation
reply.code(201)
return { token: app.jwt.sign(user) }
}
)
done()
}
NodeJS & MongoDB
Ici nous cryptons l'objet user dans un token JWT
// src/routes/users.js
export default (app, opts, done) => {
// Création de la route d'authentification
app.post(
'/authenticate',
{ schema: { body: { $ref: 'credential' } } },
async (request, reply) => {
// On récupére et on valide l'utilisateur
const user = // Récupération + Validation
reply.code(201)
return { token: app.jwt.sign(user) }
}
)
done()
}
NodeJS & MongoDB
Pour authentifier un utilisateur, rien de plus simple :
// src/routes/users.js
export default (app, opts, done) => {
// Création de la route d'authentification
app.get('/categories', async (request, reply) => {
// Calide le token envoyé de le header Authorization
await request.jwtVerify()
})
done()
}
NodeJS & MongoDB
Vérifie que le token est présent ainsi que valide dans le header "Authorization". Si ce n'est pas le cas, le code est intérompus et une erreur http 403 est envoyé !
// src/routes/users.js
export default (app, opts, done) => {
// Création de la route d'authentification
app.get('/categories', async (request, reply) => {
// Calide le token envoyé de le header Authorization
await request.jwtVerify()
})
done()
}
NodeJS & MongoDB
CORS
NodeJS & MongoDB
Les cors est une sécurité mise en place par les navigateurs et application mobiles afin de restreindre les requêtes au domaine en cours
Par éxemple depuis le site "nodejs.org" il est impossible de faire une requête sur le site "google.fr" sans mettre en place des en-têtes HTTP CORS
NodeJS & MongoDB
Il est extrémement simple de rajouter les en-têtes HTTP CORS en fastify
Il suffit d'installer et d'utiliser le plugin fastify-cors
$ npm install fastify-corsNodeJS & MongoDB
Nous enregistrons le plugin CORS
// src/index.js
import fastify from 'fastify'
import fastifyCors from 'fastify-cors'
async function start() {
const app = fastify({ logger: true })
app.register(fastifyCors, {
origin: true
})
}NodeJS & MongoDB
Le plugin CORS acceptent des options de configuration
// src/index.js
import fastify from 'fastify'
import fastifyCors from 'fastify-cors'
async function start() {
const app = fastify({ logger: true })
app.register(fastifyCors, {
origin: true
})
}NodeJS & MongoDB
By David Jegat
NodeJS & MongoDB
- 455