Archives Wild Code School
Express.js

Express 09.1 - 📁 Upload de fichier (back)

QuĂȘte 8 sur 12

Comment apprĂ©hender la quĂȘte ?

Ensemble, nous allons créer un systÚme pour la réception d'image depuis un frontend. Comment ça va se passer ?

Je vais vous guider pour la bonne gestion de cette quĂȘte, mais en Ă©change, je souhaite que vous fassiez votre propre recherche, que ce soit Google ou collĂšgues, peu importe, tant que vous faites l'effort de chercher ! On va faire un tour sur des documentations, comprendre pourquoi on les utilise et Ă  la fin, avoir notre image qui s'upload :tada:

Alors, vous ĂȘtes prĂȘt ?!

Installation de Multer

Pour la suite de la quĂȘte, je me suis basĂ© sur ce repo que vous pouvez fork puis clone.

Commencez par lire les fichiers README (tous : dans le répertoire racine et dans les sous-dossiers frontend et backend), et recherchez la commande pour setup le projet.

hidden
Afficher la solution|||javascript|||Tu as des doutes sur comment faire ?|||0|||Masquer
npm install

Vous pouvez Ă©galement crĂ©er la base de donnĂ©es avec npm run migrate (aprĂšs avoir créé le fichier .env adĂ©quat), mais cela ne sera pas nĂ©cessaire pour cette quĂȘte.

Nous allons commencer par installer le package multer dans notre dossier backend, nous verrons aprĂšs pourquoi on utilise multer !

hidden
Afficher la solution|||bash|||On installe un package dans le dossier backend|||0|||Masquer
cd nom_de_votre_projet/backend
npm install multer

Nous pouvons voir que le package.json s'est mis Ă  jour avec multer !

Mise en place de Multer

Nous allons nous intéresser au fichier router.js de notre dossier src

js
// ./src/router.js
const express = require("express");

// Ajout de multer
const multer = require("multer");

// du code

Comment fonctionne multer ?

Si on se rĂ©fĂšre Ă  la documentation de multer, on peut voir que multer est un middleware qui va nous permettre de gĂ©rer les fichiers entrants dans nos requĂȘtes HTTP.

Pour ce faire, j'ai besoin d'un dossier de destination oĂč je vais stocker mes fichiers. Pour cela, je vais crĂ©er une constante upload et grĂące Ă  multer je vais dĂ©finir ma destination ./public/upload.

bash
# Création du dossier de destination
# Dans notre cas, nous allons le créer dans le dossier backend/public, n'oubliez pas de vous y rendre !

mkdir uploads
hidden
Afficher la solution|||javascript|||Tu as des doutes sur comment faire ?|||0|||Masquer
// ./src/router.js
const express = require("express");

// Ajout de multer
const multer = require("multer");

// On définit la destination de stockage de nos fichiers
const upload = multer({ dest: "./public/uploads/" });

// du code...

Mais pourquoi faire ça ? Dans le dossier public ?

Car dans app.js, nous avons ça

js
// Serve the public folder for public resources
app.use(express.static(path.join(__dirname, "../public")));

express.static ouvre le dossier à tout le monde, ça tombe bien, parce que nous avons nos futures images dedans, c'est top !

Du coup, coté front, on pourra accéder à nos images de cette maniÚre ${BACKEND_URL}/${nomDuFichier}, mais ça, c'est pour plus tard :wink:

Ma 1Êłá”‰ route

Nous allons créer notre premiÚre route POST qui va nous permettre de recevoir un fichier.

N'hésitez pas à suivre la documentation :wink:

hidden
Afficher la solution|||javascript|||Tu as des doutes sur comment faire ?|||0|||Masquer
// ./src/router.js
const express = require("express");

// Ajout de multer
const multer = require("multer");

// On définit la destination de stockage de nos fichiers
const upload = multer({ dest: "./public/uploads/" });

// route POST pour recevoir un fichier dont le nom est "avatar"
router.post("/api/avatar", upload.single("avatar"), (req, res) => {
	res.send("File uploaded");
});

Je vous laisse tester maintenant !

bash
# Lancement du serveur
npm run dev-back

Si vous souhaitez utiliser postman, insomnia ou autre et que vous ne savez pas comment faire pour envoyer une image, je vous invite Ă  faire comme moi ! Une petite recherche Google :smile: Car il est possible qu'entre le temps oĂč j'ai Ă©crit cette quĂȘte et le moment oĂč vous lĂ  lisez, les applications aient changĂ©. MĂȘme si on met Ă  jour la quĂȘte rĂ©guliĂšrement, il y a toujours un risque que ça change.

hidden
Tiens, voilà la phrase que j'ai écrite|||text|||Tu n'as pas encore trouvé ? N'hésite pas à continuer tes recherches|||0|||Masquer
Recherche:
> How to upload a file with {postman/insomnia}:

