<header class="jumbotron subhead well" id="overview"> <div class="row"> <div class="span7"> <h1 style="font-size: 380%;font-family: Audiowide;border: 0">Hybind</h1> <p class="lead">Binds JavaScript objects to HAL hypermedia REST APIs</p> <div class="row"> <div class="span2"><a href="#jQuery">jQuery</a></div> <div class="span2"><a href="#AngularJS_1_x">AngularJS</a></div> <div class="span2"><a href="#Node_js">Node.js</a></div> </div> </div> <div class="span3 offset1"> <div> <div class="pull-left" style="padding-right: 1em;"> <a href="https://github.com/lbovet/hybind"><img src="github.png" style="width: 24px;"> Source Code</a> </div> <div class="clearfix"> <a href="https://travis-ci.org/lbovet/hybind"><img src="https://travis-ci.org/lbovet/hybind.svg?branch=master"></a> </div> <div class="clearfix"> <a href="https://www.npmjs.com/package/hybind"><img src="https://img.shields.io/npm/v/hybind.svg?maxAge=2592000"></a> </div> <div class="clearfix"> <a href="https://github.com/lbovet/hybind/blob/master/LICENSE"><img src="https://img.shields.io/github/license/lbovet/hybind.svg?maxAge=2592000"></a> </div> </div> </div> </div> </header> <div class="row"> <div class="span10"> <div class="placeholder"></div> </div> <div class="span2"> <div id="TOC"></div> </div> </div> ## Overview Unlike most [client libraries](https://github.com/mikekelly/hal_specification/wiki/Libraries#javascript) dealing with [HAL REST APIs](http://stateless.co/hal_specification.html), Hybind provides a high-level approach similar to what Object Relational Mapping (ORM) frameworks are for databases. When using [Spring Data REST](http://projects.spring.io/spring-data-rest/) in the server, it is amazing how the amount of code to write is reduced to a minimum. However, a significant amount of repeated boilerplate is still required in the JavaScript client to manipulate the resources and map them to the client-side model. That's why this library exists. It enriches plain JavaScript objects with a convenient API so that performing REST requests is as easy as calling methods directly on the model objects. It is optimized for Spring Data REST, but should work with other HAL APIs following similar conventions. Have a look at the [BugTik](https://github.com/lbovet/bugtik) sample application written with AngularJS and Spring Data Rest. ## Getting Started Hybind requires either jQuery, AngularJS or Node.js. ### jQuery ```html <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script> <script src="https://unpkg.com/hybind@latest/index.js"></script> ``` - Without AMD, a global [`hybind`](#hybind) function is created. Just make sure to include jQuery before Hybind. - With AMD, it defines a module depending on the `jquery` module. ### AngularJS 1.x ```html <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script> <script src="https://unpkg.com/hybind@latest/index.js"></script> ``` AngularJS is automatically detected and a `hybind` module containing a [`hybind`](#hybind) service is registered. You can then inject it in your code at will: ```javascript angular .module('App', ['hybind']) .controller('AppCtrl', ['hybind', function (hybind) { ... }]); ``` ### Node.js The `hybind` npm module provides the [`hybind`](#hybind) function. ``` $ npm install hybind --save ``` ```javascript hybind = require("hybind"); ``` ### Framework Details Hybind will use a different implementation for HTTP requests and promises according to the framework you chose. | Framework | HTTP | Promises | |---|---| | jQuery | [$.ajax](http://api.jquery.com/jquery.ajax/) | [$.Deferred](https://api.jquery.com/category/deferred-object/) | | AngularJS | [$http](https://docs.angularjs.org/api/ng/service/$http#usage) | [$q](https://docs.angularjs.org/api/ng/service/$q) | | Node.js | [najax](https://www.npmjs.com/package/najax)| [q](https://www.npmjs.com/package/q) | ## Reference Bound objects are enriched with the following methods: | Method | Description | HTTP Request | |--------|-------------|--------------| | [`$bind`](#_bind) | Binds a child resource | - | | [`$load`](#_load) | Fetches the resource data ands updates the bound object | GET | | [`$save`](#_save) | Updates the bound resource with the object data | PUT | | [`$create`](#_create) | Creates a child resource | POST | | [`$delete`](#_delete) | Deletes a resource | DELETE | | [`$set`](#_set) | Creates or updates a resource association | POST | | [`$add`](#_add) | Adds children to a resource collection | POST | | [`$remove`](#_remove) | Deletes an association | DELETE | | [`$share`](#_share) | Keeps objects in a shared cache to avoid loading them multiple times | - | | Property | Description | |--------|-------------| | [`$resource`](#_resource) | After `$load`, contains the original resource of collections | ### hybind This is the entry point of the library. <spec>**hybind**(pathOrUrl:_string_) : _Object_</spec> Creates the API root object and binds it to the root of the REST API specified by `pathOrUrl`. In the browser, it can be a path computed relatively to the current page. Returns the newly created API root object. <spec>**hybind**(pathOrUrl:_string_, defaults:_Object_) : _Object_</spec> Same as above but also customizes the default properties of the object passed to the underlying HTTP library when performing requests. This allows to customize headers and other transport-level configuration globally for all resources of this API. See their respective documentation under [Framework Details](#Framework_Details). ### $bind Binds a child resource. <spec>obj.**$bind**(name:_string_) : _Object_</spec> Binds a property of `obj` with the given name to a child resource having its sub-path computed by appending the property name to `obj`'s URL. If the property does not exist, it is created as a new empty object. If it exists, it can be an object or an array. An array means that the resource corresponds to a collection. Returns the child object. <spec>obj.**$bind**(name:_string_, child:_Object_|_Array_) : _Object_</spec> Binds and sets an existing `child` object or array as a property of `obj`. If `obj[name]` was not previously bound (e.g. via [`$load`](#_load)), then the child resource sub-path is given by `name`, otherwise it will reuse the previously bound resource URL so that links are followed in a pure HATEOAS way. Passing an array means that the resource corresponds to a collection. Returns the child object/array. <spec>obj.**$bind**(child:_Object_, idFn: _Function_) : _Object_</spec> Binds and sets an existing `child` object as a property of `obj`. The property name and child resource sub-path is computed by the `idFn` function applied to the child object. Returns the child object. ### $load Fetches the resource data and fills the object with it. It also binds linked resources as properties so that links can be followed in a pure HATEOAS way. <spec>objOrArr.**$load**() : _Promise&lt;Object>_</spec> Performs a GET request to retrieve the data of the bound resource and fill `objOrArr`. If `objOrArr` is an array, it is expected that the resource is a collection and its representation contains the collection items in the `_embedded` property. Also, a `$resource` property will be added to `objOrArr` with the loaded resource content without the `_embedded` property. `objectOrArr` will be emptied before being filled in case it was not an empty object or array. Returns a promise resolved to `objOrArray` after being filled. The promise is rejected in case of error with the same parameters as the promise returned by the underlying HTTP implementation. <spec>objOrArr.**$load**(parameters:_Object_, [opts:_Object_]) : _Promise&lt;Object>_</spec> Same as above but with * An object specifying URL parameters to pass in the query string. Can be null. * Options object to be passed to the underlying HTTP implementation, it can contains headers or other transport-level (see [Framework Details](#Framework_Details)). It extends/overrides the `defaults` object that can set by the [`hybind`](#hybind) function. ### $save Updates the bound resource with the object data or updates a collection content. <spec>obj.**$save**() : _Promise&lt;Object>_</spec> Performs a PUT request to create/update the bound resource with the content of `obj`. According to the REST API conventions, this can be used to create the resource if it does not exist. Otherwise, use [`$create`](#_create). Returns a promise resolving to `obj` in case of success. The promise is rejected in case of error with the same parameters as the promise returned by the underlying HTTP implementation. <spec>obj.**$save**([properties:_Array&lt;string>_]) : _Promise&lt;Object>_</spec> Same as above but also saves in the same request the specified associations, provided they are set to bound objects. This assumes that the REST API supports receiving inline links in the JSON payload as Spring Data Rest does. If the `properties` array is empty, it saves _all_ properties. <spec>arr.**$save**() : _Promise&lt;Object>_</spec> Performs a PUT request to create/update the collection content assuming that the REST API supports it the same way as Spring Data Rest [does](http://docs.spring.io/spring-data/rest/docs/current/reference/html/#repository-resources.association-resource). This resets the collection to contain all resources corresponding to the items of `arr`. The ordering is respected. Returns a promise resolving to `arr` in case of success. The promise is rejected in case of error with the same parameters as the promise returned by the underlying HTTP implementation. <spec>objOrArr.**$save**(parameters:_Object_, [opts:_Object_], [properties:_Array&lt;string>_]) : _Promise&lt;Object>_</spec> Same as above but with * An object specifying URL parameters to pass in the query string. Can be null. * Options object to be passed to the underlying HTTP implementation, it can contains headers or other transport-level (see [Framework Details](#Framework_Details)). It extends/overrides the `defaults` object that can set by the [`hybind`](#hybind) function. ### $create Creates a child resource. <spec>objOrArr.**$create**([child:_Object_]) : _Promise&lt;Object>_</spec> Performs a POST request to create a collection item or child resource. This assumes that the REST API supports this way of creating objects and returns the created resource in the response. If no `child` is given, it will default to an empty object. It will also create associations in the same request if properties are set to bound objects. This assumes that the REST API supports receiving inline links in the JSON payload as Spring Data Rest does. This does _not_ modify `objOrArr`, it only creates the resource in the server. Returns a promise resolving to the created object. The promise is rejected in case of error with the same parameters as the promise returned by the underlying HTTP implementation. <spec>objOrArr.**$create**(child:_Object_, parameters:_Object_, [opts:_Object_]) : _Promise&lt;Object>_</spec> Same as above but with * An object specifying URL parameters to pass in the query string. Can be null. * Options object to be passed to the underlying HTTP implementation, it can contains headers or other transport-level (see [Framework Details](#Framework_Details)). It extends/overrides the `defaults` object that can set by the [`hybind`](#hybind) function. ### $delete Deletes a resource. <spec>obj.**$delete**() : _Promise&lt;Object>_</spec> Performs a DELETE request on the resource bound to `obj`. This does _not_ modify `obj` nor its parent, it only deletes the resource in the server. Returns a promise resolving to `obj` in case of success. The promise is rejected in case of error with the same parameters as the promise returned by the underlying HTTP implementation. <spec>obj.**$delete**(parameters:_Object_, [opts:_Object_]) : _Promise&lt;Object>_</spec> Same as above but with * An object specifying URL parameters to pass in the query string. Can be null. * Options object to be passed to the underlying HTTP implementation, it can contains headers or other transport-level (see [Framework Details](#Framework_Details)). It extends/overrides the `defaults` object that can set by the [`hybind`](#hybind) function. ### $set Creates or update a resource association assuming that the REST API supports the same way as Spring Data Rest [does](http://docs.spring.io/spring-data/rest/docs/current/reference/html/#repository-resources.association-resource). <spec>child.**$set**() : _Promise&lt;Object>_</spec> Updates the association of the parent object to `child`. Without argument, it makes sense only after rebinding an already bound `child` to a new parent using [`$bind`](#_bind). This performs a PUT to the association URL with `child` URL as body. This does _not_ modify `child` nor its parent, it only updates the server state. Note that if `child` has not been loaded with `$load` beforehand, the operation _may_ fail. Indeed, REST API implementations may require that clients use the _self link_ instead of arbitrary links to the resource. This is the case for Spring Data Rest. `$load` obtains this self link. Returns a promise resolving to `child` in case of success. The promise is rejected in case of error with the same parameters as the promise returned by the underlying HTTP implementation. <spec>child.**$set**(newChild:_Object_) : _Promise&lt;Object>_</spec> Updates the association of the parent object to `child` by replacing it with an association to `newChild`. This performs a PUT to the association URL with `newChild` URL as body. This does _not_ modify `child` nor its parent, it only updates the server state. Note that if `newChild` has not been loaded with `$load` beforehand, the operation _may_ fail. Indeed, REST API implementations may require that clients use the _self link_ instead of arbitrary links to the resource. This is the case for Spring Data Rest. `$load` obtains this self link. Returns a promise resolving to `child` in case of success. The promise is rejected in case of error with the same parameters as the promise returned by the underlying HTTP implementation. <spec>child.**$set**(newChild:_Object_, parameters:_Object_, [opts:_Object_]) : _Promise&lt;Object>_</spec> Same as above but with * An object specifying URL parameters to pass in the query string. Can be null. * Options object to be passed to the underlying HTTP implementation, it can contains headers or other transport-level (see [Framework Details](#Framework_Details)). It extends/overrides the `defaults` object that can set by the [`hybind`](#hybind) function. ### $add Adds children to a resource collection assuming that the REST API supports it the same way as Spring Data Rest [does](http://docs.spring.io/spring-data/rest/docs/current/reference/html/#repository-resources.association-resource). <spec>arr.**$add**(item:_Object_) : _Promise&lt;Object>_</spec> Performs a POST request with `item` URL in the body to add it to the collection bound to `arr`. This does _not_ modify `arr` nor `item`, it only updates the server state. Note that if `item` has not been loaded with `$load` beforehand, the operation _may_ fail. Indeed, REST API implementations may require that clients use the _self link_ instead of arbitrary links to the resource. This is the case for Spring Data Rest. `$load` obtains this self link. Returns a promise resolving to `arr` in case of success. The promise is rejected in case of error with the same parameters as the promise returned by the underlying HTTP implementation. <spec>arr.**$add**(items:_Array&lt;Object>_) : _Promise&lt;Object>_</spec> Same as above but adds multiple items at once. <spec>arr.**$add**(itemOrItems:_Object_|_Array&lt;Object>_, parameters:_Object_, [opts:_Object_]) : _Promise&lt;Object>_</spec> Same as above but with * An object specifying URL parameters to pass in the query string. Can be null. * Options object to be passed to the underlying HTTP implementation, it can contains headers or other transport-level (see [Framework Details](#Framework_Details)). It extends/overrides the `defaults` object that can set by the [`hybind`](#hybind) function. ### $remove Deletes an association, either to a child object or a collection item assuming that the REST API supports it the same way as Spring Data Rest [does](http://docs.spring.io/spring-data/rest/docs/current/reference/html/#repository-resources.association-resource). <spec>childOrItem.**$remove**() : _Promise&lt;Object>_</spec> Removes the association between `childOrItem` and the parent or containing collection it has been bound with. This performs a DELETE request on the association URL. This does _not_ modify `childOrItem` nor its parent or containing collection, it only updates the server state. Returns a promise resolving to `childOrItem` in case of success. The promise is rejected in case of error with the same parameters as the promise returned by the underlying HTTP implementation. <spec>childOrItem.**$remove**(parameters:_Object_, [opts:_Object_]) : _Promise&lt;Object>_</spec> Same as above but with * An object specifying URL parameters to pass in the query string. Can be null. * Options object to be passed to the underlying HTTP implementation, it can contains headers or other transport-level (see [Framework Details](#Framework_Details)). It extends/overrides the `defaults` object that can set by the [`hybind`](#hybind) function. ### $share Keeps objects in a shared cache to avoid loading them multiple times. <spec>obj.**$share**(cache:_Object_) : _Object_</spec> Creates a property in `cache` containing `obj` if it does not yet exist. The property name is the URL of `obj` (self link). Returns the value of the property. That is, the cached object if it was already in cache or `obj` if it was not in cache. <spec>obj.**$share**(name:_string_, cache:_Object_) : _Object_</spec> Creates a property in `cache` containing the value of the child object `obj[name]` if it does not yet exist. The property name is the URL of the child object (self link). Returns the value of the property. That is, the cached object if it was already in cache or `obj[name]` if it was not in cache. ### $resource On [`$load`](#_load), collections are enriched with a `$resource` property containing the original resource representation returned by the GET request but without the `_embedded` field, since it contents is copied into the array items. It typically gives access to paging metadata.
Laurent Bovet