Small Simple JS Json mapper
Map one json object to another. JS developer life is hard. You're getting numbers as strings. Someone on the backend is returning objects with underscores, so you called the police, but now you're stuck with this server.
First simple case, consider this response vrom server:
const resp = {
"playerId": "123e4567-e89b-12d3-a456-426655440000",
"numberOfLives": "4",
"lastRecord": "2018-05-14T03:00:00+0200"
}
Define transformation:
const playerMapping = {
"playerId": String,
"numberOfLives": Int,
"lastRecord": Date
}
Call: mapJson(resp, playerMapping)
And this is the result:
{
const resp = {
"playerId": "123e4567-e89b-12d3-a456-426655440000",
"numberOfLives": 4,
"lastRecord": new Date("2018-05-14T03:00:00+0200")
}
}
But now you can do more cool stuff. For example you have another api, returning list of users. Now you can reuse your mapping, on the list:
const listMapping = {
"userList": new ComplexArray(playerMapping)
}
So when you receive array of users, each object will be mapped correctly to your needs.
But wait there's more.
Key PlayerId
sounds little too tedious.
So you can define transformation:
const advancedPlayerMapping = {
"playerId": {
toName: "id",
type: String,
},
"numberOfLives": Int,
"lastRecord": Date
}
and now the output will be
const mappedResp = {
"id": "123e4567-e89b-12d3-a456-426655440000",
"numberOfLives": 4,
"lastRecord": new Date("2018-05-14T03:00:00+0200")
}
But wait there's more!
Wha if playerId consists of multiple parts with meaning. First part is groupId. Now you need more complex transformation. For that purpose you can write your own mapping function.
function idMapper(value) {
const idSplit = value.split("-");
return {
groupId: idSplit[0],
playerId: value,
isValid: value.includes("-")
}
}
const playerMapping = {
"playerId": {
toName: "playerIdentifier",
mapper: idMapper,
},
"numberOfLives": Int,
"lastRecord": Date
}
Now the result will be:
const mappedResp = {
"playerIdentifier": {
groupId: "123e4567",
playerId: "123e4567-e89b-12d3-a456-426655440000",
isValid: true,
},
"numberOfLives": 4,
"lastRecord": new Date("2018-05-14T03:00:00+0200")
}
Defining these mapping objects can do for you more than you expect.
You can for example force consistency of object structures.
There is third argument to function: mapJson(obj, mappingDef, options)
options = {
includeUndescribed: boolean, // includes also attributes not specified in mappingDef
fillMissing: boolean, // add missing keys from obj - default true
}
So having input object
const simpleObj = {
attr1: "string1",
attr2: "string1",
attr3: "string1",
}
and mapping definition:
const simpleMapping = {
attr1: String,
attr3: String,
attr4: String,
}
calling const mappingResult = mapJson(simpleObj, simpleMapping)
will produce
const mappingResult = {
attr1: "string1",
attr3: "string1",
attr4: null,
}
thus maintaining the structure defined in simpleMapping
.
Or define your custom default value for attributes
const simpleMapping = {
attr1: String,
attr3: String,
attr4: {
type: String,
defaultValue: "this is missing string"
},
}
with result
const mappingResult = {
attr1: "string1",
attr3: "string1",
attr4: "this is missing string",
}
For more information consult TypeMapper.js.flow with comments and all options.
That's all folks;