Réponses :
- Postman: https://youtu.be/S7bwkys6D0E
- Insomnia: https://stackoverflow.com/questions/44365061/insomnia-upload-pic-and-post-data-at-same-time

Dans mon cas, j'ai utilisé insomnia et j'ai pu envoyer mon fichier avec succÚs !

J'ai bien reçu mon fichier dans mon dossier uploads, le problÚme, c'est que le nom de mon fichier ressemble à ça : 108b2ec2fbbb61f03740061a69ab7c36. Et vous ? :yum:

C'est normal, c'est le nom que nous a donné multer. Mais nous, on veut un nom plus parlant, non ?

Comment faire pour avoir un nom de fichier plus parlant ?

Pour cela, nous allons utiliser la fonction rename de fs (file system) de node.js, voir ici (attention, ne pas oublier de le `require` comme tous les autres packages que nous avons utilisés jusqu'à présent :muscle: ).

Ta mission, si tu l'acceptes, c'est de renommer le fichier avec le nom d'origine.

Comment faire ? N'oublie pas d'utiliser la documentation de multer pour t'aider :wink:

hidden
Afficher|||text|||1er indice|||0|||Masquer
Tu peux essayer de `console.log(req)`, et si tu veux aller plus loin, tu peux `console.log(req.file)` !
hidden
Afficher|||js|||2eme indice|||0|||Masquer
console.log(req.file)
// output âŹ‡ïž

{
  fieldname: 'avatar',
  originalname: 'mon_avatar.png',
  encoding: '7bit',
  mimetype: 'image/png',
  destination: 'uploads/',
  filename: '58a8cce161de344cf73babe3336eb762',
  path: 'uploads/58a8cce161de344cf73babe3336eb762',
  size: 731934
}

hidden
Afficher la solution|||javascript|||Attend, tu as vraiment tout essayé ?|||0|||Masquer
// ./src/router.js
const express = require("express");
const fs = require("fs");

// Ajout de multer
const multer = require("multer");

// On définit la destination de stockage de nos fichiers
const upload = multer({ dest: "./public/uploads/" });

// route POST pour recevoir un fichier
router.post("/api/avatar", upload.single("avatar"), (req, res) => {
	// On récupÚre le nom du fichier
	const { originalname } = req.file;

	// On récupÚre le nom du fichier
	const { filename } = req.file;

	// On utilise la fonction rename de fs pour renommer le fichier
	fs
		.rename(`./public/uploads/${filename}`, `./public/uploads/${originalname}`, (err) => {
			if (err) throw err;
			res.send("File uploaded");
		});
});

Alors, ça fonctionne ?

Si oui, bravo ! :tada:

Alors, nous allons faire un test supplémentaire ! Par exemple, nous allons envoyer un fichier avec un nom qui existe déjà dans notre dossier uploads et voir ce qui se passe.

hidden
Oui|||text|||Tu as essayé ?|||0|||Masquer
Ça ne va pas fonctionner, je le sais dĂ©jĂ  :wink:

Pourquoi ça ne fonctionne pas ? En faite, ça fonctionne, mais il Ă©crase l'ancienne image qui porte le mĂȘme nom !

Ce que nous devons faire, c'est ajouter un élément à notre nom de fichier pour qu'il soit unique.

Pour cela, nous allons utiliser la fonction uuid de uuid (oui, c'est un peu bizarre comme nom :smile:)

bash
# Installation de uuid
npm i uuid
hidden
Afficher la solution|||javascript|||Tu as des doutes sur comment faire ?|||0|||Masquer
// ./src/router.js
const express = require("express");
const fs = require("fs");

// Ajout de multer
const multer = require("multer");

// Ajout de uuid
const { v4: uuidv4 } = require("uuid");

// On définit la destination de stockage de nos fichiers
const upload = multer({ dest: "uploads/" });

// route POST pour recevoir un fichier
router.post("/api/avatar", upload.single("avatar"), (req, res) => {
	// On récupÚre le nom du fichier
	const { originalname } = req.file;

	// On récupÚre le nom du fichier
	const { filename } = req.file;

	// On utilise la fonction rename de fs pour renommer le fichier
	fs
		.rename(`./public/uploads/${filename}`, `./public/uploads/${uuidv4()}-${originalname}`, (err) => {
			if (err) throw err;
			res.send("File uploaded");
		});
});

Et maintenant ?

Si vous avez bien suivi, vous devriez avoir un fichier qui s'appelle public/uploads/4db44163-0810-441b-9d97-8fd0ac09e085-mon_avatar.png. Conseil : il est important de conserver le nom de l'image original. Cela laisse la possibilité d'optimiser le SEO par les administrateurs. Dans ce cas, les noms d'images doivent comporter des '-', pas d'espace ni '_'.

Et voilĂ  !

Ressources partagĂ©es sur cette quĂȘte