RESSOURCES
DÉVELOPPER VOTRE PREMIÈRE API REST AVEC NODE.JS.
👉 Les ressources de la formation « Node : Développez votre première API Rest avec Express et MySQL» se trouvent bien sur cette page. Vous trouverez, comme promis :
NOUVEAU : Votre Questionnaire 2021
Jusqu’au 1 février 2021, vous avez la possibilité de donner votre avis sur les formations Udemy que je propose.
Et récupérer 100 euros OFFERT sur ma formation la plus importante, qui sortira début Février 2021.

L’application de démonstration
Lien vers l’application de démonstration.
La correction du code
Lien vers la correction complète du code.
La favicon à télécharger
Les extraits de code
app.js
const express = require('express') const app = express() const port = 3000 app.get('/', (req, res) => res.send('Hello, Express!')) app.listen(port, () => console.log(`Notre application Node est démarrée sur : http://localhost:${port}`))
mock-pokemon.js
const pokemons = [ { id: 1, name: "Bulbizarre", hp: 25, cp: 5, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/001.png", types: ["Plante", "Poison"], created: new Date() }, { id: 2, name: "Salamèche", hp: 28, cp: 6, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/004.png", types: ["Feu"], created: new Date() }, { id: 3, name: "Carapuce", hp: 21, cp: 4, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/007.png", types: ["Eau"], created: new Date() }, { id: 4, name: "Aspicot", hp: 16, cp: 2, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/013.png", types: ["Insecte", "Poison"], created: new Date() }, { id: 5, name: "Roucool", hp: 30, cp: 7, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/016.png", types: ["Normal", "Vol"], created: new Date() }, { id: 6, name: "Rattata", hp: 18, cp: 6, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/019.png", types: ["Normal"], created: new Date() }, { id: 7, name: "Piafabec", hp: 14, cp: 5, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/021.png", types: ["Normal", "Vol"], created: new Date() }, { id: 8, name: "Abo", hp: 16, cp: 4, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/023.png", types: ["Poison"], created: new Date() }, { id: 9, name: "Pikachu", hp: 21, cp: 7, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/025.png", types: ["Electrik"], created: new Date() }, { id: 10, name: "Sabelette", hp: 19, cp: 3, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/027.png", types: ["Normal"], created: new Date() }, { id: 11, name: "Mélofée", hp: 25, cp: 5, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/035.png", types: ["Fée"], created: new Date() }, { id: 12, name: "Groupix", hp: 17, cp: 8, picture: "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/037.png", types: ["Feu"], created: new Date() } ]; module.exports = pokemons
helper.js
const success = (message, data) => { return { message: message, data: data } } exports.success
Les réponses JSON (Correction) : Retourner une liste de données au format JSON
const express = require('express') const { success } = require('./helper.js') let pokemons = require('./mock-pokemon') const app = express() const port = 3000 app.get('/', (req,res) => res.send('Hello again, Express !')) // On retourne la liste des pokémons au format JSON, avec un message : app.get('/api/pokemons', (req, res) => { const message = 'La liste des pokémons a bien été récupérée.' res.json(success(message, pokemons)) }) app.get('/api/pokemons/:id', (req, res) => { const id = parseInt(req.params.id) const pokemon = pokemons.find(pokemon => pokemon.id === id) const message = 'Un pokémon a bien été trouvé.' res.json(success(message, pokemon)) }) app.listen(port, () => console.log(`Notre application Node est démarrée sur : http://localhost:${port}`))
Une API Rest Complète : Ajouter un nouveau Pokémon
app.js
//... app.post('/api/pokemons', (req, res) => { const id = 123 const pokemonCreated = { ...req.body, ...{id: id, created: new Date()}} pokemons.push(pokemonCreated) const message = `Le pokémon ${pokemonCreated.name} a bien été crée.` res.json(success(message, pokemonCreated)) }) // ...
helper.js
exports.success = (message, data) => { return { message, data } } exports.getUniqueId = (pokemons) => { const pokemonsIds = pokemons.map(pokemon => pokemon.id) const maxId = pokemonsIds.reduce((a,b) => Math.max(a, b)) const uniqueId = maxId + 1 return uniqueId }
Une API Rest Complète : Effectuer une requête POST avec Insomnia
Le corps de la requête POST à copier-coller dans Insomnia pour ajouter le pokémon « Chenipan » sur votre API Rest.
{ "name": "Chenipan", "hp": 29, "cp":4, "picture": "https://assets.pokemon.com/assets/cms2/img/pokedex/detail/010.png", "types": ["Insecte", "Poison"] }
Une API Rest Complète : Modifier un Pokémon
app.js
// ... app.put('/api/pokemons/:id', (req, res) => { const id = parseInt(req.params.id); const pokemonUpdated = { ...req.body, id: id } pokemons = pokemons.map(pokemon => { return pokemon.id === id ? pokemonUpdated : pokemon }) const message = `Le pokémon ${pokemonUpdated.name} a bien été modifié.` res.json(success(message, pokemonUpdated)) }); // ...
Une API Rest Complète : Supprimer un Pokémon
app.js
// ... app.delete('/api/pokemons/:id', (req, res) => { const id = parseInt(req.params.id) const pokemonDeleted = pokemons.find(pokemon => pokemon.id === id) pokemons = pokemons.filter(pokemon => pokemon.id !== id) const message = `Le pokémon ${pokemonDeleted.name} a bien été supprimé.` res.json(success(message, pokemonDeleted)) }); // ...
L’API Rest et la Base de données : Créer un modèle Sequelize
src/models/pokemon.js
module.exports = (sequelize, DataTypes) => { return sequelize.define('Pokemon', { id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, name: { type: DataTypes.STRING, allowNull: false }, hp: { type: DataTypes.INTEGER, allowNull: false }, cp: { type: DataTypes.INTEGER, allowNull: false }, picture: { type: DataTypes.STRING, allowNull: false }, types: { type: DataTypes.STRING, allowNull: false } }, { timestamps: true, createdAt: 'created', updatedAt: false }) }
L’API Rest et la Base de données : Créer un modèle Sequelize
sequelize.js
const { Sequelize, DataTypes } = require('sequelize') const PokemonModel = require('../models/pokemon') const pokemons = require('./mock-pokemon') const sequelize = new Sequelize('pokedex', 'root', '', { host: 'localhost', dialect: 'mariadb', dialectOptions: { timezone: 'Etc/GMT-2', }, logging: false }) const Pokemon = PokemonModel(sequelize, DataTypes) const initDb = () => { return sequelize.sync({force: true}).then(_ => { pokemons.map(pokemon => { Pokemon.create({ name: pokemon.name, hp: pokemon.hp, cp: pokemon.cp, picture: pokemon.picture, types: pokemon.types.join() }).then(pokemon => console.log(pokemon.toJSON())) }) console.log('La base de donnée a bien été initialisée !') }) } module.exports = { initDb, Pokemon }
findAllPokemons.js
const { Pokemon } = require('../db/sequelize') module.exports = (app) => { app.get('/api/pokemons', (req, res) => { Pokemon.findAll() .then(pokemons => { const message = 'La liste des pokémons a bien été récupérée.' res.json({ message, data: pokemons }) }) }) }
findPokemonByPk.js
const { Pokemon } = require('../db/sequelize') module.exports = (app) => { app.get('/api/pokemons/:id', (req, res) => { Pokemon.findByPk(req.params.id) .then(pokemon => { const message = 'Un pokémon a bien été trouvé.' res.json({ message, data: pokemon }) }) }) }
createPokemon.js
const { Pokemon } = require('../db/sequelize') module.exports = (app) => { app.post('/api/pokemons', (req, res) => { Pokemon.create(req.body) .then(pokemon => { const message = `Le pokémon ${req.body.name} a bien été crée.` res.json({ message, data: pokemon }) }) }) }
updatePokemon.js
const { Pokemon } = require('../db/sequelize') module.exports = (app) => { app.put('/api/pokemons/:id', (req, res) => { const id = req.params.id Pokemon.update(req.body, { where: { id: id } }) .then(_ => { Pokemon.findByPk(id).then(pokemon => { const message = `Le pokémon ${pokemon.name} a bien été modifié.` res.json({message, data: pokemon }) }) }) }) }
deletePokemon.js
const { Pokemon } = require('../db/sequelize') module.exports = (app) => { app.delete('/api/pokemons/:id', (req, res) => { Pokemon.findByPk(req.params.id).then(pokemon => { const pokemonDeleted = pokemon; Pokemon.destroy({ where: { id: pokemon.id } }) .then(_ => { const message = `Le pokémon avec l'identifiant n°${pokemonDeleted.id} a bien été supprimé.` res.json({message, data: pokemonDeleted }) }) }) }) }
Authentification : Créer un modèle User avec Sequelize
models/user.js
module.exports = (sequelize, DataTypes) => { return sequelize.define('User', { id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, username: { type: DataTypes.STRING }, password: { type: DataTypes.STRING } }) }
routes/login.js
const { User } = require('../db/sequelize') const bcrypt = require('bcrypt') module.exports = (app) => { app.post('/api/login', (req, res) => { User.findOne({ where: { username: req.body.username } }).then(user => { bcrypt.compare(req.body.password, user.password).then(isPasswordValid => { if(isPasswordValid) { const message = `L'utilisateur a été connecté avec succès`; return res.json({ message, data: user }) } }) }) }) }
auth/auth.js
const jwt = require('jsonwebtoken') const privateKey = require('../auth/private_key') module.exports = (req, res, next) => { const authorizationHeader = req.headers.authorization if(!authorizationHeader) { const message = `Vous n'avez pas fourni de jeton d'authentification. Ajoutez-en un dans l'en-tête de la requête.` return res.status(401).json({ message }) } const token = authorizationHeader.split(' ')[1] const decodedToken = jwt.verify(token, privateKey, (error, decodedToken) => { if(error) { const message = `L'utilisateur n'est pas autorisé à accèder à cette ressource.` return res.status(401).json({ message, data: error }) } const userId = decodedToken.userId if (req.body.userId && req.body.userId !== userId) { const message = `L'identifiant de l'utilisateur est invalide.` res.status(401).json({ message }) } else { next() } }) }