SImple to use library to map DTO using typescript decorators
This node module is available through npm.
This package is meant to be used inside a Typescript project as it leverages decorators to work.
npm i dto-mapper
This package has a peer dependency to reflect-metadata and will require it to function properly. It can be installed from npm using the following command:
npm i reflect-metadata
You will need to enable experimental decorators and emitting decorator metadata inside your tsconfig.json
:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
@dto()
export class UserDto {
@include()
id: number;
@include()
email: string;
}
DTOs must be annotated by @dto() in order to be accepted by the builder function.
Child class inheriting from class annotated by @dto() must also be explicitly decorated by the @dto().
Every field that need to be mapped inside the DTO must be explicitly decorated by @include() or they will be ignored by default.
By default fields from the DTO will expect a field with the same name inside the object being serialized. When being deserialized they will also map to a field with the same name by default.
For example the above DTO will expect an object similar to:
const toSerialize = {
id: 0,
email: "[email protected]",
};
There are various decorators available to customize this behavior:
This decorator allows to define the name of the field the property is mapped to.
Example:
@dto()
export class UserDto {
@include()
id: number;
@include()
@mapTo('userEmail')
email: string;
}
This DTO will expect an object similar to:
const toSerialize = {
id: 0,
userEmail: "[email protected]",
};
This decorator allows to restrict the access to the property, it accepts a value from the AccessMode
enum:
Value | Effect |
---|---|
AccessMode.NONE | Property will be ignored. |
AccessMode.READ | Property will be only serialized but not deserialized. |
AccessMode.WRITE | Property will be only deserialized but not serialized. |
AccessMode.ALL (default) | Property will be ignored. |
Shortcut for @accessMode(AccessMode.READ)
Shortcut for @accessMode(AccessMode.WRITE)
Allows to modify a property before serializing and deserializing it.
Example:
@dto()
export class UserDto {
@include()
id: number;
@include()
@transform({
toDto: (name) => name.toUpperCase(),
fromDto: (name) => name.toLowerCase(),
})
name: string;
}
In this example the name
property will be serialized in uppercase but will be deserialized in lowercase.
Defines the scopes that can access this property. The scope can be passed to the mapper when serializing or deserializing.
This can be used to hide fields to user with insufficient permissions
Example:
@dto()
export class UserDto {
@include()
id: number;
@include()
@scope('admin', 'moderator')
name: string;
}
In this example the name
property will only be serialized and deserialized if the 'admin'
OR
the 'moderator'
scope is passed to the mapper.
Allows to map a property to another DTO.
Example:
@dto()
export class RoleDto {
@include()
name: string;
}
@dto()
export class UserDto {
@include()
id: number;
@include()
@nested(
() => RoleDto,
true /* Set to true if this is an array otherwise false */
)
roles: RoleDto[];
}
In this example the UserDto
includes an array of RoleDto
.
Once your DTO class has been defined you can create a mapper to actually start serializing and deserializing data.
In order to do so you can use the buildMapper
function.
Example:
const mapper = buildMapper(UserDto); // Magic !
Important: this function is expensive and should be called only once per DTO, you should cache the mapper and reuse it.
Finally, when your mapper is ready you can call the serialize
method to serialize data:
// No scope
const serialized = mapper.serialize({ id: 0, userEmail: '[email protected]' });
// Admin scope
const serializedWithScope = mapper.serialize({ id: 0, userEmail: '[email protected]' }, 'admin');
You can deserialize data using the deserialize
method:
// No scope
const deserialized = mapper.deserialize({ id: 0, email: '[email protected]' });
// Admin scope
const deserializedWithScope = mapper.deserialize({ id: 0, email: '[email protected]' }, 'admin');