Giter Club home page Giter Club logo

kokua's Introduction

Kōkua - Hypermedia Representor

Kōkua (Hawaiian) - help, aid, assistance

NPM Version Build Test Coverage

Kōkua is an implementation of the Representor pattern, written in modern Javascript/Node. It allows developers to represent hypermedia messages in a flexible media type, purpose-designed for the task: Hyper and automatically outputs messages in a variety of popular Hypermedia formats such as:

  1. HAL (application/hal+json)
  2. Siren (application/vnd.siren+json)
  3. Collection+JSON (application/vnd.collection+json)
  4. UBER (application/vnd.uber+json)
  5. JSON API (application/vnd.api+json)
  6. etc.

Usage

Convert a Hyper document to other formats

  const kokua = require("kokua");
  let halDoc = kokua(hyperDoc, kokua.mt('hal'));

where the first argument to a kokua() call is a JSON document formatted as a Hyper document, and the second argument is the name of a supported media-type that we want the message to be translated to.

Convert a document in another format to Hyper

  const kokua = require("kokua");
  let uberDoc = kokua.parse(halDoc, kokua.mt('hal'));

where the first argument to a kokua.parse() call is a JSON document formatted in a media type, supported by Kokua, and the second argument is the name of a supported media-type that we want the message to be translated from.

Please see the official specification for Hyper media type, for more details about the format.

Advanced Example

  const hyperDoc = const hyper = {
    "h:head": {"curies": {"ea": "http://example.com/docs/rels/"}},
    "h:ref": {"self": "/orders", "next": "/orders?page=2"},
    "currentlyProcessing": 14, "shippedToday": 20,
    "ea:order": [
      {
        "h:ref": {
          "self": "/orders/123",
          "ea:basket": "/baskets/98712",
          "ea:customer": "/customers/7809"
        },
        "total": 30, "currency": "USD", "status": "shipped"
      },
      {
        "h:ref": {
          "self": "/orders/123",
          "ea:basket": "/baskets/98712",
          "ea:customer": "/customers/124234"
        },
        "total": 123, "currency": "USD", "status": "pending"
      }
    ]
  };

  const kokua = require("kokua");
  let halDoc = kokua(hyperDoc, kokua.mt('hal'));
  let sirenDoc = kokua(hyperDoc, kokua.mt('siren'));

Implementation Status

  1. Hyper to HAL: 100%
    • Reverse: 0%
  2. Hyper to Siren: 100%
    • Reverse: 100%
  3. Hyper to UBER: 0%
    • Reverse: 0%
  4. Hyper to Collection+JSON: 0%
    • Reverse: 0%
  5. Hyper to JSONAPI: 0%
    • Reverse: 0%

Quick-n-dirty benchmark

> node benchmark.js
Time to convert HAL 10,000 times:  2.572 ms
Time to convert Siren 10,000 times:  1.42 ms

Plugin Development

If you are interested in developing a new plugin to implement translation to a hypermedia format that is not yet implemented, please refer to README-PLUGINDEV

kokua's People

Contributors

inadarei avatar snyk-bot avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

justinbach

kokua's Issues

Handle null values gracefully

Currently, using an input with a property mapped to a null value throws an error.

Running this code

const kokua = require('kokua');

const data = {
  foo: null,
};

kokua(data, kokua.mt('hal'));

results in this error being thrown:

/node_modules/kokua/lib/plugins/hal.js:148
          if (curr["h:ref"] || curr["h:link"]) {
                  ^

TypeError: Cannot read property 'h:ref' of null

Embedded resources in HAL fixture?

According to the HAL specification, the root object of a HAL document is a Resource Object. Resource Objects consist of JSON that represents the state of a particular resource, and have two reserved properties: _links and _embedded. The _embedded property may contain one or more objects that are recursively interpreted as Resources; just like the root object, these resources contain JSON representing state and, optionally, nested _links and _embedded properties.

The HAL fixture in this repo contains two different embedded documents. There's one at the top level:

"_embedded": {
"ea:order": [
{
"_links": {
"self": {"href": "/orders/123"},
"ea:basket": {"href": "/baskets/98712"},
"ea:customer": {"href": "/customers/7809"}
},
"total": 30,
"currency": "USD",
"status": "shipped"
},
{
"_links": {
"self": {"href": "/orders/124"},
"ea:basket": {"href": "/baskets/97213"},
"ea:customer": {"href": "/customers/12369"}
},
"total": 20,
"currency": "USD",
"status": "processing"
}
],
"comments": {"_links": {"ea:comments": {"href": "/comments/23423424"}}}
}

And one nested inside of a top-level sales property:

"sales": {
"_embedded": {
"agents": [
{
"name": "Foster Okuneva",
"_links": {"about": {"href": "http://api.x.io/u/1234"}}
},
{
"name": "Albin Osinski",
"_links": {"about": {"href": "http://api.x.io/u/5678"}}
}
],
"department": {
"name": "Lorem Ipsum",
"_links": {
"about": {"href": "http://api.x.io/dep/28374/"},
"ea:revenue": {"href": "http://api.x.io/rev/3233", "title": "Revenue"}
}
}
}
},

I can't find anything in the spec that describes or permits nesting of _embedded resources outside of the top level in the way that the fixture nests _embedded resources inside of sales. There's no precedent for it in the example document, and the Resource Object definition says that all non-reserved properties must be valid JSON representing the current state of the Resource.

Based on the HAL spec, it seems that only values mapped by a top-level _embedded property should be recursively interpreted as HAL documents, and that all other top-level fields (like sales, currentlyProcessing, and shippedToday) should be treated as JSON representing resource state, and not subjected to further HAL-specific semantics. This distinction has implications for the plugins that convert Hyper to HAL and back; specifically, processing the fixture in its current form requires recursive analysis of every property of the HAL document to check whether it contains any embedded documents, whereas the spec implies that the check only needs to be done when processing Resources (i.e. the root object or any objects mapped to by the _embedded property of a Resource).

Is there some other resource or specification that permits this kind of embedded document nesting, or does the fixture deviate from the spec?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.