Transformers
Transformer provides a presentation and transformation layer for complex data output, for example JSON response in REST APIs. Let's see any example on how it works.
Supports only JSON response for now.
We have already added a base Transformer
abstract class inside the core
module, the driver of our logic.
Let's create a BookTransformer
for a model, say Book
.
// src/transformers/book.ts
import { Transformer } from '@app/core';
export class BookTransformer extends Transformer {
async transform(book: Book$Model): Promise<Record<string, any>> {
return {
id: book.uuid,
name: book.name,
publisherName: book.publisher,
publishedOn: book.publishedAt,
};
}
}
Now to use the transformer, follow the steps below:
//TheFileWhereYouWantToUseIt.ts
import { BookTransformer } from '@app/transformers/book';
const transformer = new BookTransformer();
const payload = await transformer.work({
uuid: '75442486-0878-440c-9db1-a7006c25a39f',
name: "NestJS Boilerplate",
publisher: 'Squareboat'
publishedAt: "2020-12-03 22:00:00",
});
/**
* {
* id: "75442486-0878-440c-9db1-a7006c25a39f",
* name: "NestJS BoilerPlate",
* publisherName: "Squareboat",
* publishedAt: '2020-12-03'
* }
*/
console.log(payload)
Wait, transformer provide much more than a wrapper class.
While creating REST APIs you may come across a case where you want to fetch some related data with the main data.
For example, you may want to fetch author details along with the details of the book's detail that you requested.
Transformer provides an option to add all the available includes and default includes a transformer.
import { Transformer } from '@app/core';
export class BookTransformer extends Transformer {
availableIncludes = ['author']; // will be included on request
defaultIncludes = []; // included by default
async transform(book: Book$Model): Promise<Record<string, any>> {
return {
id: book.uuid,
name: book.name,
publisherName: book.publisher,
publishedOn: moment(book.publishedAt).format('YYYY-MM-DD'),
};
}
async includeAuthor(book: Book$Model): Promise<Record<string, any>> {
await book.$load({ author: true })
return this.item(book.author, new AuthorTransformer());
}
}
Notice the "author" inside the availableIncludes
and includeAuthor
method, transformer will add include prefix to the requested include. For example, transformer will look for includeAuthor
method when you request include=author
Now to use the include the author
option, we need to pass the include
query params in the URL, like:
/books/75442486-0878-440c-9db1-a7006c25a39f?include=author
For multiple includes, send comma seperated include options like include=author,publisher,releaseDetails
Now, inside your controller, do the following:
import { Get, Controller } from '@nestjs/common';
import { BookTransformer } from '@app/transformers';
@Controller('books')
export class BookController extends RestController {
@Get('/:uuid')
async get(@Req() req: Request, @Res() res: Response): Promise<Response> {
const inputs = req.all();
const data = {
uuid: '75442486-0878-440c-9db1-a7006c25a39f',
name: "NestJS Boilerplate",
publisher: 'Squareboat'
publishedAt: "2020-12-03 22:00:00",
};
return res.success(await this.transform(data, new BookTransformer, { req }))
/**
* {
* success: true,
* code: 200,
* data: {
* id: "75442486-0878-440c-9db1-a7006c25a39f",
* name: "NestJS BoilerPlate",
* publisherName: "Squareboat",
* publishedAt: '2020-12-03'
* }
* }
*/
}
}
You now know how to include data in your response on-demand, we understand there can be cases where you may want to include some nested relation as well.
You can do it by ?include=author[ratings]
, now make the following changes in BookTransformer
import { Transformer, Transformer$IncludeMethodOptions } from '@app/core';
export class BookTransformer extends Transformer {
availableIncludes = ['author']; // will be included on request
defaultIncludes = []; // included by default
async includeAuthor(
book: Book$Model,
options: Transformer$IncludeMethodOptions
): Promise<Record<string, any>> {
await book.$load({ author: true })
return this.item(book.author, new AuthorTransformer(), options);
}
}
Notice the options method you are receiving, this is auto-generated payload which you need to share it further to the item
, collection
method.
Now, inside the AuthorTransformer
, you can simply add a new include, rating
.