dto-serializer v0.1.1
DTO Serializer
Fast, minimal, type-safe, zero-dependency DTO serializer for Node
Get Started
Install the package
npm i dto-serializer
yarn dto-serializer
To create a DTO schema, simply declare an object with the properties you wish to expose:
const TestDto = {
foo: true,
bar: true
};
Then, simply pass the data to be serialized to the serialize
function along with the schema.
import { serialize } from 'dto-serializer';
const data = {
foo: 123,
bar: 'abc',
notExposed: 'abcd'
}
const serializedData = serialize(data, TestDto)
Usage with NestJS
To use this package with NestJS, create an interceptor, pass it the schema and serialize the data in the intercept
method.
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
import { map, Observable } from 'rxjs';
import { serialize, Schema } from 'dto-serializer';
export class SerializerInterceptor implements NestInterceptor {
constructor(private schema: Schema) {}
intercept(context: ExecutionContext, handler: CallHandler): Observable<any> {
return handler.handle().pipe(map((data: any) => serialize(data, this.schema)));
}
}
Design Principles
- Purely declarative
- no need to write ugly maps or other functions
- Properties are hidden by default
- unless you specify a property in your DTO object, it will be omitted from the output. This ensures that, as your data changes, you won't unintentionally leak properties in the output.
- Type-safe
Usage
- Declare a DTO object:
const TestDto = {
foo: true,
bar: true
};
- Import the
serialize
function and provide the data and the DTO:
const data = {
foo: 'abc',
bar: [12, 34]
};
serialize(data, TestDto)
Features
- Expose properties
To expose a property, it suffices to set its value in the DTO object to true
.
Conversely, to omit a property, don't add it in the DTO object, or set the value to false
.
- Transformations
You can pass custom transformation functions to each property
const TestDto = {
foo: (value) => Number(value, 10),
bar: (value) => value.toUppercase()
};
- Exposing in a different key
To expose a property in a different key, use the ":key"
value where key
is the name of the original key
const data = {
_id: '123'
}
// this will map the _id property of the data to id in the output
const UserDto = {
id: ':_id'
}
- Multiple transformations
To apply multiple transformations to a property, combine them in an array. This is especially useful when a different field than the exposed one needs to be transformed:
const data = {
user: ' User Name '
}
// this will trim the user field and expose it as userName
const UserDto = {
userName: [':user', ( value ) => value.trim()]
}
- Wildcards
Dealing with dynamically shaped objects is a huge pain point when working with libraries like class-transformer
. Sometimes we only know the object values, but not the exact keys:
const features = {
someFeature: true,
otherFeature: false
}
Other times, part the object we want to serialize is so dynamic that we simply want to return it as-is. Consider an endpoint which returns the responses of one or multiple API calls. Depending on the number of calls it could return short or long responses.
const data = {
status: 'OK',
}
const data1 = {
status: {status: 200, response: 'OK'},
}
const data2 = {
status: {statuses: [200, 404], responses: ['OK', 'NOT_FOUND']},
}
For both of these cases, dto-serializer
provides a handy feature called wildcards:
To serialize an object with dynamic key names, use the *
symbol as a key:
const FeaturesDTO = {
'*': true
}
To serialize a dynamic object, use the wildcard as a value.
// this will serialize all properties from the status key, whatever the value is:
const ResponseDTO = {
status: '*'
}
Inheritance
To inherit a DTO class, simply merge it with another one as you would do with plain objects:
const TestDto = {
foo: true,
bar: true
};
const HideBarDto = {
...TestDto,
bar: false
}
This will keep the foo
property of TestDto
, but hide the bar property.