Skip to main content

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.

Pro Tip

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
}
}
}

Postman Collection

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;
};
}