## Features
- Single file upload to an Amazon S3 bucket
- Support for dynamic paths, upload files wherever you want!
- Generate thumbnail image along with the original
- Resize single image or even make it into different sizes
- Load AWS S3 configuration at runtime
## Installation
**NPM**
```bash
$ npm i -s nestjs-multer-extended
```
**Yarn**
```bash
$ yarn add nestjs-multer-extended
```
## Getting started
Once the installation process is complete, we can import the module either synchronously or asynchronosly into the root `AppModule`.
### Synchronous configuration
```typescript
import { Module } from '@nestjs/common';
import { MulterExtendedModule } from 'nestjs-multer-extended';
@Module({
imports: [
MulterExtendedModule.register({
accessKeyId: 'YOUR_AWS_ACCESS_KEY_ID',
secretAccessKey: 'YOUR_AWS_SECRET_ACCESS_KEY',
region: 'AWS_REGION_NEAR_TO_YOU',
bucket: 'YOUR_S3_BUCKET_NAME',
basePath: 'ROOT_DIR_OF_ASSETS',
fileSize: 1 * 1024 * 1024,
}),
],
})
export class AppModule {}
```
### Asynchronous configuration
In this example, the module integrates with the awesome [nestjs-config](https://github.com/nestjsx/nestjs-config) package.
`useFactory` should return an object with [MulterExtendedS3Options interface](#MulterExtendedS3Options) or undefined.
```typescript
import { Module } from '@nestjs/common';
import { MulterExtendedModule } from 'nestjs-multer-extended';
import { ConfigService } from 'nestjs-config';
@Module({
imports: [
MulterExtendedModule.registerAsync({
useFactory: (config: ConfigService) => config.get('s3'),
inject: [ConfigService],
}),
],
})
export class AppModule {}
```
> **Note**: You can import this module from not only the root module of your app but also from other feature modules where you want to use it.
To upload a single file, simply tie the `AmazonS3FileInterceptor()` interceptor to the route handler and extract `file` from the request using the `@UploadedFile()` decorator.
```typescript
import { Controller, Post, UseInterceptors, UploadedFile } from '@nestjs/common';
import { AmazonS3FileInterceptor } from 'nestjs-multer-extended';
@Controller()
export class AppController {
@Post('upload')
@UseInterceptors(AmazonS3FileInterceptor('file'))
uploadFile(@UploadedFile() file) {
console.log(file);
}
}
```
In this example, `uploadFile()` method will upload a file under the base path you have configured earlrier.
The `AmazonS3FileInterceptor()` decorator takes two arguments:
- `fieldName`: string that supplies the name of the field from the HTML form that holds a file.
- `options`: optional object of type `MulterExtendedOptions`. (mode details [**here**](#MulterExtendedOptions))
What if you wanted to upload a file in a different location under the base path? Thankfully, `AmazonS3FileInterceptor()` decorator accepts `dynamicPath` property as a second argument option. Pass the string path as shown below:
```typescript
@Post('upload')
@UseInterceptors(
AmazonS3FileInterceptor('file', {
dynamicPath: 'aec16138-a75a-4961-b8c1-8e803b6bf2cf'
}),
)
uploadFile(@UploadedFile() file) {
console.log(file);
}
```
In this example, `uploadFile()` method will upload a file in `${basePath}/aec16138-a75a-4961-b8c1-8e803b6bf2cf/${originalname}`.
You may want to store the file with an arbitrary name instead of the original file name. You can do this by passing the `randomFilename` property attribute set to `true` as follows:
```typescript
@Post('upload')
@UseInterceptors(
AmazonS3FileInterceptor('file', {
randomFilename: true
}),
)
uploadFile(@UploadedFile() file) {
console.log(file);
}
```
If you want to resize the file before the upload, you can pass on the `resize` property as follows:
```typescript
@Post('upload')
@UseInterceptors(
AmazonS3FileInterceptor('file', {
resize: { width: 500, height: 400 },
}),
)
uploadFile(@UploadedFile() file) {
console.log(file);
}
```
You can pass an array of size options to resize a single image into different sizes as follows:
```typescript
@Post('upload')
@UseInterceptors(
AmazonS3FileInterceptor('file', {
resizeMultiple: [
{ suffix: 'sm', width: 200, height: 200 },
{ suffix: 'md', width: 300, height: 300 },
{ suffix: 'lg', width: 400, height: 400 },
],
}
)
uploadFile(@UploadedFile() file) {
console.log(file);
}
```
Not only creating a thumbnail image but also willing to change the file size limit, you can pass the properties as follows:
```typescript
@Post('upload')
@UseInterceptors(
AmazonS3FileInterceptor('file', {
thumbnail: { suffix: 'thumb', width: 200, height: 200 },
limits: { fileSize: 7 * 1024 * 1024 },
}),
)
uploadFile(@UploadedFile() file) {
console.log(file);
}
```
In this example, `uploadFile()` method will upload both thumbnail and original images.
### MulterExtendedS3Options
`MulterExtendedModule` requires an object with the following interface:
```typescript
interface MulterExtendedS3Options {
/**
* AWS Access Key ID
*/
readonly accessKeyId: string;
/**
* AWS Secret Access Key
*/
readonly secretAccessKey: string;
/**
* Default region name
* default: us-west-2
*/
readonly region: string;
/**
* The name of Amazon S3 bucket
*/
readonly bucket: string;
/**
* The base path where you want to store files in
*/
readonly basePath: string;
/**
* Optional parameter for Access control level for the file
* default: public-read
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl
*/
readonly acl?: string;
/**
* Optional parameter for the file size
* default: 3MB
*/
readonly fileSize?: number | string;
/**
* Optional parameter for a custom logger
* default: NestJS built-in text-based logger
* @see https://docs.nestjs.com/techniques/logger
*/
readonly logger?: LoggerService;
}
```
### MulterExtendedOptions
Key | Default | Description | Example
--- | --- | --- | ---
`dynamicPath` | undefined | The name that you assign to an S3 object | "aec16138-a75a-4961-b8c1-8e803b6bf2cf/random/dir"
`fileFilter` | Accepts JPEG, PNG types only | Function to control which files are accepted
`limits` | 3MB | Limits of the uploaded data | 5242880 (in bytes)
`resize` | undefined | Resize a single file | { width: 300, height: 350 }
`resizeMultiple` | undefined | Resize a single file into different sizes (`Array