Last active
June 29, 2024 15:42
-
-
Save felinto-dev/0450a3484ddd8aefefc79f42797eeadf to your computer and use it in GitHub Desktop.
After a lot of headaches with plugins that propose to be a wrapper between nestjs and aws-sdk, I decided to configure the dependency injection by myself and the result was not bad. You can use this code as the basis for any cloud storage S3-compatible. I am using @nestjs/config to manage the settings of environment variables. For additional inst…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { S3 } from 'aws-sdk'; | |
import { Module } from '@nestjs/common'; | |
import { ConfigModule, ConfigService } from '@nestjs/config'; | |
import { scalewayConfig } from '@/app/config/scaleway.config'; | |
import { StorageService } from './services/storage.service'; | |
@Module({ | |
imports: [ConfigModule.forFeature(scalewayConfig)], | |
providers: [ | |
StorageService, | |
{ | |
provide: 'S3', | |
useFactory: async (configService: ConfigService) => | |
new S3({ | |
credentials: { | |
accessKeyId: configService.get('scaleway.ACCESS_KEY_ID'), | |
secretAccessKey: configService.get('scaleway.SECRET_ACCESS_KEY'), | |
}, | |
region: configService.get('scaleway.REGION'), | |
endpoint: configService.get('scaleway.ENDPOINT'), | |
signatureVersion: 'v4', | |
}), | |
inject: [ConfigService], | |
}, | |
], | |
exports: [StorageService], | |
}) | |
export class StorageModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as fs from 'fs'; | |
import * as mockFs from 'mock-fs'; | |
import * as faker from 'faker'; | |
import { Console } from 'console'; | |
import { ConfigModule } from '@nestjs/config'; | |
import { Test, TestingModule } from '@nestjs/testing'; | |
import { s3CloudStorageConfig } from '@/app/config/s3-cloud-storage.config'; | |
import { StorageService } from '../../services/storage.service'; | |
describe('StorageService', () => { | |
let service: StorageService; | |
beforeEach(async () => { | |
// REF: WORKAROUND to be able to use console to show files in the directory (https://github.com/tschaub/mock-fs/issues/234) | |
global.console = new Console(process.stdout, process.stderr); | |
mockFs(); | |
const module: TestingModule = await Test.createTestingModule({ | |
imports: [ConfigModule.forFeature(s3CloudStorageConfig)], | |
providers: [ | |
StorageService, | |
{ | |
provide: 'S3', | |
useValue: { | |
upload: jest.fn(() => ({ | |
promise: jest.fn(() => | |
Promise.resolve({ | |
ETag: faker.random.uuid(), | |
Location: faker.internet.url(), | |
Key: faker.system.fileName(), | |
Bucket: 'bucket-id', | |
}), | |
), | |
})), | |
}, | |
}, | |
], | |
}).compile(); | |
service = module.get<StorageService>(StorageService); | |
}); | |
afterAll(() => { | |
mockFs.restore(); | |
}); | |
it('should be defined', () => { | |
expect(service).toBeDefined(); | |
}); | |
describe('uploadFile()', () => { | |
it('should upload a valid file', async () => { | |
mockFs({ | |
'file.txt': 'dummy content', | |
}); | |
const mockedFile = fs.readFileSync('file.txt'); | |
await service.uploadFile({ | |
dataBuffer: mockedFile, | |
filename: 'file.txt', | |
contentType: 'text/plain', | |
isPrivate: true, | |
}); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Inject, Injectable } from '@nestjs/common'; | |
import { ConfigType } from '@nestjs/config'; | |
import { S3 } from 'aws-sdk'; | |
import { scalewayConfig } from '@/app/config/scaleway.config'; | |
import { FileMetadataAwsObject } from '../interface/file-metadata-aws-object'; | |
@Injectable() | |
export class StorageService { | |
constructor( | |
@Inject(scalewayConfig.KEY) | |
private readonly scaleway: ConfigType<typeof scalewayConfig>, | |
@Inject('S3') | |
private readonly s3: S3, | |
) {} | |
async uploadFile(file: FileMetadataAwsObject) { | |
const fileSaved: S3.ManagedUpload.SendData = await this.s3 | |
.upload({ | |
Bucket: this.scaleway.BUCKET, | |
Body: file.dataBuffer, | |
Key: file.filename, | |
ACL: 'public-read', | |
ContentType: file.contentType, | |
}) | |
.promise(); | |
return fileSaved; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Some interesting S3-compatible cloud storage solutions:
Static files (images, downloads):
For static files and that there is not a lot of cache concern, I suggest you take a look at the "Cloudflare" (check the links below). It can represent considerable savings, as well as greater performance:
https://www.cloudflare.com/bandwidth-alliance/
https://support.cloudflare.com/hc/en-us/articles/360023040812-Best-Practice-Caching-Everything-While-Ignoring-Query-Strings
https://support.cloudflare.com/hc/pt-br/articles/218411427-Understanding-and-Configuring-Cloudflare-Page-Rules-Page-Rules-Tutorial-