Pourquoi Deployer Express sur DigitalOcean ?
Le déploiement d'une application Express sur DigitalOcean est une étape cruciale pour les développeurs qui souhaitent rendre leurs applications accessibles en ligne et scalables. En effet, DigitalOcean offre des ressources cloud robustes et de faible coût, ce qui permet aux développeurs de déployer facilement et efficacement leurs applications web.
Un cas d'usage concret est le développement d'une application e-commerce. Pour rendre cette application accessible à un public mondial, il est nécessaire de la déployer sur une plateforme cloud fiable comme DigitalOcean. De plus, avec les capacités de scalabilité offertes par DigitalOcean, l'application peut facilement gérer une grande charge de trafic en temps réel.
Prerequis
Pour suivre ce tutoriel, vous aurez besoin des éléments suivants :
- Un compte sur DigitalOcean
- Node.js et npm installés localement (version >= 14.x)
- MongoDB installé et configuré (pour le stockage de données)
Outils à installer :
doctl: L'outil de ligne de commande pour interagir avec DigitalOcean
Concepts fondamentaux
Création d'un nouveau projet
Pour commencer, nous allons créer un nouveau projet Express.
mkdir my-express-app
cd my-express-app
Créer un fichier package.json et installer les dépendances nécessaires :
npm init -y
npm install express mongoose body-parser cors dotenv
Structure du projet
Un projet Express typique peut avoir la structure suivante :
my-express-app/
├── app.js
├── config/
│ └── db.js
├── controllers/
│ └── taskController.js
├── models/
│ └── Task.js
├── routes/
│ └── tasks.js
├── .env
└── package.json
Middleware et hooks
Les middleware et les hooks sont des fonctions qui s'exécutent pendant la requête HTTP. Voici un exemple simple d'un middleware :
// app.js
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
app.use(bodyParser.json());
app.use(cors());
// Middleware pour afficher le temps de réponse
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
console.log(`${res.statusCode} ${req.method} ${req.url} - ${(Date.now() - start)}ms`);
});
next();
});
// Routes
const taskRoutes = require('./routes/tasks');
app.use('/api/tasks', taskRoutes);
module.exports = app;
Base de données MongoDB
Pour stocker les données, nous utiliserons MongoDB. Voici un exemple de modèle Mongoose :
// models/Task.js
const mongoose = require('mongoose');
const TaskSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
description: {
type: String
},
completed: {
type: Boolean,
default: false
}
});
module.exports = mongoose.model('Task', TaskSchema);
Configuration de la base de données
Créer un fichier config/db.js pour configurer MongoDB :
// config/db.js
const mongoose = require('mongoose');
require('dotenv').config();
const dbUri = process.env.MONGO_URI;
mongoose.connect(dbUri, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
}).then(() => console.log('MongoDB connected'))
.catch(err => console.error('MongoDB connection error:', err));
Controller pour les tâches
Voici un exemple de controller pour gérer les tâches :
// controllers/taskController.js
const Task = require('../models/Task');
exports.getTasks = async (req, res) => {
try {
const tasks = await Task.find();
res.json(tasks);
} catch (err) {
res.status(500).json({ message: err.message });
}
};
exports.createTask = async (req, res) => {
const task = new Task({
title: req.body.title,
description: req.body.description
});
try {
const newTask = await task.save();
res.status(201).json(newTask);
} catch (err) {
res.status(400).json({ message: err.message });
}
};
Routes pour les tâches
Voici un exemple de routes pour gérer les tâches :
// routes/tasks.js
const express = require('express');
const router = express.Router();
const taskController = require('../controllers/taskController');
router.get('/', taskController.getTasks);
router.post('/', taskController.createTask);
module.exports = router;
Configuration des variables d'environnement
Créer un fichier .env pour stocker les variables d'environnement :
MONGO_URI=mongodb://localhost:27017/mydatabase
PORT=3000
Mise en pratique : projet fil rouge
Étape 1 : Création du serveur Express
Créer un fichier app.js avec le contenu suivant :
// app.js
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
app.use(bodyParser.json());
app.use(cors());
// Middleware pour afficher le temps de réponse
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
console.log(`${res.statusCode} ${req.method} ${req.url} - ${(Date.now() - start)}ms`);
});
next();
});
// Routes
const taskRoutes = require('./routes/tasks');
app.use('/api/tasks', taskRoutes);
module.exports = app;
Étape 2 : Configuration de la base de données
Créer un fichier config/db.js avec le contenu suivant :
// config/db.js
const mongoose = require('mongoose');
require('dotenv').config();
const dbUri = process.env.MONGO_URI;
mongoose.connect(dbUri, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
}).then(() => console.log('MongoDB connected'))
.catch(err => console.error('MongoDB connection error:', err));
Étape 3 : Création du modèle Mongoose
Créer un fichier models/Task.js avec le contenu suivant :
// models/Task.js
const mongoose = require('mongoose');
const TaskSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
description: {
type: String
},
completed: {
type: Boolean,
default: false
}
});
module.exports = mongoose.model('Task', TaskSchema);
Étape 4 : Création du controller
Créer un fichier controllers/taskController.js avec le contenu suivant :
// controllers/taskController.js
const Task = require('../models/Task');
exports.getTasks = async (req, res) => {
try {
const tasks = await Task.find();
res.json(tasks);
} catch (err) {
res.status(500).json({ message: err.message });
}
};
exports.createTask = async (req, res) => {
const task = new Task({
title: req.body.title,
description: req.body.description
});
try {
const newTask = await task.save();
res.status(201).json(newTask);
} catch (err) {
res.status(400).json({ message: err.message });
}
};
Étape 5 : Création des routes
Créer un fichier routes/tasks.js avec le contenu suivant :
// routes/tasks.js
const express = require('express');
const router = express.Router();
const taskController = require('../controllers/taskController');
router.get('/', taskController.getTasks);
router.post('/', taskController.createTask);
module.exports = router;
Étape 6 : Configuration des variables d'environnement
Créer un fichier .env avec le contenu suivant :
MONGO_URI=mongodb://localhost:27017/mydatabase
PORT=3000
Erreurs frequentes et debugging
Erreur 1 : TypeError: Cannot read property 'length' of undefined
Ce type d'erreur peut survenir lorsque vous essayez de lire la longueur d'une propriété qui n'est pas définie.
Code incorrect :
const arr = undefined;
console.log(arr.length);
Code correct :
const arr = undefined;
if (arr && arr.length) {
console.log(arr.length);
} else {
console.log('Array is undefined');
}
Erreur 2 : MongoError: not authorized for query on mydatabase.tasks
Cette erreur indique que l'utilisateur MongoDB n'a pas les autorisations nécessaires.
Code incorrect :
mongoose.connect(dbUri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
Code correct :
mongoose.connect(dbUri, {
useNewUrlParser: true,
useUnifiedTopology: true,
user: process.env.MONGO_USER,
pass: process.env.MONGO_PASSWORD
});
Erreur 3 : SyntaxError: Unexpected token 'const'
Cette erreur peut survenir si vous utilisez des fonctionnalités ECMAScript modernes qui ne sont pas supportées par votre version de Node.js.
Code incorrect :
const { taskController } = require('../controllers/taskController');
Code correct :
const taskController = require('../controllers/taskController').taskController;
Pour aller plus loin
Piste 1 : Authentification sécurisée avec JWT
L'authentification JWT (JSON Web Tokens) offre une solution sécurisée pour l'autorisation des utilisateurs.
Piste 2 : Intégration de Redis pour la mise en cache
Redis est un système de stockage clé-valeur qui peut être utilisé comme base de données in-memory pour accélérer les requêtes.
Piste 3 : Déploiement sur Heroku
Heroku est une plateforme cloud populaire qui facilite le déploiement des applications web.
Défi pratique
Vous devez créer une API pour un blog. L'API devrait permettre aux utilisateurs de :
- Créer des articles
- Lire tous les articles
- Mettre à jour et supprimer des articles
Ensuite, déployez cette API sur DigitalOcean.