Using with class-transformer
Last updated for:
@typegoose/typegoose@10.0.0
class-transformer@0.5.1
This guide shows how to use typegoose
with class-transformer
.
- npm
- Yarn
- pnpm
npm install --save class-transformer@~0.5.1
yarn add class-transformer@~0.5.1
pnpm add class-transformer@~0.5.1
Implementation
Suppose you have this Account
class decorated with class-transformer
:
import { Exclude, Expose, Transform } from 'class-transformer';
import { getModelForClass, mongoose, prop } from '@typegoose/typegoose';
// re-implement base Document to allow class-transformer to serialize/deserialize its properties
// This class is needed, otherwise "_id" and "__v" would be excluded from the output
class DocumentCT {
@Expose()
// makes sure that when deserializing from a Mongoose Object, ObjectId is serialized into a string
@Transform((value) => {
if ('value' in value) {
// HACK: this is changed because of https://github.com/typestack/class-transformer/issues/879
// return value.value.toString(); // because "toString" is also a wrapper for "toHexString"
return value.obj[value.key].toString();
}
return 'unknown value';
})
public _id: string;
@Expose()
public __v: number;
}
@Exclude()
class Account extends DocumentCT {
@prop()
@Expose()
public email: string;
@prop()
@Expose({ groups: ['admin'] })
public password: string;
}
const AccountModel = getModelForClass(Account);
Side-Note: Typegoose doesn't provide a class like DocumentCT
by default, because this would require adding class-transformer
as a dependency.
You can then use, for example:
lean()
on the query:// lean return a Plain Old Javascript Object
const pojo = await AccountModel.findById(id).orFail().lean().exec();
// deserialize Plain Old Javascript Object into an instance of the Account class
const deserialized = plainToClass(Account, pojo);
// serialize Account instance back to a Plain Old Javascript Object, applying class-transformer's magic
const serialized = instanceToPlain(deserialized);or a normal document:
// exec returns a Mongoose Object
const mo = await AccountModel.findById(id).orFail().exec();
// deserialize Mongoose Object into an instance of the Account class
const deserialized = plainToClass(Account, mo);
// serialize Account instance back to a Plain Old Javascript Object, applying class-transformer's magic
const serialized = instanceToPlain(deserialized);
As you can see from these examples, there is:
- a redundant step to first turn the output of the query into a full instance of
Account
:plainToClass(..., ...)
- before being able to benefit from its features for serialization:
instanceToPlain(...)
The reason for doing this is so queries will output DocumentType<Account>
(Mongoose Document) instead of required Account
(Plain Object / instance of the Class) in this example.
class-transformer
can only operate its magic on instances of annotated classes.
info
For more information, you can always look at the typegoose class-transformer
tests