Rebolon / json-reviver

Pattern to restore json object/string into real Entities. Even nested entities can be restored as expected.
2 stars 1 forks source link

Json Reviver

FOSSA Status

[![Build Status](https://scrutinizer-ci.com/g/Rebolon/json-reviver/badges/build.png?b=master)](https://scrutinizer-ci.com/g/Rebolon/json-reviver/build-status/master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Rebolon/php-sf-flex-webpack-encore-vuejs/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/Rebolon/php-sf-flex-webpack-encore-vuejs/badges/quality-score.png?b=master) [![Known Vulnerabilities](https://snyk.io/test/github/rebolon/json-reviver/badge.svg?targetFile=package.json)](https://snyk.io/test/github/rebolon/json-reviver?targetFile=package.json)

When you work on a Frontend application with an API, you usually receive JSON string in HTTP. This is a pain to get back this JSON into real entities. And it's a worst pain when this JSON contain nested entities. This happens also when you try to restore JSON from LocalStorage !

So if you want to restore entities, with all their prototype, there is a lot to do. This is where this package can help you.

HowTo

Install the package npm install @rebolon/json-reviver --save For all required entities, just implements EntityInterface from this package (this is just for typings). Then write a Reviver for all required entities. This reviver must extends ItemAbstractReviver or ListAbstractReviver (for entities that are just an association between different entities).

eg:

// json object restored from localStorage or received from API call
{
    "book": {
        "title": "Zombies in western culture",
        "editors": [{
            "publicationDate": "1519664915",
            "collection": "printed version",
            "isbn": "9781783743230",
            "editor": {
                "name": "Open Book Publishers"
            }
        }, {
            "publicationDate": "1519747464",
            "collection": "ebooks",
            "isbn": "9791036500824",
            "editor": {
                "name": "Open Book Publishers"
            }
        }]
        "serie": {
            "name": "Open Reports Series"
        }
    }
}

// entities that represents a Book (for other entities look at tests/fixtures/entities folder
class Book implements EntityInterface {
    id: number
    title: string = ''
    description?: string = ''
    indexInSerie?: number

    editors: Array<Editors>
    serie?: Serie

    addEdition(edition: Editors) {
        if (typeof this.editors == 'undefined') {
            this.editors = []
        }

        this.editors.push(edition)
    }

    setEdition(edition: Editors) {
        this.editors = []

        this.editors.push(edition)
    }
}

// the reviver for the book
class BookReviver extends ItemAbstractReviver
{
    protected editorsReviver

    protected serieReviver

    constructor (
        editorsReviver: EditorsReviver,
        serieReviver: SerieReviver
    ) {
        super()

        this.editorsReviver = editorsReviver
        this.serieReviver = serieReviver
    }

    // The name of the node in the json string/object
    getNodeName(): string {
        return 'book'
    }

    // The entity for which the reviver works
    getNewEntity(): Object {
        return new Book()
    }

    // List of props (int, string, date, bool) of the entity
    public getEzPropsName()
    {
        return ['id', 'title', 'description', 'indexInSerie', ]
    }

    // List of props that links to other entities (relations Many To Many)
    // And configuration of how to restore them
    public getManyRelPropsName(): Object
    {
        return {
            'editors': {
                'reviver': this.editorsReviver,
                'setter': 'addEdition',
                'cb': function (relation, entity) {
                    Accessor('book', relation, entity)
                },
            },
        }
    }

    // List of props that links to other entities (relations Many To One)
    public getOneRelPropsName(): Object
    {
        return {
            'serie': {
                'reviver': this.serieReviver,
                'registryKey': 'serie',
            },
        }
    }
}

// In your application you just have to do this to restore the entities:
// those 3 are mandatory for nested entities: Book constructor require SerieReviver and EditorsReviver, and the EditorsReviver nees EditorReviver to restore its own editor sub entity (have a look at tests/fixtures/reviver/library)
const editorReviver = new EditorReviver()
const serieReviver = new SerieReviver()
const editorsReviver = new EditorsReviver(editorReviver)

const bookReviver = new BookReviver(editorsReviver, serieReviver)
const bookReviver = new BookReviver()
const book = bookReviver.main(myJsonStringOrObject)

// you can now use all feature of Book entity from your `book`  constant

You can also restore array of object like this (root node book is not mandatory):

[{
    "book": {
        "title": "Zombies in western culture"
    }
},
{   "book": {
         "title": "Another book with Zombies in western culture"
     }
 ]

Running unit tests

Run npm run test to execute the unit tests via Karma.

Npm publication

With typescript package it appears that .ts files should not be published (more info here:https://ljn.io/posts/publishing-typescript-projects-with-npm/). In fact we have to transpile .ts into javascript files. During this process we also need to generate module files (the famous .d.ts). Those files will be published and it will allow typescript compiler to use the .js file finely.

To do this:

Todo

License

FOSSA Status