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

@dinevillar/json-api-serializer

v1.11.0

Published

Framework agnostic JSON API serializer.

Downloads

2

Readme

json-api-serializer

Build Status Coverage Status npm

A Node.js framework agnostic library for serializing your data to JSON API compliant responses (a specification for building APIs in JSON).

Why another library for serializing data to JSON API ?

Simply because others libraries are not as flexible as i need.

Installation

npm install --save json-api-serializer

Documentation

Register

var JSONAPISerializer = require('json-api-serializer');
var Serializer = new JSONAPISerializer();
Serializer.register(type, options);

Serialization options:

  • id (optional): The key to use as the reference. Default = 'id'.
  • blacklist (optional): An array of blacklisted attributes. Default = [].
  • whitelist (optional): An array of whitelisted attributes. Default = [].
  • links (optional): Describes the links inside data. It can be:
    • An object (values can be string or function).
    • A function with one argument function(data) { ... } or with two arguments function(data, extraData) { ... }
  • topLevelMeta (optional): Describes the top-level meta. It can be:
    • An object (values can be string or function).
    • A function with one argument function(extraData) { ... } or with two arguments function(data, extraData) { ... }
  • topLevelLinks (optional): Describes the top-level links. It can be:
    • An object (values can be string or function).
    • A function with one argument function(extraData) { ... } or with two arguments function(data, extraData) { ... }
  • relationships (optional): An object defining some relationships
    • relationship: The property in data to use as a relationship
      • type: The type to use for serializing the relationship (type need to be register)
      • alternativeKey (optional): An alternative key (string or path) to use if relationship key not exist (example: 'author_id' as an alternative key for 'author' relationship). See issue #12.
      • schema (optional): A custom schema for serializing the relationship. If no schema define, it use the default one.
      • links (optional): Describes the links for the relationship. It can be:
        • An object (values can be string or function).
        • A function with one argument function(data) { ... } or with two arguments function(data, extraData) { ... }
      • meta (optional): Describes meta that contains non-standard meta-information about the relationship. It can be:
        • An object (values can be string or function).
        • A function with one argument function(data) { ... } or with two arguments function(data, extraData) { ... }
  • convertCase (optional): Case conversion for serializing data. Value can be : kebab-case, snake_case, camelCase

Deserialization options:

  • unconvertCase (optional): Case conversion for deserializing data. Value can be : kebab-case, snake_case, camelCase
  • blacklistOnDeserialize (optional): An array of blacklisted attributes. Default = [].
  • whitelistOnDeserialize (optional): An array of whitelisted attributes. Default = [].

Global options:

To avoid repeating the same options for each type, it's possible to add global options on JSONAPISerializer instance:

var JSONAPISerializer = require('json-api-serializer');
var Serializer = new JSONAPISerializer({
  convertCase: 'kebab-case',
  unconvertCase: 'camelCase'
});

Usage

input data (can be an object or an array of objects)

// Data
var data = [{
  id: "1",
  title: "JSON API paints my bikeshed!",
  body: "The shortest article. Ever.",
  created: "2015-05-22T14:56:29.000Z",
  updated: "2015-05-22T14:56:28.000Z",
  author: {
    id: "1",
    firstName: "Kaley",
    lastName: "Maggio",
    email: "[email protected]",
    age: "80",
    gender: "male"
  },
  tags: ["1", "2"],
  photos: ["ed70cf44-9a34-4878-84e6-0c0e4a450cfe", "24ba3666-a593-498c-9f5d-55a4ee08c72e", "f386492d-df61-4573-b4e3-54f6f5d08acf"],
  comments: [{
    _id: "1",
    body: "First !",
    created: "2015-08-14T18:42:16.475Z"
  }, {
    _id: "2",
    body: "I Like !",
    created: "2015-09-14T18:42:12.475Z"
  }, {
    _id: "3",
    body: "Awesome",
    created: "2015-09-15T18:42:12.475Z"
  }]
}]

Register

Register your resources types :

var JSONAPISerializer = require('json-api-serializer');
var Serializer = new JSONAPISerializer();

// Register 'article' type
Serializer.register('article', {
  id: 'id', // The attributes to use as the reference. Default = 'id'.
  blacklist: ['updated'], // An array of blacklisted attributes. Default = []
  links: { // An object or a function that describes links.
    self: function(data) { // Can be a function or a string value ex: { self: '/articles/1'}
      return '/articles/' + data.id;
    }
  },
  relationships: { // An object defining some relationships.
    author: {
      type: 'people', // The type of the resource
      links: function(data) { // An object or a function that describes Relationships links
        return {
          self: '/articles/' + data.id + '/relationships/author',
          related: '/articles/' + data.id + '/author'
        }
      },
    },
    tags: {
      type: 'tag'
    },
    photos: {
      type: 'photo'
    },
    comments: {
      type: 'comment',
      schema: 'only-body' // A custom schema
    }
  },
  topLevelMeta: function(data, extraData) { // An object or a function that describes top level meta.
    return {
      count: extraData.count,
      total: data.length
    }
  },
  topLevelLinks: { // An object or a function that describes top level links.
    self: '/articles' // Can be a function (with extra data argument) or a string value
  }
});

// Register 'people' type
Serializer.register('people', {
  id: 'id',
  links: {
    self: function(data) {
      return '/peoples/' + data.id;
    }
  }
});

// Register 'tag' type
Serializer.register('tag', {
  id: 'id',
});

// Register 'photo' type
Serializer.register('photo', {
  id: 'id',
});

