Uploading Images to your Node/MongoDB Backend
Published: 2021-02-22 02:38:18

Today I will be breaking down how to upload an image to your node backend. This will be uploading the image file to the actual back end keep in mind so if you're looking to uploading to the database this isn't the article. I won't be showing anything about creating a front end form or anything but I will be testing my routes with POSTMAN.

Something else to note is I will assume you have basic knowledge of express and routes in your backend. If you don't I have a prior post that might be helpful *nudge nudge*.

Let's get started. 

So first things first you will need to install **multer** which is a package that will help with file handling. 

```
npm i multer
```

Good. Now that that's done lets go ahead and create an 'uploads' folder in your root directory for storing these images.

```
mkdir uploads
```

Following that lets set up some middleware so that we can access our uploads folder in a request. This is set up in my server file app.js

```
app.use('/uploads', express.static('uploads'));
```

Awesome now that that's all good to go let's head to whichever route you are trying to set up image upload with.

In there you will bring in that multer mentioned earlier...

``` JavaScript
const multer = require('multer');
``` 
 
...and then we will configure it.

First off lets set up its storage. 

``` JavaScript
const storage = multer.diskStorage({
    destination: function(req, file, callback){
        callback(null, './uploads/');
    },
    filename: function(req, file, callback){
        callback(null, Date.now() + '-' + file.originalname)
    },
});
```

Woah woah woah what's going on in there? 

1. A storage variable is created and assigned to multer.diskStorage()

2. A couple options are set up inside of their in the form of an object. 

3. The first being the destination which takes a  function with the request, the file, and the callback.

4. The callback takes in two parameters the first being for error handling which I won't be working with and the destination you'd like the image file to be stored. In our case the uploads folder we set up earlier.

5. The second option is the filename which also takes a function with the same parameters. You can set that up how you like but I set it up so It prepends my original files name with the Date.


Sweet. Our storage options are created.

Following that we will be setting up our upload middleware which invokes multer. We will also be configuring that with an object.

```JavaScript
const upload = multer({ 
    storage: storage, 
    limits: {
        fileSize: 1024 * 1024 * 5
    },
    fileFilter(req, file, callback){
        
        if(!file.originalname.endsWith(".png" || ".jpg" || ".jpeg")){
            callback(new Error("Must be an image file", false))
        } else {
            callback(null, true);
        }
    },
});

```

1. I assign our invoked multer to the upload constant.

2. I assign its storage option to that storage constant we just configured.

3. A second option it takes limits. I assigned it so that it can only take a fileSize up to 5MB.

4. A third option is the fileFilter which will determine that the file is actually an image. I did the check by checking if the file name ends with any of the image tags. If not it throws an error and doesn't save if it does it saves the file.

We're mostly there.

In your Schema make sure and include the image and in this case we will be accessing the path so it will be type: String.

``` JavaScript
const NovelSchema = mongoose.Schema({
    title: {
        type: String,
        required: true
    },
    author: {
        type: String,
        required: true
    },
    book_cover: { 
        type: String,
    }
}, { timestamps: true });
```

Now that we have it all set configured you just pass it into your post request as middleware.

``` JavaScript
//Post a new novel
router.post('/', upload.single('image') ,async (req, res) => {
    try {
        const novel = new Novel({
            title: req.body.title,
            author: req.body.author,
            image: req.file.path,
        });

        const savedNovel =  await novel.save();
        res.json(savedNovel);
    } catch(e) {
        res.json({ message: e})
    }
});
```

1. I passed our upload(multer) in as middleware to handle the file. I used the single option and passed in the argument for image. 

2. The rest is a standard post response but notice how in our image instead of accessing our requests body we access the file.

3. I assigned it the path in our backend to access that image.


Now what is stored in our backend is the image in our uploads folder and what is stored in MongoDB is a String with the path to that image. It should look something like:

"uploads/1613958234056-Dark_Disciple_Cover.png"

Since we setup middleware to access our uploads folder as a route earlier you can use that as your URL param and viola your image should appear. 

### Wrap Up

Now you should be able to successfully save an image to your backend and store its path in your database. If you'd like to know how to store the actual image to the database.. well me too. I'm working on that currently and will be making a future blog post once I get it figured out myself. If you have any questions or comments feel free to reach out. As always happy coding!