Skip to main content

EJSON

EJSON is a great way to use JSON to pass binaries and serialize/deserialize any type of data with ease. We use it to easily serialise/deserialise our objects while maintaining important objects such as dates, object ids, regexps, etc.

Install

npm install --save @bluelibs/ejson
import { EJSON } from "@bluelibs/ejson";
const result = EJSON.stringify({ a: 1 }); // string: {"a": 1}const parsed = EJSON.parse(result); // object: {a: 1}

Works with complex objects such as Date, RegExp, NaN, Inf, -Inf:

const result = EJSON.stringify({ now: new Date() }); // string: {"now": { "$date": 100000000 }}

Official EJSON Documentation

This has been done by Meteor, we migrated it to TypeScript and added some extra flavors. Follow the official and complete documentation here, our implementation is a superset of it: https://docs.meteor.com/api/ejson.html

Custom Types

Works with custom defined objects for easy serialisastion and deserialisation:

class Distance {  constructor(value, unit) {    this.value = value;    this.unit = unit;  }
  // Convert our type to JSON.  toJSONValue() {    return {      value: this.value,      unit: this.unit,    };  }
  // Unique type name.  typeName() {    return "Distance";  }}
EJSON.addType("Distance", function fromJSONValue(json) {  return new Distance(json.value, json.unit);});
EJSON.stringify(new Distance(10, "m"));// Returns '{"$type":"Distance","$value":{"value":10,"unit":"m"}}'

ObjectId

We use and export ObjectId from bson-objectid npm package (the only dependency of this package).

Basically we encode and decode to ObjectId the following set:

import { ObjectId } from "@bluelibs/ejson";
const postEJSON = {  _id: {    $objectId: "XXX",  },};
const post = EJSON.fromJSONValue(postEJSON);post._id instanceof ObjectId; // true

This is mostly used for MongoDB database; if you use other databases and don't need it, then you can leave it be as a dormant functionality.

Models

An easy way to transform an object into a class instance.

import { toModel } from "@bluelibs/ejson";
class Person {  firstname: string;  lastname: string;  age: number = 25;
  get fullname() {    return `${this.firstname} ${this.lastname}`;  }}
const person = toModel(Person, {  firstname: "John",  lastname: "Smith",});
// ignore default valuesconst person = toModel(  Person,  {    firstname: "John",    lastname: "Smith",  },  {    partial: true,  });
// person.age == undefined

Note that this toModel function is very primitive. It won't work with nested functions. For a more robust alternative feel free to use class-transformer as it gives you with a stable and fully-featured way to transform plain objects into models.

Another solution which focuses on speed but also Developer Experience is Type from DeepKit. We recommend that you take a look at it as well.

Meta

Summary

EJSON is JSON + some flavors. It allows us to easily communicate with external JSON APIs and removes the headache of handling Dates, RegExps when they are coming as a client request.

Challenges

  • Try serialising with EJSON the following object: { date: new Date(), } (1p)