0.1.0 • Published 7 years ago

jsonmodel v0.1.0

Weekly downloads
2
License
MIT
Repository
github
Last release
7 years ago

JSONModel

JSONModel is a tiny yet powerful library which does three things:

  • Provides utility functions for save, update, find and delete without developer needing to write verbose AJAX apis
  • Gives a structure to a JSON string which makes it easier to understand and maintain
  • Validates the passed JSON and returns well-formatted error messages

In summary, it uses W3C JSON Schema to define object structure, provides well-formatted error messages, and a simple default RESTful CRUD interface.

We are using JSONModel in our Core Analytics Portal client and backend apps. This makes it very easy to share schemas across stacks as it is based of JSON without any code duplication for all the 3 tasks!

Installation

npm install json_model --save

Usage

These are the typical order of steps for using JSON Model. index_test.js has an excellent example how to use JSON Model.

  • Create a JSON Schema object
  • Create a settings object (see below for all available settings)
  • Create JSONModel class using JSONModel.create()
  • Create an instance of the class
  • Interact with server using the instance with .save(), .delete() methods
  • Interact with server using the class with .find() method
const JSONModel = require( "json_model" );

const schema = {}; // standard JSON Schema http://json-schema.org/
const settings = {}; // options like URI of the server

const Person = JSONModel.create( schema, settings );

const john = new Person({name: "John", age: 36});
john.save().then( p => console.log( p ) ).catch( err => console.log( err ) ); // makes a POST
john.age = 37;
john.save().then( p => console.log( p ) ).catch( err => console.log( err ) ); // makes a PUT

const josh = new Person({name: "Josh", age: 35}); // create another person using Person class
josh.save();
josh.delete(); // makes a DELETE request

const alice = await Person.find(673653); // makes a GET /personAPI/673653
alice.age = 40;
alice.save(); // makes a PUT

const someJohns = await Person.find({name: "john", age: 35}); // makes a GET /personAPI?name=john&age=35
someJohns.forEach(j => {
    j.name = "John"; // make changes
    j.save(); // makes a PUT
});

API

The code, json_model.js file is < 100 lines of code easy enough to read.

JSONModel.create(schema, settings)

Creates a new JSON Model class which can be used to create or fetch instances of the schema.

Arguments

  • schema: a valid JSON Schema. However JSON Schema doesn't support custom error messages for validation errors. JSON Model introduces error_messages field for each property where error messages for each validation are specified.
const schema = {
  "title": "Person",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Auto generated by backend"
    },
    "name": {
      "type": "string",
      "error_messages": { "required": "name is required" }
    },
    ...
  },
  "required": [ "name" ]
};

In the above schema when trying to save a Person with name missing, name is required error is thrown.

  • settings: describes the details required to talk to server.

    • idProp: name of the property to uniquely identify an instance. Existance of this property hints whether this is a new object or an existing object and accordingly either POST or PUT calls are made
    • url: the url to make the AJAX requests
    • parseInstanceProp: what property in response from the server has the instance. If the response for GET /api/person/13 is,
    {
        errors: [],
        message: "Saved Person successfully",
        result: {
            id: 3424243
            name: "john",
            age: 34
        }
    }

    the property which has the person object is result.

    • parseListProp: what property in response from the server has the list of instances. If the response for GET /api/person/ is,
    {
        errors: [],
        message: "Saved Person successfully",
        result: [
            {
                id: 3424243
                name: "john",
                age: 34
            },
            {
                id: 2423423
                name: "josh",
                age: 33
            }
        ]
    }

    the property which has the list of persons is result.

A sample settings object is,

{
  "idProp": "id",
  "url": "/api/v1/person",
  "parseInstanceProp": "result",
  "parseListProp": "result"
}

Returns

a JSON Model class which can be used to create instances.

const Person = new JSONModel(schema, settings);
const john = new Person({name: "john"});
john.age = 34;

save()

This function is available on an instance of JSON Model class like john above. The same method is used for create as well as update. The method decides to make a POST or PUT request based on presence of an ID value.

const Person = new JSONModel(schema, {"idProp": "id", ..});
const john = new Person({name: "john"});
console.log(john.id); // => undefined
const savePromise = john.save(); // makes a POST

john.age = 35;
console.log(john.id); // => 43543535 (some ID sent by server)
john.save(); // makes a PUT

find()

This function is available on the class itself like Person above. It can be used to either fetch an instance by ID or search params which will be turned to a query string.

const Person = new JSONModel(schema, settings);
const IDOfJohn = 324234234;
const john = await Person.find(IDOfJohn); // makes a GET /personAPI/324234234
// Use john instance like before

const someJohns = await Person.find({name: "john"}); // makes a GET /persnAPI?name=john

Each object in someJohns above is an instance of Person class and has access to save() and delete() methods.

delete()

This function is available on the instance objects. The API is still under development but is planned to make a DELETE REST request.

Contributing to the code

JSONModel is a nice abstraction which makes mundane tasks like validations and CRUD calls elegant and easy to use. There is still lot of interesting work to do listed below. Always happy to merge a pull request!

TODO

  • optional parseInstanceProp and parseListProp settings
  • validation of nested objects
  • delete API