How to setup MinIO in a NestJS API to handle file uploads

ramu kramu k
4 min read

Table of contents

Introduction

MinIO is an open source object storage server that is compatible with Amazon S3 cloud storage service. Using it in your NestJS API will allow you to store your files in it.

Requirements

Installation

Create a NestJS API

First, we need to create a NestJS API. To do so, we will use the NestJS CLI.

nest new <project-name>

Install the dependencies

To use MinIO in our NestJS API, we will use the MinIO client.

npm i minio && npm i -D @types/minio

We will also need to install the type definitions for Multer, which is a middleware for handling multipart/form-data.

npm i -D @types/multer

Install MinIO

To install MinIO, we will use Docker Compose.

touch docker-compose.yml

Fill your docker-compose.yml file with the following content:

version: '3.8'

services:
  minio:
    image: docker.io/bitnami/minio:2022
    environment:
      MINIO_ROOT_USER: minio
      MINIO_ROOT_PASSWORD: supersecret
    ports:
      - '9000:9000'
      - '9001:9001'
    volumes:
      - 'minio_data:/data'

volumes:
  minio_data:
    driver: local

Then, type the following command to start MinIO:

docker-compose up -d

You are now able to access the MinIO dashboard at http://127.0.0.1:9001.
After the userName and password
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: supersecret
Then getting logged into like below :

Enter user name and password after login the page will be appear like this

Set up the NestJS Config module

To use MinIO in our NestJS API, we will use the NestJS Config module.

npm i @nestjs/config

Then, we will create a .env file in the root of our project.

touch .env

Fill your .env file with the following content, and make sure to replace the keys with your own :

MINIO_ENDPOINT='localhost'
MINIO_PORT=9000

MINIO_ACCESS_KEY=<my_access_key>
MINIO_SECRET_KEY=<my_secret_key>
MINIO_USE_SSL=false
MINIO_BUCKET_NAME=<my_bucket_name>
my .env

MINIO_ENDPOINT=127.0.0.1
MINIO_PORT=9000

MINIO_ACCESS_KEY=cmXXXXXXXX
MINIO_SECRET_KEY=kZhXXXXXX
MINIO_USE_SSL=false
MINIO_BUCKET_NAME=min-io-st

After doing that, we will import the ConfigModule in our app.module.ts file.

import { Module } from '@nestjs/common'

import { ConfigModule } from '@nestjs/config'

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true
    })
  ]
})
export class AppModule {}

Usage

Create a MinIO service

To use MinIO in our NestJS API, we will create a MinIO service.

nest g service minio

Fill your minio.service.ts file with the following content:

import { Injectable } from '@nestjs/common'
import * as Minio from 'minio'

@Injectable()
class MinioService {
  private minioClient: Minio.Client
  private bucketName: string

  constructor(private readonly configService: ConfigService) {
    this.minioClient = new Minio.Client({
      endPoint: this.configService.get('MINIO_ENDPOINT'),
      port: Number(this.configService.get('MINIO_PORT')),
      useSSL: this.configService.get('MINIO_USE_SSL') === 'true',
      accessKey: this.configService.get('MINIO_ACCESS_KEY'),
      secretKey: this.configService.get('MINIO_SECRET_KEY')
    })
    this.bucketName = this.configService.get('MINIO_BUCKET_NAME')
  }

  async createBucketIfNotExists() {
    const bucketExists = await this.minioClient.bucketExists(this.bucketName)
    if (!bucketExists) {
      await this.minioClient.makeBucket(this.bucketName, 'eu-west-1')
    }
  }

  async uploadFile(file: Express.Multer.File) {
    const fileName = `${Date.now()}-${file.originalname}`
    await this.minioClient.putObject(
      this.bucketName,
      fileName,
      file.buffer,
      file.size
    )
    return fileName
  }

  async getFileUrl(fileName: string) {
    return await this.minioClient.presignedUrl('GET', this.bucketName, fileName)
  }

  async deleteFile(fileName: string) {
    await this.minioClient.removeObject(this.bucketName, fileName)
  }
}

Feel free to extend this service to suit your needs.

Example

To use our MinIO service, we will fill our app.controller.ts file, in order to handle file uploads and downloads of book covers.

// app.controller.ts
import {
  Controller,
  Get,
  Post,
  Param,
  Delete,
  UploadedFile,
  UseInterceptors
} from '@nestjs/common'

@Controller()
class AppController {
  constructor(private readonly minioService: MinioService) {}

  @Post('covers')
  @UseInterceptors(FileInterceptor('file'))
  async uploadBookCover(@UploadedFile() file: Express.Multer.File) {
    await this.minioService.createBucketIfNotExists()
    const fileName = await this.minioService.uploadFile(file)
    return fileName
  }

  @Get('covers/:fileName')
  async getBookCover(@Param('fileName') fileName: string) {
    const fileUrl = await this.minioService.getFileUrl(fileName)
    return fileUrl
  }

  @Delete('covers/:fileName')
  async deleteBookCover(@Param('fileName') fileName: string) {
    await this.minioService.deleteFile(fileName)
    return fileName
  }
}

Then call the 'covers' post action
example in my case I used nestjs swagger

after called we can get response 200

then go check you min io . there place we can able to see the file we have been uploaded

Conclusion

You are now able to use MinIO in your NestJS API and store your files in it.

If you have any questions, feel free to reach me.

0
Subscribe to my newsletter

Read articles from ramu k directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

ramu k
ramu k

Fullstack developer