DEV Community

Cover image for 5 Minutes Tutorial Series - NodeJS upload files to Minio
Gökay Okyay
Gökay Okyay

Posted on

5 Minutes Tutorial Series - NodeJS upload files to Minio

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 to learn more.

We'll be using fastify as our server framework. If you're using express, you can find an awesome post by thepolygotdeveloper here. Let's begin!

# 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
Enter fullscreen mode Exit fullscreen mode

Create a file named index.js then add following code.

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!');
});
Enter fullscreen mode Exit fullscreen mode

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

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;
Enter fullscreen mode Exit fullscreen mode

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:

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!');
});
Enter fullscreen mode Exit fullscreen mode

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:

{ 
    "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/*"
          ]
       }
    ]
 }
Enter fullscreen mode Exit fullscreen mode

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.

Last thing, it can be problematic to use files' original names. I suggest trying some package like uuid to prevent it.

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

Top comments (4)

Collapse
 
dogancalli profile image
dogancalli

Hello i m a student in computer engineering, so i would like to ask so many things about this, but the most i want to know is : can we get all kind of files or only images ? and how could we get and send the files name and url into a database ?
Ps : im using a node+express+mysql API

Collapse
 
gokayokyay profile image
Gökay Okyay • Edited

Hello! The file url will be
MINIO_ENDPOINT:MINIO_PORT/BUCKET_NAME/FILE_NAME

Yes, you can save any file, not just images.

You can save the file’s url and the name to your db. However you need to be sure that file’s been uploaded successfully. In order to do that, save url and name of the file inside of the putObject method’s callback, after checking for the error ofc.

Collapse
 
dogancalli profile image
dogancalli • Edited

Hello it's me again :)
What am i doing wrong on my post method ?

app.post('/documents',(request, response) => {
    client.presignedPutObject('uploads', request.query.name, (err, url ,obj) => {
        dataAPI = {
                docName:$request.query.name,  
                docLink:"https://play.min.io:9000/uploads/"+request.query.name  
                }  
        response.send(dataAPI)
    })
});
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
gokayokyay profile image
Gökay Okyay

Hello!
It’s hard to tell just by looking at it but what’s with the dollar sign? Did you try to create a template literal? And it’ll be better gor you to check if any errors occurred.
Btw I didn’t use the presignedPutObject method on tutorial, have you read the docs? 😄