mikekelly / hal-browser

An API browser for the hal+json media type
MIT License
835 stars 157 forks source link

= HAL-browser

An API browser for the hal+json media type

== Example Usage

Here is an example of a hal+json API using the browser:

http://haltalk.herokuapp.com/explorer/browser.html[http://haltalk.herokuapp.com/explorer/browser.html]

== About HAL

HAL is a format based on json that establishes conventions for representing links. For example:

[source,javascript]

{ "_links": { "self": { "href": "/orders" }, "next": { "href": "/orders?page=2" } } }

More detail about HAL can be found at http://stateless.co/hal_specification.html[http://stateless.co/hal_specification.html].

== Customizing the POST form

By default, the HAL Browser can't assume there is any metadata. When you click on the non-GET request button (to create a new resource), the user must enter the JSON document to submit. If your service includes metadata you can access, it's possible to plugin a custom view that makes use of it.

. Define your custom view. + Here is an example that leverages Spring Data REST's JSON Schema metadata found at /{entity}/schema. + [source,javascript]

var CustomPostForm = Backbone.View.extend({ initialize: function (opts) { this.href = opts.href.split('{')[0]; this.vent = opts.vent; _.bindAll(this, 'createNewResource'); },

events: {
    'submit form': 'createNewResource'
},

className: 'modal fade',

createNewResource: function (e) {
    e.preventDefault();

    var self = this;

    var data = {}
    Object.keys(this.schema.properties).forEach(function(property) {
        if (!("format" in self.schema.properties[property])) {
            data[property] = self.$('input[name=' + property + ']').val();
        }
    });

    var opts = {
        url: this.$('.url').val(),
        headers: HAL.parseHeaders(this.$('.headers').val()),
        method: this.$('.method').val(),
        data: JSON.stringify(data)
    };

    var request = HAL.client.request(opts);
    request.done(function (response) {
        self.vent.trigger('response', {resource: response, jqxhr: jqxhr});
    }).fail(function (response) {
        self.vent.trigger('fail-response', {jqxhr: jqxhr});
    }).always(function () {
        self.vent.trigger('response-headers', {jqxhr: jqxhr});
        window.location.hash = 'NON-GET:' + opts.url;
    });

    this.$el.modal('hide');
},

render: function (opts) {
    var headers = HAL.client.getHeaders();
    var headersString = '';

    _.each(headers, function (value, name) {
        headersString += name + ': ' + value + '\n';
    });

    var request = HAL.client.request({
        url: this.href + '/schema',
        method: 'GET'
    });

    var self = this;
    request.done(function (schema) {
        self.schema = schema;
        self.$el.html(self.template({
            href: self.href,
            schema: self.schema,
            user_defined_headers: headersString}));
        self.$el.modal();
    });

    return this;
},
template: _.template($('#dynamic-request-template').html())

});

+ . Register it by assigning to HAL.customPostForm + [source,javascript]

HAL.customPostForm = CustomPostForm;

+ . Load your custom JavaScript component and define your custom HTML template. + [source,html,indent=0]


NOTE: To load a custom JavaScript module AND a custom HTML template, you will probably need to create a customized version of browser.html.

NOTE: The HAL Browser uses a global HAL object, so there is no need to deal with JavaScript packages.

== Usage Instructions

All you should need to do is copy the files into your webroot. It is OK to put it in a subdirectory; it does not need to be in the root.

All the JS and CSS dependencies come included in the vendor directory.

== TODO