1.0.8 • Published 5 years ago

jsonapi-instance-store v1.0.8

Weekly downloads
3
License
MIT
Repository
github
Last release
5 years ago

jsonapi-instance-store

MIT License npm version codecov CircleCI
Deserializes JSON API, and stores the instances.

Why?

  • :rocket:Easy To Use:
    • no configuration
    • framework agnostic
  • :star2:Featured:
    • ES6 class based deserialization
    • synced relationships
    • customizable deserializer
  • :sunglasses:Reliable:
    • written in TypeScript
    • tested with CI

Getting Started

// class in TypeScript
class Dog {
  id: string;

  age: string;

  // Of course, you can define instance method.
  get numAge(): number {
    return Number(this.age);
  }
}

// or in JavaScript(you do not have to declare instance properties).
class Dog {
  get numAge() {
    return Number(this.age);
  }
}

class Cat {
  id: string;

  friend: Dog;
}

const catResponseWithRelationships = {
  data: {
    type: "cats",
    id: "1",
    relationships: {
      friend: {
        data: {
          type: "dogs",
          id: "3"
        }
      }
    }
  },
  included: [
    {
      type: "dogs",
      id: "3",
      attributes: {
        age: "2"
      }
    }
  ]
};
import store from 'jsonapi-instance-store';

store.define(Dog);
store.define(Cat);

const cat = store.read(catResponseWithRelationships);

console.log(cat instanceof Cat); // => true
console.log(cat.id); // => "1"
console.log(cat.friend instanceof Dog); // => true
console.log(cat.friend.id); // => "3"
console.log(cat.friend.age); // => "2"

note
The class name should correspod to the "type" of JSON API.
Whether type is single or plural, and the case of type do not matter.

note
In TypeScript, your editor's static analysis cannot know the class of the deserialized instances as it is defined dynamically.
So you should use type assertion to use static analysis.

Usage

Deserialize

sync relationships

const catResponseWithNoIncluded = {
  data: {
    type: "cats",
    id: "1",
    relationships: {
      friend: {
        data: {
          type: "dogs",
          id: "1"
        }
      }
    }
  }
};

const dogResponse = {
  data: {
    type: "dog",
    id: "1",
    attributes: {
      age: "2"
    }
  }
};
// deserialize record with no "included"
const catWithNoIncluded = store.read(catResponseWithNoIncluded);

// cat.friend has no attributes
console.log(catWithNoIncluded.friend.age); // => undefined

// read a response corresponding to cat.friend
store.read(dogsResponse)

// now, cat.friend has its attributes!
console.log(catWithNoIncluded.friend.age); // => "2"

append another instances to an existing result

const dogsResponse = {
  data: [
    {
      type: "dog",
      id: "1",
      attributes: {
        age: "2"
      }
    },
    {
      type: "dog",
      id: "2",
      attributes: {
        age: "3"
      }
    }
  ]
};

const anoutherDogsResponse = {
  data: [
    {
      type: "dog",
      id: "10",
      attributes: {
        age: "4"
      }
    },
    {
      type: "dog",
      id: "11",
      attributes: {
        age: "5"
      }
    }
  ]
};
const multipleDogs = store.read(dogsResponse);

// append another instances to the existing result
store.append(multipleDogs, anotherDogResponse);

console.log(multipleDogs.length); // => 4
console.log(multipleDogs[multipleDogs.length - 1].id); // => "11"
console.log(multipleDogs[multipleDogs.length - 1].age); // => "5"

note
As the second argument, you can also pass a payload containing single recored.

case of the attributes key does not matter

export class Person {
  id: string;

  firstName: string;

  lastName: string;
}

const personResponseInSnake = {
  data: {
    type: "person",
    id: "1",
    attributes: {
      first_name: "John",
      last_name: "Doe"
    }
  }
};

const personResponseInCamel = {
  data: {
    type: "person",
    id: "1",
    attributes: {
      firstName: "John",
      lastName: "Doe"
    }
  }
};
import store from 'jsonapi-instance-store';

store.define(Person);

// deserialize JSON API with snake cased attributes
const person1 = store.read(personResponseInSnake);

console.log(person1.firstName); // => "John"

// deserialize JSON API with camel cased attributes
const person2 = store.read(personResponseInCamel);

console.log(person2.firstName); // => "John"

Store

class Dog {
  id: string;

  age: string;
}

const dogsResponse = {
  data: [
    {
      type: "dog",
      id: "1",
      attributes: {
        age: "2"
      }
    },
    {
      type: "dog",
      id: "2",
      attributes: {
        age: "3"
      }
    }
  ]
};
import store from 'jsonapi-instance-store';

store.define(Dog);

store.read(dogsResponse);

// find
console.log(store.find("dog", "1").id); => "1"
console.log(store.find("dogs", "1").id); => "1"
console.log(store.find("dog", 1).id); => "1"

// findAll
const dogs = store.findAll("dog");

console.log(dogs instanceof Array); => true
console.log(dogs.length) => 2

// destroy
const dog = store.find("dog", "1")
store.destroy(dog);
console.log(store.find("dog", "1")); => undefined
console.log(store.findAll("dog").length); => 1

// reset
store.reset();
console.log(store.findAll("dog").length); => 0

Custom Deserializer

You can use your own deserializer. A sample implementation is JsonApiDeserializer.ts

import CustomDeserializer from "path/to/custom/deserializer";
import { Store } from "jsonapi-instance-store";
const store = new Store();
store.deserializer = new CustomDeserializer(store);
store.read(payload);

Contributing

Contribution Guide

License

MIT

1.0.8

5 years ago

1.0.7

5 years ago

1.0.6

5 years ago

1.0.5

5 years ago

1.0.4

5 years ago

1.0.3

5 years ago

1.0.2

5 years ago

1.0.1

5 years ago