Modify Routes to Take Files Into Account

For your middleware to work on your routes, you will need to modify them slightly, as a request containing a file from the front end will have a different format.

#Modify the POST Route

First, add your  multer  middleware to your POST route in your  stuff  router:

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;

You now need to update your controller to correctly handle the new incoming request:

exports.createThing = (req, res, next) => {
req.body.thing = JSON.parse(req.body.thing);
const url = req.protocol + '://' + req.get('host');
const thing = new Thing({
title: req.body.thing.title,
description: req.body.thing.description,
imageUrl: url + '/images/' + req.file.filename,
price: req.body.thing.price,
userId: req.body.thing.userId
});
thing.save().then(
() => {
res.status(201).json({
message: 'Post saved successfully!'
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};

So what are we doing here?

  • To add a file to the request, the front end needed to send the request data as form-data as opposed to JSON. The request body contains a  thing  string, which is simply a stringified  thing  object. Therefore, you need to parse it using  JSON.parse()  to get a usable object.

  • You need to resolve the full URL because your image req.file.filename  only contains the filename segment. Use  req.protocol  to get the first segment ( 'http' , in this case). Add the  '://' , and then use  req.get('host')  to resolve the server host ('localhost:3000' ). Finally, add  '/images/'  and the filename to complete your URL.

If you save the controller as is and try out the app (remember to use the part 4 section!), you will see that almost everything works. You only get a 404 error when trying to fetch the image, even though it looks like your URL is correct. So what's happening here?

Well, you are making a GET request to  http://localhost:3000/images/<image-name>.jpg  . It seems simple, but remember that the Express app is running on  localhost:3000  , and you haven't told it how to react to requests going to that endpoint, so it is returning a 404 error. Therefore, you need to tell your  app.js  how to handle those requests, serving up your static  images  folder. 

You will need a new import in  app.js :

const path = require('path');

Add the following route handler just above your current routes:

app.use('/images', express.static(path.join(__dirname, 'images')));

This tells Express to serve up the static resource  images  (a sub-directory of your base directory,  __dirname ) whenever it receives a request to the  /images  endpoint. Save and refresh the app in the browser: things should now be working properly! Now on to the PUT route!

#Modify the PUT Route

Modifying the PUT route is slightly more complicated, as you have to take into account both possibilities: the user has updated the image, or they have not. In the first case, you will receive form-data and file; in the second case, you will just receive JSON data.

First, add  multer  as middleware to your PUT route:

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;

Now modify your  modifyThing()  function to check if you have received a new file, and react accordingly:

exports.modifyThing = (req, res, next) => {
let thing = new Thing({ _id: req.params._id });
if (req.file) {
const url = req.protocol + '://' + req.get('host');
req.body.thing = JSON.parse(req.body.thing);
thing = {
_id: req.params.id,
title: req.body.thing.title,
description: req.body.thing.description,
imageUrl: url + '/images/' + req.file.filename,
price: req.body.thing.price,
userId: req.body.thing.userId
};
} else {
thing = {
_id: req.params.id,
title: req.body.title,
description: req.body.description,
imageUrl: req.body.imageUrl,
price: req.body.price,
userId: req.body.userId
};
}
Thing.updateOne({_id: req.params.id}, thing).then(
() => {
res.status(201).json({
message: 'Thing updated successfully!'
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};

In this modified version of the function:

  • First create a new instance of your  Thing  model with the received  _id  so as not to cause problems when trying to update that  Thing  in the database.

  • If you receive a new file with the request (via  multer  ), handle the form-data and generate the image URL.

  • If you do not receive a new file, capture the request body JSON.

  • Save the updated  Thing  to the database.

Congratulations! Your app now correctly handles file uploads both when putting new things up for sale, and when modifying existing ones.

#Let's Recap!

  • JSON.parse()  turns a stringified object into a usable JavaScript Object.

  • To reconstruct the full URL of a saved file, you'll need  req.protocol  and  req.get('host')  , joining them with  '://'  , followed by  req.file.filename  .

  • Tell your server to serve static files on a given route using  express.static()  and   path.join()  .

In the next chapter, you'll see how to expand the back end's delete function! 

Et si vous obteniez un diplôme OpenClassrooms ?
  • Formations jusqu’à 100 % financées
  • Date de début flexible
  • Projets professionnalisants
  • Mentorat individuel
Trouvez la formation et le financement faits pour vous