# JsonMapper
The @tsed/json-mapper
package is responsible to map a plain object to a model and a model to a plain object.
It provides two functions
serialize
and
deserialize
to transform object depending on which operation you want to perform.
It uses all decorators from @tsed/schema
package and TypeScript metadata to work.
Ts.ED use this package to transform any input parameters sent by your consumer to a class and transform returned value by your endpoint to a plain javascript object to your consumer.
# Configuration
@Configuration({
jsonMapper: {
additionalProperties: false,
disableUnsecureConstructor: false,
}
})
2
3
4
5
6
# jsonMapper.additionalProperties
Enable additional properties on model. By default, false
. Enable this option is dangerous and may be a potential security issue.
# jsonMapper.disableUnsecureConstructor
Pass the plain object to the model constructor. By default, true
.
It may be a potential security issue if you have as constructor with this followings code:
class MyModel {
constructor(obj: any = {}) {
Object.assign(this, obj); // potential prototype pollution
}
}
2
3
4
5
# Usage
JsonMapper works with a class and decorators. Use decorators on properties to describe a model and use this model as an input parameter or return value by your endpoint. Here is a model example:
Note
Take a look on Jest/Mocha tabs to see serialize and deserialize functions usage.
Now we can use the Person
model on a controller:
import {BodyParams} from "@tsed/platform-params";
import {Get, Post, Returns} from "@tsed/schema";
import {Controller} from "@tsed/di";
import {Person} from "../models/Person";
@Controller("/")
export class PersonsCtrl {
@Post("/")
@Returns(200, Person)
async save1(@BodyParams() person: Person): Promise<Person> {
console.log(person instanceof Person); // true
return person; // will be serialized according to your annotation on Person class.
}
// OR
@Post("/")
@Returns(200, Person)
async save2(@BodyParams("person") person: Person): Promise<Person> {
console.log(person instanceof Person); // true
return person; // will be serialized according to your annotation on Person class.
}
@Get("/")
@Returns(200, Array).Of(Person) // Add the correct json schema for swagger essentially.
async getPersons(): Promise<Person[]> {
return [new Person()];
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Note
In the previous example, we can see Returns decorator usage. In all case, Ts.ED infer the returned value and apply the correct transformation on your response.
Returns decorator is used to generate the correct swagger documentation only.
WARNING
When a model is provided, JsonMapper will follow exactly the JsonSchema generated by @tsed/schema
package.
It means, if you missed decorating one or more properties on your model, these properties won't be appear after the transformation.
Note: Result is displayed in Jest/Mocha tabs.
# Ignore properties
# Usage
Ignore decorator can be used to ignore explicitly a property when a transformation have been performed.
For example, you have a base model to create a User named UserCreation
where the password
is required, but
you don't want to expose this field in other cases. One of the solution is to use class inheritance to solve this problem.
# With a callback
Ignore decorator since v6.13.0 accept a callback which will be called when a property have been serialized or deserialized. The callback will give you more control over the way to ignore a property.
class User {
@Name("id")
_id: string;
@Property()
firstName: string;
@Property()
lastName: string;
@Ignore((value, ctx) => ctx.endpoint) // should not serialized when the object is returned by an endpoint.
password: string;
@Ignore((value, ctx) => ctx.mongoose) // should be serialized when the object is returned by an endpoint.
scopes: string[];
@Ignore()
alwaysIgnored: string;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Here is the available options on ctx:
Prop | Type | Description |
---|---|---|
endpoint | boolean | It's an endpoint context |
mongoose | boolean | It's a mongoose context |
# Additional properties
AdditionalProperties decorator can be used to accept any additional properties on a specific model.
# Alias
Name decorator lets you to rename the exposed property in your json schema.
For example mongo db uses the _id
property.
In order not to give any indication to our consumer about the nature of the database, it's better to rename the property to id
.
import {Description, Example, Name} from "@tsed/schema";
import {ObjectID} from "@tsed/mongoose";
export class Model {
@Name("id")
@Description("Object ID")
@Example("5ce7ad3028890bd71749d477")
_id: string;
}
// same example with mongoose
export class Model2 {
@ObjectID("id")
_id: string;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# OnSerialize
OnSerialize decorator can be used to intercept and change the property value when a serialization is performed on class.
import {OnSerialize} from "@tsed/schema";
export class Person {
@OnSerialize((v) => v + "Test")
property: string;
}
2
3
4
5
6
# OnDeserialize
OnDeserialize decorator can be used to intercept and change the property value when a deserialization is performed on class.
import {OnDeserialize} from "@tsed/schema";
export class Person {
@OnDeserialize((v) => v + "Test")
property: string;
}
2
3
4
5
6
# Type mapper
@tsed/json-mapper
use classes to transform an input value to the expected value:
Type | Mapper |
---|---|
Primitives | PrimitiveMapper , |
Symbol | SymbolMapper , |
Objects | DateMapper , |
Collections | ArrayMapper , MapMapper and SetMapper . |
It's possible to add your own type mapper by using the JsonMapper decorator on a class. Just copy a mapper implementation and import the mapper in your application.
# Primitives
PrimitiveMapper
is responsible to map the primitive value like Boolean
, Number
or String
.
# Cheat sheet
Input | Type | Output |
---|---|---|
1 | String | "1" |
"1" | String | "1" |
null | Number | null |
"null" | Number | null |
"1" | Number | 1 |
1 | Number | 1 |
"to1" | Number | Throw Bad Request. This is the only case where JsonMapper throw a cast type error. |
true | Boolean | true |
"true" | Boolean | true |
"1" | Boolean | true |
1 | Boolean | true |
false | Boolean | false |
"false" | Boolean | false |
"0" | Boolean | false |
0 | Boolean | false |
"" | Boolean | false |
"null" | Boolean | null |
undefined | Boolean | undefined |
# Symbol
SymbolMapper
is responsible to map a String
to Symbol
or a Symbol
to a String
.
# Date
DateMapper
is responsible to map a Number
, String
to a Date
or a Date
to a String
.
# Array
ArrayMapper
is responsible to map any data to an Array
.
# Map
MapMapper
is responsible to map an Object
to a Map
.
# Set
SetMapper
is responsible to map an Array
to a Set
.
# Create your own type mapper
It's possible de to change add your own type mapper by using the JsonMapper decorator on a class. Just copy a mapper implementation and import the mapper in your application.
A mapper must declare the type it must work on and implement two methods: serialize and deserialize.
import {JsonMapper, JsonMapperMethods, JsonMapperCtx} from "@tsed/json-mapper";
@JsonMapper(String)
export class TheTypeMapper implements JsonMapperMethods {
deserialize(data: any, ctx: JsonMapperCtx): String {
return JSON.stringify(data) + ":deserialize";
}
serialize(data: any, ctx: JsonMapperCtx): String {
return JSON.stringify(data) + ":serialize";
}
}
2
3
4
5
6
7
8
9
10
11
12
Then import your new mapper in your Server.ts as following:
import {Configuration} from "@tsed/di";
import "./mappers/TheTypeMapper";
@Configuration({
mount: {
"/rest": []
}
})
export class Server {}
2
3
4
5
6
7
8
9
10
# Moment
Moment.js (opens new window) is a powerful library to transform any formatted date string to a Moment instance.
You can change the Date mapper behavior to transform string to a Moment instance.
Last Updated: 2/5/2023, 1:16:22 PM
Other topics
- Session & cookies
- Passport.js
- Keycloak
- Prisma
- TypeORM
- MikroORM
- Mongoose
- GraphQL
- Socket.io
- Swagger
- AJV
- Multer
- Serve static files
- Templating
- Serverless HTTP
- Seq
- OIDC
- Stripe
- Agenda
- Terminus
- Serverless
- IORedis
- Controllers
- Providers
- Model
- JsonMapper
- Middlewares
- Pipes
- Interceptors
- Authentication
- Hooks
- Exceptions
- Throw HTTP Exceptions
- Cache
- Command
- Response Filter
- Injection scopes
- Custom providers
- Lazy-loading provider
- Custom endpoint decorator
- Testing
- Customize 404