@zola_do/minio
v0.2.8
Published
MinIO object storage for NestJS
Maintainers
Readme
@zola_do/minio
MinIO object storage integration for NestJS applications.
Overview
@zola_do/minio provides:
- File Upload — Direct upload with Multer or buffer
- Presigned URLs — Secure upload/download links
- Bucket Management — Multiple predefined buckets
- Streaming — Efficient file streaming
Installation
# Install individually
npm install @zola_do/minio
# Or via meta package
npm install @zola_do/nestjs-sharedNote: If installation fails due to nestjs-minio-client postinstall script, use:
npm install @zola_do/minio --ignore-scriptsDependencies
npm install nestjs-minio-clientQuick Start
1. Configure Environment
# .env
MINIO_ENDPOINT=localhost
MINIO_PORT=9000
MINIO_USESSL=false
MINIO_ACCESSKEY=your-access-key
MINIO_SECRETKEY=your-secret-key
DURATION_OF_PRE_SIGNED_DOCUMENT=1202. Register Module
import { Module } from "@nestjs/common";
import { MinIoModule } from "@zola_do/minio";
@Module({
imports: [MinIoModule],
})
export class AppModule {}3. Use Service
import { Injectable } from "@nestjs/common";
import { MinIOService, BucketNameEnum } from "@zola_do/minio";
@Injectable()
export class FileService {
constructor(private readonly minioService: MinIOService) {}
async uploadFile(file: Express.Multer.File) {
return await this.minioService.upload(file, BucketNameEnum.MEGP);
}
}MinIO Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ MinIO Flow │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ │
│ │ Client │ │
│ └────┬─────┘ │
│ │ │
│ │ 1. Request presigned URL │
│ ├─────────────────────────────────────┐ │
│ │ │ │
│ │ ┌───────────────┐ │ │
│ │ │ Controller │ │ │
│ │ └───────┬───────┘ │ │
│ │ │ │ │
│ │ │ 2. Generate URL │ │
│ │ ▼ │ │
│ │ ┌───────────────┐ │ │
│ │ │ MinIOService │ │ │
│ │ └───────┬───────┘ │ │
│ │ │ │ │
│ │ │ 3. Client PUT │ │
│ │<─────────┼──────────────────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌───────────────┐ │ │
│ │ │ MinIO │◄─────────────────┘ │
│ │ │ Server │ Direct upload │
│ │ └───────────────┘ │
│ │ │
│ │ 4. File stored │
│ │ ┌───────────────┐ │
│ │ │ Bucket │ │
│ │ │ documents/ │ │
│ │ └───────────────┘ │
│ │ │
└───────┴─────────────────────────────────────────────────────────────┘Upload Operations
File Upload
async uploadFile(file: Express.Multer.File) {
const result = await this.minioService.upload(
file,
BucketNameEnum.MEGP,
);
// Returns: { filepath, bucketName, contentType, originalname }
}Buffer Upload
async uploadBuffer(
buffer: Buffer,
filename: string,
mimetype: string,
) {
const result = await this.minioService.uploadBuffer(
buffer,
filename,
mimetype,
BucketNameEnum.MEGP,
);
return result;
}Custom Bucket
async uploadToCustomBucket(file: Express.Multer.File, bucketName: string) {
// Ensure bucket exists
await this.minioService.ensureBucket(bucketName);
return await this.minioService.upload(file, bucketName);
}Download Operations
Download to Buffer
async downloadFile(filepath: string, bucketName: string): Promise<Buffer> {
const buffer = await this.minioService.downloadBuffer({
filepath,
bucketName,
});
return buffer;
}Download to Response
async downloadToResponse(
@Param('filepath') filepath: string,
@Res() res: Response,
) {
const buffer = await this.minioService.downloadBuffer({
filepath: `documents/${filepath}`,
bucketName: BucketNameEnum.MEGP,
});
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', `attachment; filename="${filepath}"`);
res.end(buffer);
}Presigned URLs
Generate Upload URL
async getUploadUrl(filename: string, contentType: string) {
const { presignedUrl, file } = await this.minioService.generatePresignedUploadUrl(
{ originalname: filename, contentType },
'documents/', // Folder prefix
);
return {
presignedUrl,
filepath: file.filepath,
bucketName: file.bucketName,
};
}Generate Download URL
async getDownloadUrl(filepath: string) {
const fileInfo = {
filepath,
bucketName: BucketNameEnum.MEGP,
contentType: 'application/pdf',
originalname: 'document.pdf',
};
const presignedUrl = await this.minioService.generatePresignedDownloadUrl(fileInfo);
return { downloadUrl: presignedUrl };
}Client-Side Upload Example
// Backend
@Post('upload-url')
async getUploadUrl() {
const { presignedUrl, file } = await this.minioService.generatePresignedUploadUrl(
{ originalname: 'report.pdf', contentType: 'application/pdf' },
'reports/',
);
return { presignedUrl, file };
}
// Frontend (React/Angular/Vue)
const response = await fetch('/api/upload-url');
const { presignedUrl, file } = await response.json();
await fetch(presignedUrl, {
method: 'PUT',
body: fileBuffer,
headers: { 'Content-Type': 'application/pdf' },
});BucketNameEnum
Predefined bucket names:
enum BucketNameEnum {
MEGP = "megp",
SPD_TEMPLATE = "spd_template",
// Add more buckets as needed
}Custom Buckets
// Define custom bucket names
const MY_BUCKETS = {
DOCUMENTS: "my-documents",
IMAGES: "my-images",
EXPORTS: "my-exports",
} as const;Ensure Bucket Exists
async ensureBucketExists(bucketName: string) {
await this.minioService.ensureBucket(bucketName);
}Environment Variables
| Variable | Description | Default |
| --------------------------------- | ------------------------------ | -------- |
| MINIO_ENDPOINT | MinIO server endpoint | Required |
| MINIO_PORT | MinIO port | 443 |
| MINIO_USESSL | Use SSL | true |
| MINIO_ACCESSKEY | MinIO access key | Required |
| MINIO_SECRETKEY | MinIO secret key | Required |
| DURATION_OF_PRE_SIGNED_DOCUMENT | Presigned URL expiry (seconds) | 120 |
PresignedFileUploadDto
Response type for presigned upload:
interface PresignedFileUploadDto {
presignedUrl: string;
file: {
filepath: string;
bucketName: string;
contentType: string;
originalname: string;
};
}API Reference
Module
MinIoModule.forRoot(options?: MinIoModuleOptions)
MinIoModule.forRootAsync(options?: MinIoModuleAsyncOptions)Service
class MinIOService {
async upload(
file: Express.Multer.File,
bucketName: string,
): Promise<{
filepath: string;
bucketName: string;
contentType: string;
originalname: string;
}>;
async uploadBuffer(
buffer: Buffer,
originalname: string,
mimetype: string,
bucketName: string,
): Promise<FileUploadResult>;
async downloadBuffer(fileInfo: FileInfo): Promise<Buffer>;
async generatePresignedUploadUrl(
file: Partial<FileInfo>,
folder?: string,
expiry?: number,
): Promise<PresignedFileUploadDto>;
async generatePresignedDownloadUrl(
fileInfo: FileInfo,
expiry?: number,
): Promise<string>;
async ensureBucket(bucketName: string): Promise<void>;
}Troubleshooting
Q: Connection refused error?
Verify MinIO is running:
docker run -p 9000:9000 minio/minio server /dataQ: Bucket not found?
Create the bucket in MinIO console or use ensureBucket():
await this.minioService.ensureBucket("my-bucket");Q: Presigned URL expired?
Increase DURATION_OF_PRE_SIGNED_DOCUMENT or pass custom expiry:
await this.minioService.generatePresignedUploadUrl(file, "folder", 3600);Q: File upload fails with CORS?
Configure MinIO CORS:
mc cors set minio/ALIAS <<EOF
{
"CORSRules": [{
"AllowedOrigins": ["*"],
"AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
"AllowedHeaders": ["*"]
}]
}
EOFRelated Packages
- @zola_do/document-manipulator — Uses MinIO for document storage
License
ISC
