Build a REST API with Node.js: Upload an Image File
Tags: node, restapi, mongodb, javascript
Published: 2020-12-29 06:11:12

---
title: Build a REST API with Node.js: Upload an Image File
published: true
date: 2020-08-07 01:59:57 UTC
tags: Nodejs,RESTAPI,MongoDB,JavaScript
canonical_url: https://lo-victoria.com/build-rest-api-with-nodejs-upload-files-mongodb
---

Hello everyone! Welcome back to the 5th part of [Let's Build a Node.js REST API Series](https://hashnode.com/series/lets-build-a-nodejs-rest-api-ckcov1aob00dcfms19o5g2x42). We are so close to finishing this API. Let's not waste any more time and begin!

If you are new to this series, please check out the previous articles to follow along:
1. [Designing and Planning the API](https://lo-victoria.com/build-a-nodejs-api-for-beginners-1-designing-and-planning-your-api-ckdcat2o903cj66s1g7tu0cds)
2. [Routes and Controllers](https://lo-victoria.com/build-a-nodejs-api-for-beginners-2-routes-and-controllers-ckder50v20005xxs13rfsg1r8)
3. [Integrating MongoDB Atlas](https://lo-victoria.com/build-a-nodejs-api-for-beginners-3-integrating-mongodb-atlas-ckdgk9irb00ikdns16xr5b5et)
4. [Finalizing Controllers](https://lo-victoria.com/build-a-nodejs-api-for-beginners-4-finalizing-controllers-ckdi6itoe0097wgs1hr4530c6)

In the previous article, we finally have all our controller functions done and working. Our API can GET, POST and DELETE our tea objects that consists of:

| Properties | Description | Type  |
|:----------- |:---------------|:--------|
|name| the tea name | String| 
|image| an image url | String |
|description| the description | String | 
|keywords|words associated with the tea  |String | 
|origin|country where the tea is first made | String| 
|brew_time|time to brew in minutes | Number | 
|temperature|best temperature in Celsius to drink | Number | 
|comments|any comments posted about the tea |Array of String | 

However, in the previous article, I set the image property to just "dummy". In this article, we shall work on setting up this correctly.

## Step 1: Install multer and import

For images, we don't just supply a text string like "name" but a file, **an image file** to be exact. And our image property is a String that will be the path of our uploaded image file. 

Simply typing "/myImage.png" in our req.body.image will not work because that path does not exist. We need to upload our image with [multer](https://www.npmjs.com/package/multer), a node.js middleware useful for uploading files.

Install multer by running:
```
npm install --save multer
```
Then let's import multer to our **controllers/tea.js** file:
```
const multer = require('multer');
```
## Step 2: Create Storage
Still in our controllers/tea.js file, we add the following code to create a **storage** where our uploaded images will be stored. 

We use `multer.diskStorage()` and include its 2 properties:
- **destination**: the path where the images will be stored. We shall set it as './uploads'.
- **filename**: determines the name that would be saved in storage. We can just keep it as its original name.

Here's what it should look like:
```
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, './uploads');
      },
    filename: function (req, file, cb) {
        cb(null, file.originalname);
    }
});
```
Remember to create an **'uploads**' folder in your root directory so it actually exists for the image to be stored there.

## Step 3: Upload Image function
Below our `const storage`, we can initialize multer with `multer()` and pass `storage` in its **storage** property. Next, we have a `.single()` method which ensures that multer will accept only one file and store it as `req.file`.

The code will be:
```
const uploadImg = multer({storage: storage}).single('image');
```
In our **newTea** function, we have to change our image property to `req.file.path` instead of `req.body.image` because we want image to be our image file's path, not a string from req.body.image.
```
const newTea = new Tea({
     name:req.body.name,
     image: req.file.path,  //update this
     description: req.body.description,
     keywords: req.body.keywords,
     origin: req.body.origin,
     brew_time: req.body.brew_time,
     temperature: req.body.temperature,
})
```

Now we just have to export `uploadImg` to use in our **routes/tea.js** and include it as middleware. So include this function in our `module.exports` at the bottom, along with the rest.
```
module.exports = {
    getAllTea,
    uploadImg,  //include the new guy
    newTea,
    deleteAllTea,
    getOneTea,
    newComment,
    deleteOneTea
};
```
Now head over to our **routes/tea.js** file, find the POST /tea route and add `uploadImg` before newTea.
```
router.post('/tea', teaController.uploadImg /*insert this guy*/ , teaController.newTea);
```

## Let's test it!
Let's try to POST a new tea with POSTman. Make sure the method is set to POST and the url is correct. Supply some values for each property. For image, set it to 'file' instead of text then upload an image.

![set to file.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1595445263646/rpqol0Ym8.png)

POSTman should return our new tea object data with our image property saved as a path to our image.

![POST image to uploads.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1595445709537/TUZPBX5IB.png)

If we check in our **'uploads'** folder, the image that we uploaded should be there. That means it works! We can upload images to our tea object.

![picture in uploads.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1595445786457/hcxK3HmR0.png)

## What about GET?
It's pointless to be able to POST if you cannot GET the image right?

Let's try to get the image by entering `http://localhost:3000/uploads/green.png` as the url in POSTman and set the method to GET. You should see this error being returned:

![GET fail.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1595446631033/pylUa4kHc.png)

### Why is this so?
Our **'uploads'** folder cannot be accessed publicly and therefore the server cannot GET our image. To fix this, we have to make our uploads folder a static file.

Go to **server.js** and add this line of code:
```
app.use('/uploads', express.static('./uploads')); 
```
Now let's retry that test on POSTman and it should return the image correctly.

![GET tea.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1595446487500/mOwOJMMlE.png)

## Congratulations!
Our API is now fully working and built! All there's left to do is to add some security and deploy it for use! That will be in our next and final part of the series. Thank you for reading and following this series, I hope it has been helpful. Stay tuned for the final part. In the meantime, please ask questions or concerns in the comments and refer to the resources below. Cheers!

--------------------
### Further Reading
- [About multer](https://www.npmjs.com/package/multer)

> Notes: All images used in this API is from freepik.com