achelous

0.0.2 • Public • Published

achelous

Generating a proper RESTful response, following hypermedia principles, can be a little tedious. Standards exist for HTML (HTML) and XML (AtomPub), which provide fairly complete hypermedia response. What is missing is equivalent guidance for JSON responses.

This API is a server-side API to make it easy to generate JSON based hypermedia responses that can be consumed by clients. The hypermedia specification I'm using is called Siren, so this API helps you generate Siren compatible JSON to return to clients.

Why Hypermedia? Hypermedia is the part of REST that allows the application state to be encapsulated in the server response. This is not the same thing as being a 'stateful' server. Rather, the client that requests a resource and from the server is returned a hypermedia response that encapsulates the state that maps to that request. State is really a client construct. It's up to the client to make appropriate state transitions based on the contents of the hypermedia response.

Take a web page as an example, if you navigate to a web page you are presented links, forms, and inline data that represents the current state. All the information you need to move to a next state (by following a link, for exmple), is provided in the HTML response. This is not what happens for many APIs (which often use JSON). It is up to the client to calculate the state transition based on some standard around URL formats.

For a more in depth description of HATEOAS (Hypermedia as the engine of application state), here are some useful resources:

There are two approaches to designing a hypermedia format. One is to use existing hypermedia definitions. For example, servers on the web use HTML as their preferred hypermedia format (text/html). Many sites use AtomPub as an alternative hypermedia format for server or clients that request data through an API (application/vnd.atom+xml). Another option is to define your own hypermedia format for a given format or client. Rather than coming up with DarcInc's format for JSON APIs, I chose the Siren format (application/vnd.siren+json).

About the name

Achelous is the father of sirens. In this sense it makes siren compliant JSON responses. This being an early version, the API is still in flux, but the goals are to provide easy, logical, and simplified generation of a siren compatible response instead of a blob of JSON.

For more information on Siren, here's the basic spec.

Overview

To begin a response:

var Achelous = require('achelous');
 
function getCustomer(req, res) {
    var result = new Achelous("customer", { firstName: "Joe", lastName: "Customer" });
    result.addEntity({ class: ["order" "collection"], rel: "http://foo.bar.com/orders",
        href: "http://myserver.com/api/orders");
    result.addLink("self", "http://myserver.com/api/customers/1234");
    result.addLink("account", "http://myserver.com/lookup/account.json?customer=1234");
    result.addLink("lastOrder", "http://myserver.com/api/customers/1234/orders?filter=last",
    res.set('Content-Type', 'application/vnd.siren+json');
    res.send(200, result);
}

The client receives:

{
   "class": ["customer"],
   "properties": {
       "firstName": "Joe",
       "lastName": "Customer"
   }
   "entities": [
       {
          "class": ["order", "collection"],
          "rel": "http://foo.bar.com/orders",
          "href": "http://myserver.com/api/orders"
       }
   ]
   "links": [
       { "rel": ["self"], "href": "http://myserver.com/api/customers/1234" },
       { "rel": ["account"], "href": "http://myserver.com/lookup/account.json&customer=1234" }
       { "rel": ["lastOrder"], "href": "http://myserver.com/api/customers/1234/orders?filter=last" }
   ]
}

Constructor

new Achelous(className);
new Achelous(className, properties);

The className is required and can be either a string, such as "customer" or an array of strings, such as ["customer", "commercial"]. The properties is a has of property values.

addEntity

The addEntity function adds information about entities tha are related to the entity in the response. For example, a URL returning customer information might have related 'order' entities. The addEntity function returns a reference to the main response, so that addEntity calls may be chained.

var achelous = new Achelous("customer");
achelous.addEntity(rel, href);
achelous.addEntity(entityObject);

The addEntity function takes either a string for the rel and href (both required) or an object with the entity attributes:

Attribute Required? Description
rel Yes How the entity is related to the response object.
href Yes The url of the related entity.
class No The class of the related entity.

It's possible to return a completed entity as a complete entity object.

Attribute Required? Description
rel Yes How the entity is related to the response object.
class No The class of the related entity (array)
properties No The properties of the related entity (hash)
entities No Entities related to this related entity
links No Any links applicable to this related entity
actions No Actions appropriate to this related entity
title No Descriptive title

makeEntity

While addEntity returns the root response object so that methods can be chained, makeEntity returns a reference to the newly created entity. It is inserted in the response object and allows you to

var response = new Achelous('foo', {bar: 'baz'});
 
var subEntity = response.makeEntity('qux', 'http://myserver.com/qux?id=1');
subEntity.addLink(...)
...
 

addAction

The addAction function adds a new action to the response entity. The action describes a templated link that could be invoked. It should carry enough information to allow the API client to deduce the parameters and operations. The addAction method returns a reference to the parent object so that methods can be chained.

var response = new Achelous('foo', {bar: 'baz'});
response.addAction(name, href);
response.addAction(actionObject);
Attribute Required? Description
name Yes The name of the action
href Yes The url for the action
title No A useful and friendly title
method No The HTTP method (defaults to 'GET')
type No The request type (defaults to 'application/x-www-form-urlencoded')
fields No The collection of fields

If provided, each field can contain the following attributes

Attribute Required? Description
name Yes The name of the field
type No Any of the HTML5 input types such as 'text' or 'number' (defaults to text)
value No A fixed value appropriate to the type
title No A friendly and useful human name for the field.

makeAction

This method is the same as addAction, except that instead of returning a reference to the containing object, it returns a reference to the new action.

action.addField

Adds a new field to an action. Fields describe to the client the expected parameters.

var response = new Achelous('foo', {bar: 'baz'});
var newAction = response.makeAction(name, href);
newAction.addField(name);
newAction.addField(name, type, value, title);
Parameter Required? Description
name Yes The name of the field.
type No The HTML5 input type of the field (defaults to "text")
value No A fixed value
title No A helpful and friendly title

addLink

The add link function adds a new link to the response or entity. It returns a reference to the parent object to allow method chaining.

var response = new Achelous('foo', {bar: 'baz'});
response.addLink(rel, href);
response.addLink(rel, href, title);
response.addLink(linkObject);

The parameters/attriburtes are:

Attribute Required? Description
rel Yes The relationship to the current resonse or entity
href Yes The URL of the related link
title No A useful title for the link

Revsion History

Version Description
0.0.0 Initial delivery - first draft of the API.

Readme

Keywords

Package Sidebar

Install

npm i achelous

Weekly Downloads

1

Version

0.0.2

License

MIT

Last publish

Collaborators

  • darcinc