// Register 'comment' type with a custom schema
Serializer.register('comment', 'only-body', {
  id: '_id',
});

Serialize

Serialize it with the corresponding resource type, data and optional extra data :

// Synchronously (blocking)
const result = Serializer.serialize('article', data, {count: 2});

// Asynchronously (non-blocking)
Serializer.serializeAsync('article', data, {count: 2})
  .then((result) => {
    ...
  });

The output data will be :

{
  "jsonapi": {
    "version": "1.0"
  },
  "meta": {
    "count": 2,
    "total": 1
  },
  "links": {
    "self": "/articles"
  },
  "data": [{
    "type": "article",
    "id": "1",
    "attributes": {
      "title": "JSON API paints my bikeshed!",
      "body": "The shortest article. Ever.",
      "created": "2015-05-22T14:56:29.000Z"
    },
    "relationships": {
      "author": {
        "data": {
          "type": "people",
          "id": "1"
        },
        "links": {
          "self": "/articles/1/relationships/author",
          "related": "/articles/1/author"
        }
      },
      "tags": {
        "data": [{
          "type": "tag",
          "id": "1"
        }, {
          "type": "tag",
          "id": "2"
        }]
      },
      "photos": {
        "data": [{
          "type": "photo",
          "id": "ed70cf44-9a34-4878-84e6-0c0e4a450cfe"
        }, {
          "type": "photo",
          "id": "24ba3666-a593-498c-9f5d-55a4ee08c72e"
        }, {
          "type": "photo",
          "id": "f386492d-df61-4573-b4e3-54f6f5d08acf"
        }]
      },
      "comments": {
        "data": [{
          "type": "comment",
          "id": "1"
        }, {
          "type": "comment",
          "id": "2"
        }, {
          "type": "comment",
          "id": "3"
        }]
      }
    },
    "links": {
      "self": "/articles/1"
    }
  }],
  "included": [{
    "type": "people",
    "id": "1",
    "attributes": {
      "firstName": "Kaley",
      "lastName": "Maggio",
      "email": "[email protected]",
      "age": "80",
      "gender": "male"
    },
    "links": {
      "self": "/peoples/1"
    }
  }, {
    "type": "comment",
    "id": "1",
    "attributes": {
      "body": "First !"
    }
  }, {
    "type": "comment",
    "id": "2",
    "attributes": {
      "body": "I Like !"
    }
  }, {
    "type": "comment",
    "id": "3",
    "attributes": {
      "body": "Awesome"
    }
  }]
}

Some others examples are available in tests folders

Deserialize

input data (can be an simple object or an array of objects)

var data = {
  data: {
    type: 'article',
    id: '1',
    attributes: {
      title: 'JSON API paints my bikeshed!',
      body: 'The shortest article. Ever.',
      created: '2015-05-22T14:56:29.000Z'
    },
    relationships: {
      author: {
        data: {
          type: 'people',
          id: '1'
        }
      },
      comments: {
        data: [{
          type: 'comment',
          id: '1'
        }, {
          type: 'comment',
          id: '2'
        }]
      }
    }
  }
};

Serializer.deserialize('article', data);
{
  "id": "1",
  "title": "JSON API paints my bikeshed!",
  "body": "The shortest article. Ever.",
  "created": "2015-05-22T14:56:29.000Z",
  "author": "1",
  "comments": [
    "1",
    "2"
  ]
}

Custom schemas

It is possible to define multiple custom schemas for a resource type :

Serializer.register(type, 'customSchema', options);

Then you can apply this schema on the primary data when serialize or deserialize :

Serializer.serialize('article', data, 'customSchema', {count: 2});
Serializer.serializeAsync('article', data, 'customSchema', {count: 2});
Serializer.deserialize('article', jsonapiData, 'customSchema');

Or if you want to apply this schema on a relationship data, define this schema on relationships options with the key schema :

Example :

relationships: {
  comments: {
    type: 'comment'
    schema: 'customSchema'
  }
}

Mixed data (dynamic type)

Serialize

If your data contains one or multiple objects of different types, it's possible to define a configuration object instead of the type-string as the first argument of serialize and serializeAsync with these options:

  • type (required): A string for the path to the key to use to determine type or a function deriving a type-string from each data-item.
  • topLevelMeta (optional): Describes the top-level meta. It can be:
    • An object (values can be string or function).
    • A function with one argument function(extraData) { ... } or with two arguments function(data, extraData) { ... }
  • topLevelLinks (optional): Describes the top-level links. It can be:
    • An object (values can be string or function).
    • A function with one argument function(extraData) { ... } or with two arguments function(data, extraData) { ... }

Example :

const typeConfig = {
  // Same as type: 'type'
  type: (data) => data.type, // Can be very complex to determine different types of items.
};

Serializer.serializeAsync(typeConfig, data, {count: 2})
  .then((result) => {
    // ...
  });

Deserialize

If your data contains one or multiple objects of different types, it's possible to define a configuration object instead of the type-string as the first argument of deserialize with these options:

  • type (required): A string for the path to the key to use to determine type or a function deriving a type-string from each data-item.

Example :

const typeConfig = {
  // Same as type: 'type'
  type: (data) => data.type, // Can be very complex to determine different types of items.
};

const deserialized = Serializer.deserialize(typeConfig, data);

Requirements

json-api-serializer only use ECMAScript 2015 (ES6) features supported natively by Node.js 4 and above (ECMAScript 2015 (ES6) | Node.js). Make sure that you have Node.js 4+ or above.

License

MIT