gomoob / backbone.hateoas Goto Github PK
View Code? Open in Web Editor NEWUse HAL and HATEOAS in your Backbone and Marionette applications !
License: MIT License
Use HAL and HATEOAS in your Backbone and Marionette applications !
License: MIT License
Any ideas ?
Help on this is welcome, the logo should be available in svg like this one https://github.com/marionettejs/marionettejs.com/blob/master/src/images/marionette.svg.
When we call the this.model.unsetEmbedded(rel, [options])
and this.model.unsetLink(rel, [options])
the behavior is exaclty the same as the Backbone unset(attr, [options])
(i.e the attribute stays and has an undefined
value).
We've added a custom delete
option which can be used to force complete deletion of the attribute (using the Javascript delete
operator).
Here is an exemple with and without the delete
option using an undefined address
embedded relation.
Without the delete
option
var user = new Hal.Model({
id : 1,
firstName : 'John',
lastName : 'Doe',
_embedded : {
address : {
id : 10,
street : '142 Rue de Rivoli',
postalCode : 75001,
city : 'Paris'
}
}
});
user.unsetEmbedded('address');
user.toJSON({contentType: 'application/hal+json'});
// {
// id : 1,
// firstName : 'John',
// lastName : 'Doe',
// _embedded : {
// address : null
// }
// }
With the delete
option
var user = new Hal.Model({
id : 1,
firstName : 'John',
lastName : 'Doe',
_embedded : {
address : {
id : 10,
street : '142 Rue de Rivoli',
postalCode : 75001,
city : 'Paris'
}
}
});
user.unsetEmbedded('address', {delete : true});
user.toJSON({contentType : 'application/hal+json'});
// {
// id : 1,
// firstName : 'John',
// lastName : 'Doe'
// }
This is good but in some project it would be easier to allow overwriting of the unset
behavior on embedded and likes for the whole project.
For example.
Hal.embeddedUnsetOptions : {
delete : true
};
Hal.linksUnsetOptions : {
delete : true
};
// Now unsetEmbedded has the delete option set to true by default
var user = new Hal.Model({
id : 1,
firstName : 'John',
lastName : 'Doe',
_embedded : {
address : {
id : 10,
street : '142 Rue de Rivoli',
postalCode : 75001,
city : 'Paris'
}
}
});
user.unsetEmbedded('address');
user.toJSON({contentType : 'application/hal+json'});
// {
// id : 1,
// firstName : 'John',
// lastName : 'Doe'
// }
// We could still force the option
user = new Hal.Model({
id : 1,
firstName : 'John',
lastName : 'Doe',
_embedded : {
address : {
id : 10,
street : '142 Rue de Rivoli',
postalCode : 75001,
city : 'Paris'
}
}
});
user.unsetEmbedded('address', {delete: false});
user.toJSON({contentType: 'application/hal+json'});
// {
// id : 1,
// firstName : 'John',
// lastName : 'Doe',
// _embedded : {
// address : null
// }
// }
Setup travis.
Document how to write a custom error handler to catch library errors.
When urlMiddle parameter is set with URI special characters, they are encoded while they should not be.
The Hal.Model
class should define 2 additional methods :
hasEmbedded(rel)
to quickly check if an embedded resource is presenthasLink(rel)
to quickly check if a link is presentAdd method unsetLink(rel) on the Hal.Model class.
Here is the problem, very critical .
var model = new Hal.Model();
model.setEmbedded('myCollection', new Backbone.Collection());
// Here the returned object is not a collection but an Hal.Model instead
var myCollection model.getEmbedded('myCollection');
The clone()
method of the Hal.Model
classe is not overwritten. So it do not clone HAL links and embedded resources.
For now we are forced to specify 2 parameters when we create a Hal.Collection
:
url
: An absolute URL used to fetch the REST resourcerel
: The name of the relation embedded in the returned HAL response.var users = new Hal.Collection();
users.url = 'https://myserver.com/api/users';
users.rel = 'users'
It works but using absolute URLs is not good, instead we should be able to do this :
// Only one time at project initialization
Hal.urlRoot = 'https://myserver.com/api';
// Later when we want to create a collection
var users = new Hal.Collection();
users.urlMiddle = 'users';
users.rel = 'users';
users.fetch(); // https://myserver.com/api/users
// And even shorter if we suppose the default 'rel' value is equal to 'urlMiddle'
var users = new Hal.Collection();
users.urlMiddle = 'users';
users.fetch(); // https://myserver.com/api/users
// We could even allow to specify the 'urlMiddle' as options
var users = new Hal.Collection({ urlMiddle : 'users'});
users.fetch();
// But if a url is explicitly provided use it in all cases
var users = new Hal.Collection();
users.urlMiddle = 'users';
users.url = 'https://myserver.com/api-v2/users'
users.fetch(); // https://myserver.com/api-v2/users
The clone()
method of the Hal.Collection
class is not overwritten. So it do not clone HAL links and embedded resources.
For now each time we encounter an error in the library we throw a standard Javascript Error
, here is a sample.
throw new Error('Invalid link identified by \'rel\'=\'' + rel + '\' !');
It works but has several drawbacks :
instanceof
Error
class ;Error
object when an error is encountered is not always wanted by developers, instead it could be cool to have an error handler which could be overriden (to add a logger for example).So, to improve error management we propose here to create an Hal.Error
class and an Hal.ErrorHandler
class.
We should be here https://github.com/mikekelly/hal_specification.
Increase code coverage to 100%.
If we fetche an HAL Collection from server side and this HAL collection is empty then if we try to add a model on this empty collection the following exception is encountered.
Uncaught RangeError: No link found for page 1
Backbone.PageableCollection.Backbone.Collection.extend._checkState @ backbone.paginator.js:588
collectionEventHandler @ backbone.paginator.js:433
triggerEvents @ backbone.js:209
Backbone.Events.trigger @ backbone.js:148
_.extend._onModelEvent @ backbone.js:946
triggerEvents @ backbone.js:210
Backbone.Events.trigger @ backbone.js:149
_.extend.set @ backbone.js:749
_.extend.add @ backbone.js:638
Marionette.LayoutView.extend._onUserProductRatingSaveSuccess @ list-child-view.js:724
proxy @ jquery.js:512
options.success @ backbone.js:486
fire @ jquery.js:3099
self.fireWith @ jquery.js:3211
done @ jquery.js:8264
(anonymous function) @ jquery.js:8605
XMLHttpRequest.oXMLHttpRequest.onload @ oauth.js:107
If we call the unsetEmbedded(rel)
method on an Hal.Model
and then we call toJSON()
method it fails at line https://github.com/gomoob/backbone.hateoas/blob/master/src/embedded/embedded.js#L235.
This is because the Backbone unset(attributeName)
method does not really remove properties but only set them to undefined.
Add it here https://cdnjs.com.
The Backbone has(attribute)
method checks if an attribute is not null or not undefined. Also to check for the existence of a HAL link we use the has(attribute)
method on the Hal.Links
container.
But setting a null
or undefined
link throws an error which is not normal, also not authorizing null
or undefined
links will lead to problems if the unsetLink
method is called (same problem as #5).
Updates the link implementation to authorize null
and undefined
links and update the hasLink -> With a not empty model
unit test accordingly.
When we create an Hal.Collection
we use a rel
property to indicate which name is used for the embedded array of elements.
For example if we have the following HAL collection.
{
"_embedded" : {
"users" : [ ... ]
},
"_links" : { ... }
"page" : 1
"page_count" : 1
"page_size" : 12
"total_items": 2
}
}
To fetch this collection we have to write the following code.
var collection = new Hal.Collection();
collection.rel = 'users';
collection.url = 'https://myserver.com/rest/users'
Here if the developer configure a bad rel
the collection fetch
will succeed but with an empty collection. This is very annoying and we can consider this is a bug.
We should improve the Hal.Collection
the following way :
_embedded
section, so by default provided the rel
should be optional and the Hal.Collection
should be able to pick the only _embedded
element and check if its an array. If it is it should consider this array corresponds to the collection elements. If the rel
parameter is not provided and at least 2 elements are in the _embedded
section then the Hal.Collection
should throw a detailed error message ;rel
element is provided and the Hal.Collection
does not found any key corresponding to this rel
in the _embedded
section then the Hal.Collection
should throw an error with a detailed message.In fact we have a problem because somebody already use backbone.hateoas
as package name :-( : https://www.npmjs.com/package/backbone.hateoas.
See also https://docs.npmjs.com/misc/disputes.
npm owner ls backbone.hateoas
repocho <[email protected]>
To do :
backbone.hateoas
npm package ownershipbackbone-hateoas
Create a documentation using Couscous.
Having specific Hal.Model
and Hal.Collection
objects is good, but we could do it better by extending the Backbone.Model
and Backbone.Collection
types directly.
In fact having additionnal Hal.Model
and Hal.Collection
types adds complexity in the code and confusion.
For exemple we should be able to do this but its not possible :
var halModel = new Hal.Model();
halModel.setEmbedded('address', new Backbone.Model());
halModel.getEmbedded('address').setEmbedded('city', new Backbone.Mode());
The solution would be to extend the Backbone.Model
and Backbone.Collection
types the same way Backbone.Stickit does it.
Then we should be able to simply do :
var model = new Backbone.Model();
model.setEmbedded('address', new Backbone.Model());
model.getEmbedded('address').setEmbedded('city', new Backbone.Mode());
// Standard 'application/json' serialization
model.toJSON();
// Custom 'application/hal+json' serialization
model.toJSON({contentType : 'application/hal+json'});
For example :
// Export onto Backbone object
Backbone.Hal = Hal;
// Backbone.Model Mixins
// --------------------
Hal.ModelMixin = {
...
hasEmbedded : function(rel) {
return this._embedded.has(rel);
},
...
};
// Backbone.Collection Mixins
// --------------------
Hal.CollectionMixin = {
...
};
_.extend(Backbone.Model.prototype, Hal.ModelMixin);
_.extend(Backbone.Collection.prototype, Hal.CollectionMixin);
Then to let old version of backbone.hateoas
we could simply do this :
Hal.Model = Backbone.Model;
Hal.Collection = Backbone.Collection;
Quickly explain http://martinfowler.com/articles/richardsonMaturityModel.html and give more links.
We need at least 80 Github stars to do it.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.