hyperagent-forms.js is a hyperagent.js plugin for interacting with HAL Hypermedia Forms

hyperagent-forms.js Build Status Coverage Status

hyperagent-forms is a plugin for hyperagent.js adding support for a custom, unofficial form profile to HAL.

Installation

Download with bower or alternatively install manually.

bower install hyperagent-forms

Usage

Just configure hyperagent.js to run the plugin's load hook when a resource is loaded:

Hyperagent.configure('loadHooks', [HyperagentForms.LoadHook]);

Dependencies

There is optional support for [JSON Schema v4] validation through the Tiny Validator for JSON Schema v4 tv4. You only need to load it if you want to use validate, though.

Spec

There is no official support for write access in HAL at this time, but several discussions have been had around this topic. This library implements a custom schema, based on what has been proposed in those discussions.

Example

The following JSON response represents the entry point of https://rw-api.example.com and shall serve as an example for using hyperclient.

{
  "_links": {
    "self": {
      "href": "/"
    },
    "curies": [
      {
        "name": "ht",
        "href": "http://haltalk.herokuapp.com/rels/{rel}",
        "templated": true
      }
    ]
  },
  "_forms": {
    "ht:signup": {
      "href": "/signup",
      "method": "POST",
      "schema": {
        "$schema": "http://json-schema.org/draft-04/schema#",
        "description": "Create an account",
        "title": "signup",
        "required": [
          "username",
          "password"
        ],
        "type": "object",
        "properties": {
          "username": {
            "minLength": 1,
            "type": "string",
            "description": "The username you want to log in with."
          },
          "password": {
            "type": "string",
            "description": "The password you want to log in with."
          },
          "bio": {
            "type": "string",
            "description": "A short description of yourself."
          },
          "real_name": {
            "type": "string",
            "description": "The name you were born with."
          }
        }
      }
    }
  }
}

Forms

Forms are available as forms attribute on your Hyperagent Resource.

var api = Hyperagent.Resource('https://api-rw.example.com/');
api.fetch().then(function () {
  var signup = new api.forms['ht:signup']({ username: 'mkelly' });
  signup.data.username = 'overwrite';

  if (signup.validate()) {
    signup.submit();
  } else {
    console.error(signup.errors);
  }
});

Submitting this formular with the data { username: 'mkelly', password: 'ilikehal' } would cause an HTTP request similar to this to be sent:

POST /signup HTTP/1.1
Host: api-rw.example.com
...
Content-Type: application/json
Content-Size: xxx

{
  "username": "mkelly",
  "password": "ilikehal"
}

API

Resource#forms

When the plugin is loaded, a forms attribute is added to every loaded Resource instance and represents the form objects under the _forms key of the document. Forms are lazily constructed and can be accessed via name, CURIE or expanded URL.

assert.equal(api.forms['ht:signup'], api.forms['http://haltalk.herokuapp.com/rels/signup']);

The return value is a constructor for a Form class and also exposes a schema attribute that contains the raw JSON schema that can be accessed without instantiating the object.

buildFormFor(api.forms['ht:signup'].schema);

Form([data])

The constructor of Forms takes an an object containing the form values specified by the schema.

var form = new api.forms['ht:signup']({ username: 'passy', password: 'unicorns' });

The form can also be constructed without passing in data:

var form = new api.forms['delete']();

Form#data

The data passed into the constructor can be altered at any point through the data attribute:

var form = new api.forms['ht:signup']({ password: 'popsicles' });
form.data.username = 'newuser';
console.log(form.data.password);  // "popsicles"

Form#schema / Form.schema

If the form has a JSON schema, it can be accessed through the object or the class. This can be used to generate user interfaces based on the required inputs or own validations.

Form#submit()

Submits the data to the specified href. The data will be stringified as JSON and is passed as request body. The return value is a promise that contains a DelayedResource object both when resolved and rejected:

form.submit().then(function (result) {
  console.log('Status Code: ', result.xhr.statusCode);
  console.log('User name: ', result.loadResource().props.username);
}, function (error) {
  console.warn('Status Code: ', result.xhr.statusCode);
  console.warn('Error Message: ', result.loadResource().props.error);
});

DelayedResource

A delayed resource is wrapped in a promise returned from submit operation. It always contains the underlying XMLHttpRequest object as xhr attribute and has a loadResource() message that can be used to interpret the response text as HAL document.

License

Licensed under MIT