Setup
To get started with the Media Worker in your project, follow the below mentioned steps.
./node_modules/.bin/nest g lib media-worker # answer the question whatever is asked for.
torque add-pod nestjs-media-worker --directory libs/media-worker --latest
You should see an output like below.
It is highly recommended to keep Media Worker function outside your main backend application, as this is heavy and needs good amount of computing power.
A good idea will be to keep all serverless applications as a separate project.
Configuration
Use ConfigModule
provided by NestJS to load configurations. To learn about ConfigModule
, click here.
1. Create config/pdf-worker.ts
import { MediaWorkerOptions } from '@libs/image-compressor';
import { registerAs } from '@nestjs/config';
export default registerAs(
'media',
() =>
({
isLocal: process.env.NODE_ENV === 'local',
storageDisk: 'media',
images: {
variants: [
{ width: 500, height: 480, path: 'img_small' },
{ width: 854, height: 480, path: 'img_medium' },
],
},
} as MediaWorkerOptions),
);
2. Register Async MediaWorkerModule
Add following snippet to the imports
array. ConfigService
is importable from @nestjs/config
module
MediaWorkerModule.registerAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => config.get('media'),
inject: [ConfigService],
}),
Apart from the above mentioned configuration, you need to also configure @squareboat/nest-storage
package if not already configured. You can follow this documentation for it's setup.
Usage
Now that the configuration and setup is complete, let's see how we can use it.
The usage is pretty straight forward, the module exports a MediaWorker
class which you can use to compress the image.
Compressing Image
services/media.ts
import { Injectable } from '@nestjs/common';
import { CompressImageDto } from './dto';
import { MediaWorkerLibService } from '@libs/image-compressor';
@Injectable()
export class MediaService {
constructor(private lib: MediaWorkerLibService) {}
async compress(dto: CompressImageDto): Promise<Record<string, any>> {
return this.lib.compressImage(dto);
}
}
You can use this MediaService
further in your controller and start using the API for compressing the image.
controllers/pdf.ts
@Controller()
export class MediaWorkerController extends RestController {
constructor(private readonly service: MediaService) {
super();
}
@Post('compress')
@Validate(CompressImageDto)
async compress(@Dto() dto: CompressImageDto, @Res() res: Response) {
console.log(dto);
const compressResponse = await this.service.compress(dto);
return res.success(compressResponse);
}
}
You can test your integration by sending a sample request to your controller, as below.
# URL
{{base_url}}/media-worker/compress
# Body
{
"sourceDisk": "s3",
"s3": {
"bucket": "batteries-test",
"path": "images/originals/nested1/IMG_5337.jpg"
}
}
# Response
{
"success": true,
"code": 200,
"data": {
"variants": [
{
"width": 500,
"height": 480,
"path": "img_small"
},
{
"width": 854,
"height": 480,
"path": "img_medium"
}
],
"dimensions": {
"originalWidth": 4032,
"originalHeight": 3024,
"originalChannels": 3
},
"dominantColor": {
"r": 126,
"g": 126,
"b": 110
}
}
}
API
1. CompressImageDto
export class CompressImageDto {
@IsIn(['s3'])
sourceDisk: 's3';
@ValidateNested()
@ValidateIf((o) => o.sourceDisk === 's3')
@Type(() => S3ConfigDto)
s3: S3ConfigDto;
@ValidateNested()
@IsOptional()
@Type(() => S3ConfigDto)
destination: S3ConfigDto;
}
2. S3ConfigDto
export class S3ConfigDto {
@IsNotEmpty()
@IsString()
bucket!: string;
@IsNotEmpty()
@IsString()
path!: string;
}
3. ImageVariant
export interface ImageVariant {
width: number;
height: number;
path: string;
}
4. CompressImageResponse
export interface CompressImageResponse {
variants: ImageVariant[];
dimensions: {
originalWidth: number;
originalHeight: number;
originalChannels: number;
};
dominantColor: {
r: number;
g: number;
b: number;
};
}