How to setup MinIO in a NestJS API to handle file uploads
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.
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