Using ts-serializer to serialize and deserialize JSON Objects

Serializing?

Serialization is the process of converting complex objects into a data format that can be easily stored or sent across a network connection. In JavaScript, serialization and deserialization of objects can be achieved by using JSON.stringify() and JSON.parse().

Example

 // Let's say you have a simple json response from your server.
 var jsonResponse = "{firstName:\"John\", lastName:\"Doe\"}";

 // If you want to deserialize this object, you can use JSON.parse().
 var jsonParsed = JSON.parse(jsonResponse);

 // An object with the correct properties will be returned
 console.log(jsonParsed.firstName); // Prints 'John'
 console.log(jsonParsed.lastName); // Prints 'Doe'

 // If you want to serialize the object back into a string represantation, you can use JSON.stringify()
 var serializedJson = JSON.stringify(parsedJson);
 console.log(serializedJson); // Prints '{firstName:"John", lastName:"Doe"}'

The Problem?

Things start to get complicated when you are using TypeScript or ES6 and the response from the server doesn’t really match your client data structure. In this case you have an extra step of copying the properties from the parsed json response into your custom model object. When you want to send the data back to the server you have to copy the properties again into their original format.

Example

 // The response from the server
 let response:string = "{first_name:\"John\", last_name:\"Doe\"}";

 // Your model class
 class UserProfile {
     firstName:string;
     lastName:string;
 }

 let jsonParsed = JSON.parse(response);

 var userProfile = new UserProfile();
 userProfile.firstName = jsonParsed.first_name;
 userProfile.lastName = jsonParsed.last_name;

 // When you want to send the data back to the server you have to do the same things as above but in reverse.
 let dataToSend = {
     first_name: userProfile.firstName,
     last_name: userProfile.lastName
 };

 let dataAsString = JSON.stringify(dataToSend);

 console.log(dataAsString); // Prints {first_name:"John", last_name:"Doe"}

 // It's easy to see that when you have lots of properties this gets very messy, very quickly

Solution? Introducing TS Serializer

Some time ago I have started using TypeScript for most of my projects. One of those projects had a very different data structure between the server and the client. After getting very frustated with writing serialization and deserialization methods for my data models, I came up with the ideea of ts-serializer. ts-serializer is a collection of typescript decorators and helper classes that allows the developer to easily serialize and deserialize complex objects to and from JSON objects.

Installation

Using NPM

npm install --save ts-serializer

Build from Git

git clone https://github.com/dpopescu/ts-serializer.git
cd ts-serializer
npm install
npm run build

The library will be in the dist folder

Usage

You start by importing the library decorators and the Serializable abstract class

 import {Serialize, SerializeProperty, Serializable} from 'ts-serializer';

In order to mark a class as serializable, you need to use the Serialize decorator and extend the abstract Serializable class.

 @Serialize({})
 class Profile extends Serializable {
 }

The Serialize decorator implements in the target class the serialize and deserialize methods required by the Serializable class.

By default, the library does not serialize class properties if are not marked for serialization. In order to declare a property as serializable you use the SerializeProperty decorator.

 @Serialize({})
 class Profile extends Serializable {
     @SerializeProperty({})
     firstName:string;
     @SerializeProperty({})
     lastName:string;
 }

After the class and the class properties are marked as serializable, you can use the serialize and deserialize methods and ts-serializer will take care of things for you.

Full Example

import {Serialize, SerializeProperty, Serializable} from 'ts-serializer';

@Serialize({})
 class User extends Serializable {
     @SerializeProperty({
        map: 'first_name'
     })
     firstName:string;
     @SerializeProperty({
        map: 'last_name'
     })
     lastName:string;
 }

@Serialize({})
 class Profile extends Serializable {
     @SerializeProperty({
        type: User
     })
     user: User;
 }

 let data = {
    user: {
        first_name: 'John',
        last_name: 'Doe'
    }
 };

 let instance:Profile = new Profile();
 instance.deserialize(data);

 console.log(instance.user.firstName); // Prints 'John'
 console.log(instance.user.lastName); // Prints 'Doe'

 console.log(instance.serialize()); // Prints {"user":{"first_name":"John", "last_name":"Doe"}}

 console.log(instance.user.serialize()); // Prints {"first_name":"John", "last_name":"Doe"}

For more information about the library check out serializer.dpopescu.me and ts-serializer Github page

11 comments on “Using ts-serializer to serialize and deserialize JSON Objects

  1. Florin Onciu says:

    Nice post! But I have a very awkward scenario, where my app should work offline. So what I am doing today is to send all the data as a json string to the client and sync it back when there is connection.

    The problem I have is that data can become huge. When I JSON.parse a huge string on an old device, the browser crashes.

    Is there any possible solution to this?

    Like

    • Daniel Popescu says:

      Personally, I would split my data in related chunks. You can still sync it with your server in just one call, but the JSON parsing can be done in chunks.

      Let’s say you have this kind of data :
      {user:{name:’a’, email:’a@b.com’}, books:[{name:’a’, type:’a’}, {name:’b’, type:’b’}], someOtherObject:{prop:value}}

      Instead of parsing the whole thing you could just split it in small objects

      var user = JSON.parse(data.user);
      var books = JSON.parse(data.books);
      var someObject = JSON.parse(data.someOtherObject);

      When you want to send it back to the server just reverse the operation.

      Hope this helps.

      Like

      • Florin Onciu says:

        But you still need to do JSON.parse of that to have access to “user”, “books” and “someOtherObject” objects. So we’re back to the first problem 🙂

        Like

      • Daniel Popescu says:

        Save smaller json files locally. Instead of having one big json you will have smaller ones that can be easily parsed. User json, books json and someOtherObject json.

        If you have some code publicly available maybe I can better understand what the code looks like.

        Like

  2. Mary P says:

    You can still sync it with your server in just one call, but the JSON parsing can be done in chunks. User json, books json and someOtherObject json.

    Like

  3. Programming Lang says:

    User json, books json and someOtherObject json. com’}, books:[{name:’a’, type:’a’}, {name:’b’, type:’b’}], someOtherObject:{prop:value}}
    Instead of parsing the whole thing you could just split it in small objects
    var user = JSON.

    Like

  4. TechBook says:

    The problem I have is that data can become huge. User json, books json and someOtherObject json.

    Like

  5. Computer says:

    User json, books json and someOtherObject json. You can still sync it with your server in just one call, but the JSON parsing can be done in chunks.

    Like

  6. gumersindo says:

    User json, books json and someOtherObject json. com’}, books:[{name:’a’, type:’a’}, {name:’b’, type:’b’}], someOtherObject:{prop:value}}
    Instead of parsing the whole thing you could just split it in small objects
    var user = JSON.

    Like

  7. Chandar says:

    getting error angular2-polyfills.js:138 Error: XHR error (404 Not Found) loading http://localhost:8000/ts-serializer

    Like

  8. Michael Fritsch says:

    Hi Daniel, looks very interesting, especially it’s based on decorators. But I found no way to handle the deserializing with an angular 5 service. Would it possible to get a sample, too? greets, Michael

    Like

Leave a reply to Michael Fritsch Cancel reply