npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

jsonapi-instance-store

v1.0.8

Published

JSON:API deserializer that is based on ES6 class, and stores the deserialized instances.

Downloads

10

Readme

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