Pour que notre middleware de téléchargement de fichiers fonctionne sur nos routes, nous devrons les modifier, car le format d'une requête contenant un fichier du front-end est différent.
Modifiez la route POST
Tout d'abord, ajoutons notre middleware multer
à notre route POST dans notre routeur stuff
:
const express = require('express');
const router = express.Router();
const auth = require('../middleware/auth');
const multer = require('../middleware/multer-config');
const stuffCtrl = require('../controllers/stuff');
router.get('/', auth, stuffCtrl.getAllStuff);
router.post('/', auth, multer, stuffCtrl.createThing);
router.get('/:id', auth, stuffCtrl.getOneThing);
router.put('/:id', auth, stuffCtrl.modifyThing);
router.delete('/:id', auth, stuffCtrl.deleteThing);
module.exports = router;
Pour gérer correctement la nouvelle requête entrante, nous devons mettre à jour notre contrôleur :
exports.createThing = (req, res, next) => {
const thingObject = JSON.parse(req.body.thing);
delete thingObject._id;
const thing = new Thing({
...thingObject,
imageUrl: `${req.protocol}://${req.get('host')}/images/${req.file.filename}`
});
thing.save()
.then(() => res.status(201).json({ message: 'Objet enregistré !'}))
.catch(error => res.status(400).json({ error }));
};
Que fait le code ci-dessus ?
Pour ajouter un fichier à la requête, le front-end doit envoyer les données de la requête sous la forme form-data, et non sous forme de JSON. Le corps de la requête contient une chaîne
thing
, qui est simplement un objetThing
converti en chaîne. Nous devons donc l'analyser à l'aide deJSON.parse()
pour obtenir un objet utilisable.Nous devons également résoudre l'URL complète de notre image, car
req.file.filename
ne contient que le segmentfilename
. Nous utilisonsreq.protocol
pour obtenir le premier segment (dans notre cas'http'
). Nous ajoutons'://'
, puis utilisonsreq.get('host')
pour résoudre l'hôte du serveur (ici,'localhost:3000'
). Nous ajoutons finalement'/images/'
et le nom de fichier pour compléter notre URL.
En fait, nous effectuons une demande GET vers http://localhost:3000/images/<image-name>.jpg
. Cela semble simple, mais n'oubliez pas que notre application s'exécute sur localhost:3000
, et nous ne lui avons pas indiqué comment répondre aux requêtes transmises à cette route : elle renvoie donc une erreur 404. Pour remédier à cela, nous devons indiquer à notre app.js
comment traiter les requêtes vers la route /image
, en rendant notre dossier images
statique.
Il nous faudra une nouvelle importation dans app.js
pour accéder au path de notre serveur :
const path = require('path');
De plus, nous ajoutons le gestionnaire de routage suivant juste au-dessus de nos routes actuelles :
app.use('/images', express.static(path.join(__dirname, 'images')));
Cela indique à Express qu'il faut gérer la ressource images
de manière statique (un sous-répertoire de notre répertoire de base, __dirname
) à chaque fois qu'elle reçoit une requête vers la route /images
. Enregistrez et actualisez l'application dans le navigateur ; désormais, tout devrait fonctionner correctement. Et maintenant, occupons-nous de la route PUT !
Modifiez la route PUT
La modification de notre route PUT est sensiblement plus compliquée, car nous devons prendre en compte deux possibilités : l'utilisateur a mis à jour l'image, ou pas. Dans le premier cas, nous recevrons l'élément form-data et le fichier. Dans le second cas, nous recevrons uniquement les données JSON.
Tout d'abord, ajoutons multer
comme middleware à notre route PUT :
const express = require('express');
const router = express.Router();
const auth = require('../middleware/auth');
const multer = require('../middleware/multer-config');
const stuffCtrl = require('../controllers/stuff');
router.get('/', auth, stuffCtrl.getAllStuff);
router.post('/', auth, multer, stuffCtrl.createThing);
router.get('/:id', auth, stuffCtrl.getOneThing);
router.put('/:id', auth, multer, stuffCtrl.modifyThing);
router.delete('/:id', auth, stuffCtrl.deleteThing);
module.exports = router;
À présent, nous devons modifier notre fonction modifyThing()
pour voir si nous avons reçu ou non un nouveau fichier, et répondre en conséquence :
exports.modifyThing = (req, res, next) => {
const thingObject = req.file ?
{
...JSON.parse(req.body.thing),
imageUrl: `${req.protocol}://${req.get('host')}/images/${req.file.filename}`
} : { ...req.body };
Thing.updateOne({ _id: req.params.id }, { ...thingObject, _id: req.params.id })
.then(() => res.status(200).json({ message: 'Objet modifié !'}))
.catch(error => res.status(400).json({ error }));
};
Dans cette version modifiée de la fonction, on crée un objet thingObject
qui regarde si req.file
existe ou non. S'il existe, on traite la nouvelle image ; s'il n'existe pas, on traite simplement l'objet entrant. On crée ensuite une instance Thing
à partir de thingObject
, puis on effectue la modification.
Félicitations ! Notre application gère correctement les téléchargements de fichiers lorsque nous mettons de nouveaux articles en vente et lorsque nous modifions les articles existants.
En résumé
JSON.parse()
transforme un objet stringifié en Object JavaScript exploitable.Vous aurez besoin de
req.protocol
et dereq.get('host')
, connectés par'://'
et suivis dereq.file.filename
pour reconstruire l'URL complète du fichier enregistré.Configurez votre serveur pour renvoyer des fichiers statiques pour une route donnée avec
express.static()
etpath.join()
.
Dans le prochain chapitre, nous verrons comment développer la fonction delete du back-end !