jsonapify is a library to assist the development of JSON-API compatible APIs with NodeJS.
You can see jsonapify in action in this repo.
Why jsonapify?jsonapify detaches mongoose models from the actual representation of the resources. This allows for a lot of flexibility: as a matter of fact, declaring a non-readable field is this elegant:
ES6 in actionvar User = require('../models/User');
Â
var userResource = new jsonapify.Resource(User, {
    type: 'users',
    id: new jsonapify.Property('_id'),
    attributes: {
        email: new jsonapify.Property('email'),
        password: {
            value: new jsonapify.Property('password'),
            readable: false,
        },
    },
});
Â
jsonapify.Runtime.addResource('User', userResource);
This is how the previous example would look in ES6:
Navigating resourcesimport {Property, Resource, Runtime} from 'jsonapify';
import User from '../models';
Â
const userResource = new Resource(User, {
    type: 'users',
    id: new Property('_id'),
    attributes: {
        email: new Property('email'),
        password: {
            value: new Property('password'),
            readable: false,
        },
    },
});
Â
Runtime.addResource('User', userResource);
HATEOAS is one of the most important principles of the REST phylosophy. jsonapify makes interconnecting your resources a piece of cake:
Linking resourcesvar User = require('../models/User');
Â
var userResource = new jsonapify.Resource(User, {
    type: 'users',
    id: new jsonapify.Property('_id'),
    links: {
        self: {
            value: new jsonapify.Template('/users/${_id}'),
            writable: false,
        },
    },
});
Â
jsonapify.Runtime.addResource('User', userResource);
As someone said, "nobody is an island". Resources are not islands either. Linking resources in jsonapify is as easy as you'd expect:
var User = require('../models/User');
var roleResource = require('./roles').resource;
Â
var userResource = new jsonapify.Resource(User, {
    type: 'users',
    id: new jsonapify.Property('_id'),
    relationships: {
        role: new jsonapify.Ref('Role', 'role'),
    },
});
Â
jsonapify.Runtime.addResource('User', userResource);
Note: related resources are not subresources. Subresources are resource-like objects so tightly linked to their parent resource that they can't exist on their own. jsonapify does not support access of related resources as subresources. This is by-design.
Exposing resourcesWe all know about DRY. But then, why do we keep writing the same endpoint boilerplate again and again? jsonapify offers all CRUD operations as connect-compatible middleware. That means plugging a new endpoint is as simple as it gets:
Middleware and resource addressingapp.get('/users/', [
    jsonapify.enumerate('User'),
    jsonapify.errorHandler()
]);
Everything in REST is a resource. Resources can have subresources, too. That means that you can apply a READ operation (GET verb in REST terms) to a subresource. Let's see how resource addressing works in jsonapify.
jsonapify.param(...)
jsonapify.query(...)
jsonapify.parent(...)
For example, a READ operation with the following resource chain, directed to the URI '/groups/{group}/users/{user}', would retrieve a resource object of type 'User', with group == parent._id and name == user
, where parent
is the group the user logically belongs to:
 [
    'UserGroup', {
        name: jsonapify.param('group'),
    },
    'User', {
        group: jsonapify.parent('_id'),
        name: jsonapify.param('user'),
    },
]
On the other hand, a CREATE operation with the following resource chain, directed to the same URI, would store a resource object of type 'User', with group == parent._id
and the rest of the properties from the request body:
 [
    'UserGroup', {
        name: jsonapify.param('group'),
    },
    'User', {
        group: jsonapify.parent('_id'),
    },
]
Note: While jsonapify subresource addressing is already functional, it is not polished enough to be considered production-ready (think of error reporting, usability...) If you ever encounter a bug, please file an issue and it will get assigned a high priority.
Transaction filtersIn addition to all of the above, jsonapify also offers transaction filters. These filters enable per-request functionality, such as pagination, sparse-fields, sorting... The most common transaction filters are enabled by default, so you don't have to worry.
CreditsThis library wouldn't have been possible without all the great work by the people of the JSON-API specification. Thank you guys, you're awesome!
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4