jsonapi-instance-store
v1.0.8
Published
JSON:API deserializer that is based on ES6 class, and stores the deserialized instances.
Downloads
10
Maintainers
Readme
jsonapi-instance-store
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
License
MIT