nest-file-repository v0.1.3
nest-file-repository
This library provides a flexible file repository for storing files.
Features
- Provides a flexible file repository
- Support Disk, Memory, AWS S3, GCS(google cloud storage) file repository
- Use
savefor save file,getfor get file,getUrlfor download public file,getSingedUrlForReadfor download private file,getSignedUrlForUploadfor download private file method
Installation
npm install nest-file-repositoryyarn add nest-file-repositoryIf you want to use S3FileRepository, you have to install @aws-sdk/client-s3, @aws-sdk/s3-request-presigner.
npm install nest-file-repository @aws-sdk/client-s3 @aws-sdk/s3-request-presigneryarn add nest-file-repository @aws-sdk/client-s3 @aws-sdk/s3-request-presignerIf you want to use GCSFileRepository, you have to install @google-cloud/storage
npm install nest-file-repository @google-cloud/storageyarn add nest-file-repository @google-cloud/storageBasic Usage
First, the module we created must be imported into your module
import { Module } from '@nestjs/common';
import { FileRepositoryModule, UploadStrategy } from 'nest-file-repository';
import { YourService } from './your.service'
@Module({
imports: [
FileRepositoryModule.register({
strategy: UploadStrategy.MEMORY,
}),
],
providers: [YourService]
})
export class YourModule {}Then, Make the file repository available to inject into your service what you want.
Appropriate file repository will be injected via the config you passed when configuring the module.
import { Injectable } from '@nestjs/common';
import { FileRepository, File } from 'nest-file-repository';
import { getBindingIdentifiers } from "@babel/types";
@Injectable()
export class YourService {
constructor(private readonly fileRepository: FileRepository) {
}
async save(filePath: string, fileData: Buffer): Promise<string> {
const path = await this.fileRepository.save(new File(filePath, fileData))
return path;
}
async get(key: string): Promise<File> {
const file = await this.fileRepository.get(key);
if (!file) {
throw new Error("file not found");
}
return file;
}
async getUrl(key: string): Promise<string> {
return this.fileRepository.getUrl(key);
}
async getSignedUrlForRead(key: string): Promise<string> {
return this.fileRepository.getSingedUrlForRead(key)
}
async getSignedUrlForUpload(key: string): Promise<string> {
return this.fileRepository.getSingedUrlForUpload(key)
}
}If you want to use more than one file repository, you can specify it like this:
First, when importing our module into your module, you must set the name
import { Module } from '@nestjs/common';
import { YourService } from './your.service';
import { FileRepositoryModule, UploadStrategy } from 'nest-file-repository';
@Module({
imports: [
FileRepositoryModule.register({
name: 'sample1',
strategy: UploadStrategy.MEMORY,
}),
FileRepositoryModule.register({
name: 'sample2',
strategy: UploadStrategy.DISK,
options: {
path: './sample2',
},
}),
],
providers: [YourService],
})
export class YourModule {}Then, you need to @Inject the FileRepository into your service.
You must set which file repository it is through Inject.
import { Inject, Injectable } from '@nestjs/common';
import { TestProjectService } from './test-project.service';
import { File, FileRepository } from 'nest-file-repository';
@Injectable()
export class YourService {
constructor(
@Inject('sample1') private readonly fileRepository1: FileRepository,
@Inject('sample2') private readonly fileRepository2: FileRepository,
) {}
async save1(): Promise<string> {
return await this.fileRepository1.save(
new File('test-file.txt', Buffer.from('hello')),
);
}
async save2(): Promise<string> {
return await this.fileRepository2.save(
new File('test-file.txt', Buffer.from('hello')),
);
}
}Customize
CustomProvider
You can customize some providers. For example, options.uploadOptionFactory in S3FileRepositoryConfiguration is type CustomProvider<S3UploadOptionFactory>.
Type CustomProvider<T> can be customized in four ways: Type<T>, CustomClassProvider<T>, CustomValueProvider<T>, CustomFactoryProvider<T>. It is similar to Provider of NestJS.
Type\
If you set implementation of generic type parameter in CustomProvider, then it is replaced by instance of your customized class.
import { Injectable } from '@nestjs/common';
import { S3UploadOptionFactory } from 'nest-file-repository';
@Injectable()
class CustomS3UploadOptionFactory implements S3UploadOptionFactory {
getOptions(
file: File,
config: S3FileRepositoryConfiguration,
): S3UploadOption {
return {
bucket: config.options.bucket,
key: file.filename,
body: file.data,
};
}
}import { Module } from '@nestjs/common';
import { YourService } from './your.service';
import { FileRepositoryModule, UploadStrategy } from 'nest-file-repository';
@Module({
imports: [
FileRepositoryModule.register({
strategy: UploadStrategy.S3,
options: {
region: 'your region',
bucket: 'your bucket',
acl: 'public-read', // acl of your bucket
credentials: {
accessKeyId: 'your access key id',
secretAccessKey: 'your secret access key',
},
uploadOptionFactory: CustomS3UploadOptionFactory,
},
})
],
providers: [YourService],
})
export class YourModule {}CustomClassProvider\
It works almost the same as the Type<T>.
import { Module } from '@nestjs/common';
import { YourService } from './your.service';
import { FileRepositoryModule, UploadStrategy } from 'nest-file-repository';
@Module({
imports: [
FileRepositoryModule.register({
strategy: UploadStrategy.S3,
options: {
region: 'your region',
bucket: 'your bucket',
acl: 'public-read', // acl of your bucket
credentials: {
accessKeyId: 'your access key id',
secretAccessKey: 'your secret access key',
},
uploadOptionFactory: { useClass: CustomS3UploadOptionFactory }
},
})
],
providers: [YourService],
})
export class YourModule {}CustomValueProvider\
If you set instance of generic type parameter in CustomProvider, then it is replaced by the value.
import { Module } from '@nestjs/common';
import { YourService } from './your.service';
import { FileRepositoryModule, UploadStrategy } from 'nest-file-repository';
@Module({
imports: [
FileRepositoryModule.register({
strategy: UploadStrategy.S3,
options: {
region: 'your region',
bucket: 'your bucket',
acl: 'public-read', // acl of your bucket
credentials: {
accessKeyId: 'your access key id',
secretAccessKey: 'your secret access key',
},
uploadOptionFactory: { useValue: new CustomS3UploadOptionFactory() }
},
})
],
providers: [YourService],
})
export class YourModule {}CustomFactoryProvider\
If you want to customize implementation requiring DI, can use CustomFactoryProvider.
@Injectable()
class CustomS3UploadOptionFactory implements S3UploadOptionFactory {
constructor(private readonly nameGenerator: NameGenerator) {}
getOptions(
file: File,
config: S3FileRepositoryConfiguration,
): S3UploadOption {
return {
bucket: config.options.bucket,
key: this.nameGenerator.generate(file),
body: file.data,
};
}
}Prepare a module with provider to be injected. If the global module contains the value you want to inject, it is not necessary.
@Module({
providers: [IdentityNameGenerator],
exports: [IdentityNameGenerator],
})
class NameGeneratorModule {
}Import prepared modules, inject provider you want and set factory function. Then it is replaced by return value of factory function.
@Module({
imports: [
FileRepositoryModule.register({
strategy: UploadStrategy.S3,
options: {
region: 'your region',
bucket: 'your bucket',
acl: 'public-read', // acl of your bucket
credentials: {
accessKeyId: 'your access key id',
secretAccessKey: 'your secret access key',
},
uploadOptionFactory: {
import: [NameGeneratorModule],
useFactory: (nameGenerator: NameGenerator) => new CustomS3UploadOptionFactory(nameGenerator),
inject: [IdentityNameGenerator]
}
},
})
],
providers: [YourService],
})
export class YourModule {
}options
common options
strategy(required): Select upload strategy of FileRepository. ExistMEMORY,DISK,S3strategy.name: Set name of your FileRepository. It is required if you want to use two or more file repositories.options.timeout: Set timeout. The number of milliseconds a request can take before automatically being terminated. 0 disables the timeout.options.path: Set save path.
S3 options
region(required): Set the region where your bucket is located.credentials.accessKeyId(required): Set an access key id with access to AWS s3.credentials.secretAccessKey(required): Set a secret access key with access to AWS s3.bucket(required): Set your bucket.acl: Set available acl on your bucket.endPoint: Set AWS endpoint.forcePathStyle: Whether to force path style URLs for S3 objects (e.g.,https://s3.amazonaws.com/<bucketName>/<key>instead ofhttps://<bucketName>.s3.amazonaws.com/<key>.uploadOptionFactory: Set the implementation of theS3UploadOptionFactory. By default, theDefaultS3UploadOptionFactoryis used.
GCS options
bucket(required): Set your bucket.acl: Set available acl on your bucket.apiEndPoint: Set your api endpoint.projectId: Set your project id. If not provided, the library will attempt to automatically detect the project ID based on the environment.keyFile: Set your keyfile path.uploadOptionFactory: Set the implementation of theGCSUploadOptionFactory. By default, theDefaultGCSUploadOptionFactoryis used.
Exception
TimeoutException: Times outNoSuchBucketException: Does not exist s3 or gcs bucket.InvalidAccessKeyIdException: Invalid access key id of s3NotAllowedAclException: Not allowed acl of s3 bucketSignatureDoesNotMatchedException: Not matched access key id and secret access key of s3
License
This library is licensed under the MIT license.