5 Minutes Tutorial Series - NodeJS upload files to Minio
Tags: node, minio, javascript, api
Published: 2020-01-01 18:52:27

Hello everyone, I am starting a new series called "5 Minutes Tutorial Series". In this tutorial, I'll show how can you upload a file to a Node server and then upload it to Minio Object Storage. Since it is about Minio, I'm assuming that you know what it is, but if you don't click [here](https://min.io/) to learn more.

We'll be using [fastify](https://www.fastify.io/) as our server framework. If you're using express, you can find an awesome post by [thepolygotdeveloper](https://www.thepolyglotdeveloper.com/2017/03/upload-files-minio-object-storage-cloud-node-js-multer/) here. Let's begin!

```bash
# create new project
mkdir fastify-minio
cd fastify-minio

# initialize npm project
npm init -y

# install fastify, fastify-file-upload, minio
npm i fastify fastify-file-upload minio
```

Create a file named index.js then add following code.
```javascript
const fastify = require('fastify');
const app = fastify();
app.register(require('fastify-file-upload'));

app.post('/upload', function(req, res) {
	const files = req.raw.files;
    res.send(files);
});

app.listen(3000, err => {
	if (err) {
    	throw err;
    }
    console.log('App is listening on port 3000!');
});
```


Here we have a very basic fastify server. Next create a file named minioClient.js with the following code.

```javascript
const Minio = require('minio');

const minioClient = new Minio.Client({
    endPoint: 'play.minio.io',
    port: 9000,
    secure: true,
    accessKey: 'Q3AM3UQ867SPQQA43P2F',
    secretKey: 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG'
});

module.exports = minioClient;
```
We're using minio's playground but feel free to change the configuration as you wish. Next we'll modify our index.js code to:
```javascript
const fastify = require('fastify');
const app = fastify();
// ->CHANGED
const minioClient = require('./minioClient');
// CHANGED<-
app.register(require('fastify-file-upload'));

app.post('/upload', function(req, res) {
	const files = req.raw.files;
    // ->CHANGED
    minioClient.putObject("test", files.image.name, files.image.data, function(error, etag) {
        if(error) {
            return console.log(error);
        }
    	res.send(`https://play.minio.io:9000/test/${files.image.name}`);
    });
    // CHANGED<-
});

app.listen(3000, err => {
	if (err) {
    	throw err;
    }
    console.log('App is listening on port 3000!');
});
```

You can see what's changed by looking at //CHANGED code blocks. But I want you to focus on minioClient part. We put object to a bucket named "test" with filename and data buffer. By the way notice the files.image part, in this case the file's key is "image". And the file's url is MINIO_ENDPOINT:MINIO_PORT/BUCKET_NAME/FILE_NAME. Since minio uses a technique called "presigned url" the file won't be accessible from that url. But we can change it by changing bucket policy. Here's the policy I use:
```json
{ 
    "Version":"2012-10-17",
    "Statement":[
       {
          "Effect":"Allow",
          "Principal":{
             "AWS":[
                "*"
             ]
          },
          "Action":[
             "s3:GetBucketLocation",
             "s3:ListBucket"
          ],
          "Resource":[
             "arn:aws:s3:::bucket"
          ]
       },
       {
          "Effect":"Allow",
          "Principal":{
             "AWS":[
                "*"
             ]
          },
          "Action":[
             "s3:GetObject"
          ],
          "Resource":[
             "arn:aws:s3:::bucket/*"
          ]
       }
    ]
 }
```
When you apply this policy via "setBucketPolicy" method of client, the files in the bucket will be accessible publicly and the url will be available permanently. You can see the method's docs [here](https://docs.min.io/docs/javascript-client-api-reference.html#setBucketPolicy).

Last thing, it can be problematic to use files' original names. I suggest trying some package like [uuid](https://www.npmjs.com/package/uuid) to prevent it.

Okay it's been 5 minutes already, see you in another tutorial!