[ ] Regression
[ ] Bug report
[ ] Feature request
[x] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Hey! I'm currently evaluating Nest for use on a larger project. Really liking the framework so far.
One thing I can't seem to see clearly in the documentation is a recommended approach to JSON serialization. Coming from Laravel and Rails, I'm used to using packages such as ThePHPLeague / Fractal, or Rails' ActiveModel::Serializer to define the structure of each entity for when it's serialized as JSON.
I've seen recommendations to use class-transformer
, which allows you to hide/show properties using decorators. However, I see some significant benefits when using the two libraries mentioned above:
<root>/posts?include=author,comments.author
will return posts, with comments and the author of each comment.Is there a common package or process used to achieve parts (or all) of the above in Nest / Node?
Hi @jonlambert,
Thank you!
I think that you should be able to easily achieve all these functionalities using interceptors.
class-validator
or put a custom logic inside an interceptor (treat it like a serializer)context.switchToHttp().getRequest()
) and utility functions like pick
or get
from lodash https://lodash.com/docs/4.17.10#pick, and afterward, map the result.Thanks for the response! For those finding this issue later, serializers just like these have been added to Nest docs. Cheers @kamilmysliwiec 馃憤
What about serializers on mongoose models? These are not covered.
Bump, what about mongoose? @kamilmysliwiec
anyway of using this with mongoose?
@DimosthenisK, @rlesniak, @cerireyhan If you are still interested, I was able to find one approach to make serialization work with mongoose and that is by using typegoose.
TL;DR: Set prototype of returned object to a prototype of a class with your serialization decorators.
Versions that I worked with:
"@nestjs/common": "6.6.7",
"@hasezoey/typegoose": "6.0.0-27",
"typescript": "3.7.0-dev.20190907",
Problem: The way I see it, functions like 'find'/'save'/etc.. return Documents and for serialization to work, you have to map those results to concrete types with serialization decorators. One way is to use any available mapping mechanism (e.g. morphism npm package), and that way you might not even need a Serialization approach. But if you want to use serialization on defined model, then typegoose helps a little by removing a need to maintain an interface and defining serialization decorators in your model.
Examples below might be missing some parts like imports and setup of modules/providers, but should be enough
Model:
import { prop as Property } from '@hasezoey/typegoose';
export class Asset {
public id!: string;
@Property({ required: true, index: true })
public title!: string;
@Exclude()
@Property()
public excludeMe: string;
}
Controller
@UseInterceptors(ClassSerializerInterceptor)
@SerializeOptions({
excludePrefixes: ['_'],
})
@Controller('assets')
export class AssetsController {
constructor(private readonly assetsService: AssetsService) {}
@Get('/:id')
async getById(@Param('id') id: string): Promise<Asset> {
return await this.assetsService.getById(id);
}
}
Service
import { DocumentType } from '@hasezoey/typegoose';
@Injectable()
export class AssetsService {
constructor(
@Inject('assets')
private readonly model: Model<DocumentType<Asset>>,
) {
}
async getById(id: ObjectId | string): Promise<Asset> {
const result = await this.model.findById(id);
if (result) {
result = result.toObject();
const classProto = Object.getPrototypeOf(new Asset());
Object.setPrototypeOf(result, classProto);
return result ;
}
throw new NotFoundException(`Asset with Id '${id}' not found.`);
}
}
To me, it kind of looks like a hack, but I have not found a better way without introducing dedicated DTOs to return. Trying to do this in mongoose middleware seems to not work and creating a separate nestjs interceptor will not guarantee a positive result, because in some cases you want to return a DTO which contains a property of Document type, and in that case you basically have to iterate through all properties to find ones to transform, which is a hassle.
Hope this helps a little :)
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
What about serializers on mongoose models? These are not covered.