What is minio? Minio is *free, open-source, scalable S3 compatible object storage.
First of all, let's setup minio in docker container. I use bitnami's minio package. Add minio service to your docker-compose.yaml
:
services:
minio:
image: bitnami/minio:2024.11.7
restart: always
ports:
- ${MINIO_PORT}:${MINIO_PORT}
- ${MINIO_CONSOLE_PORT}:${MINIO_CONSOLE_PORT}
environment:
MINIO_ROOT_USER: ${MINIO_USER}
MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD}
MINIO_DEFAULT_BUCKETS: ${MINIO_BUCKET}
MINIO_API_PORT_NUMBER: ${MINIO_PORT}
MINIO_CONSOLE_PORT_NUMBER: ${MINIO_CONSOLE_PORT}
volumes:
- minio-data:/bitnami/minio/data
volumes:
minio-data:
driver: local
Let me explain this quickly:
ports
:MINIO_PORT
is minio's port for API requests, while as the name saysMINIO_CONSOLE_PORT
is minio's dashboard port:
MINIO_ROOT_USER
&MINIO_ROOT_PASSWORD
are for login credentials to login minio console dashboard.
For more information about env
variables of minio docker image, visit bitnami's minion docker image
Add these variables to your .env
file:
MINIO_PORT=9000
MINIO_CONSOLE_PORT=8000
MINIO_USER="admin"
MINIO_PASSWORD="veryhardpassword"
MINIO_BUCKET="main"
MINIO_ENDPOINT="localhost"
MINIO_ACCESS_KEY=""
MINIO_SECRET_KEY=""
To obtain access and secret keys:
Go to minio console (it's http://localhost:8000 in our example) & sign in.
Go Access Keys & Create access key
Copy & add access/secret keys to
.env
Setup minio client in nestjs
Install npm minio package
pnpm add minio
Create minio/minio.decorator.ts
& minio/minio.module.ts
import { Inject } from '@nestjs/common';
export const MINIO_TOKEN = 'MINIO_INJECT_TOKEN';
export function InjectMinio(): ParameterDecorator {
return Inject(MINIO_TOKEN);
}
import { Global, Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { MINIO_TOKEN } from './minio.decorator';
import * as Minio from 'minio';
@Global()
@Module({
exports: [MINIO_TOKEN],
providers: [
{
inject: [ConfigService],
provide: MINIO_TOKEN,
useFactory: async (
configService: ConfigService,
): Promise<Minio.Client> => {
const client = new Minio.Client({
endPoint: configService.getOrThrow("MINIO_ENDPOINT"),
port: +configService.getOrThrow("MINIO_PORT"),
accessKey: configService.getOrThrow("MINIO_ACCESS_KEY"),
secretKey: configService.getOrThrow("MINIO_SECRET_KEY"),
useSSL: false,
});
return client;
},
},
],
})
export class MinioModule {}
If you want to use minio in only one module (files module for example) you can remove @Global()
decorator.
Import it to app.module.ts
:
@Module({
imports: [
...
MinioModule,
],
})
export class AppModule {}
Now let's test it out. Inject minio to your server (files.service.ts
for example)
import { Injectable } from '@nestjs/common';
import { randomUUID } from 'crypto';
import * as Minio from 'minio';
import { InjectMinio } from 'src/minio/minio.decorator';
@Injectable()
export class FilesService {
protected _bucketName = 'main';
constructor(@InjectMinio() private readonly minioService: Minio.Client) {}
async bucketsList() {
return await this.minioService.listBuckets();
}
async getFile(filename: string) {
return await this.minioService.presignedUrl(
'GET',
this._bucketName,
filename,
);
}
uploadFile(file: Express.Multer.File) {
return new Promise((resolve, reject) => {
const filename = `${randomUUID().toString()}-${file.originalname}`;
this.minioService.putObject(
this._bucketName,
filename,
file.buffer,
file.size,
(error, objInfo) => {
if (error) {
reject(error);
} else {
resolve(objInfo);
}
},
);
});
}
}
and it's my files.controller.ts
import { Body, Controller, Get, Param, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FilesService } from './files.service';
import { FileInterceptor } from '@nestjs/platform-express';
@Controller('files')
export class FilesController {
constructor(readonly service: FilesService) {}
@Get('buckets')
bucketsList() {
return this.service.bucketsList();
}
@Get('file-url/:name')
getFile(@Param('name') name: string) {
return this.service.getFile(name);
}
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
uploadFile(
@UploadedFile('file') file: Express.Multer.File,
) {
payload.file = file;
return this.service.uploadFile(file);
}
}
Send a file to POST /files/upload
endpoint. It should return this response:
Let's visit minio console and go main bucket to check if file was uploaded
It's uploaded 🥳
Now let's test generating file URL for uploaded file (retrieve file) GET /files/file-url/<file_name>
. It should return URL to retrieve file something like this:
http://localhost:8000/main/2254a964-28dd-4c35-8494-5e767693cd26-iOS%2BSyllabus.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=m0iWmenUgJi2xBcFNNPF%2F20241129%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20241129T065735Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=a052b98dcfa95a4d1cdb1c9b0b91d1263440adf184aab5238e6d572c0f42e7c5
If you visit this URL you can retrieve that file.
You can find all minio methods with this link
*free - MinIO is free for self-hosted use under the GNU AGPLv3 license, which allows you to run and modify the software as long as any modifications you make are also made available under the same license. This license ensures freedom to use, study, share, and modify the software.
That's all. Thanks for reading I hope it's beneficial for you. If you find any mistake or issue in this post, feel free to comment or let me know.
Top comments (0)