AngularJS: Creating Objects that map to REST Resources (ORM-Style)

JavascriptWeb ApplicationsOrmAngularjs

Javascript Problem Overview


I'm pretty new to AngularJS, but I'm pretty unclear on how to tie it up to my Server's REST Api backend.

For example, say I have an "image" resource that I get by GET-ing: myApi/image/1/. This returns a json object with various fields. Let's say something like:

{url: "some/url", date_created: 1235845}

Now, I want some kind of representation in my AngularJS app of this "Image" object. This representation is more than just a mapping of the fields - I want to add "helper" functions, for example a function that converts the date_create field into something human-readable.

I know about the $resource service, but I'm unclear what I need to do to create a basic "class" in Angular, that uses Resource to get the JSON object, but then enhances it by adding various helper functions.

Bonus points:

I'm also unclear how to add "relationships" between models. For example, I might have a "user" resource that has embedded inside it an "image" resource, and I'll want to grab the User resource, but be able to call "Image" helper functions on the "Image" part of the model.

Javascript Solutions


Solution 1 - Javascript

JSData
A project which started as angular-data is now "a framework-agnostic data store built for ease of use and peace of mind." It is has excellent documentation and has support for relations, multiple backends (http, localStorage, firebase), validation and of course angular integration.
http://www.js-data.io/

BreezeJS
The AngularJS YouTube channel features this video using BreezeJS

Which is an advanced ORM which even supports client-side filtering and other cool stuff. It best suited for backend that support OData, but can be made to work on other types of backends.

ngResource
Another option is to use the ngResource, here is an example on how to extend it with your own functions:

module.factory('Task', function ($resource) {
	var Task = $resource(WEBROOT + 'api/tasks/:id', {id: '@id'}, {update: { method: 'PUT'}});
	angular.extend(Task.prototype, {

		anExampleMethod: function () {
			return 4;
		},

		/**
		 * Backbone-style save() that inserts or updated the record based on the presence of an id.
		 */
		save: function (values) {
			if (values) {
				angular.extend(this, values);
			}
			if (this.id) {
				return this.$update();
			}
			return this.$save();
		}
	});
	return Task;
});

I found ngResource to be very limited, even compared to Backbone.Model which has:

  • Custom JSON parsing via Model.parse
  • Possible to extend a BaseModel (No the baseUrl in ngResource)
  • Other hooks like Backbone.sync, which enables LocalStorage, etc.

Restangular
"AngularJS service to handle Rest API Restful Resources properly and easily"
https://github.com/mgonto/restangular

Or try some of the other ORM's
https://stackoverflow.com/questions/6786307/which-javascript-orm-to-use

Solution 2 - Javascript

I'm creator of Restangular so my opinion can be biased.

But as Bob said, you can use Restangular for it.

Restangular uses your Restful API Resources to go over the tree. You can also add new methods to this.

This is coding example: https://github.com/mgonto/restangular#lets-code

And this way you can add new methods to your object (The bonus points :)) https://github.com/mgonto/restangular#creating-new-restangular-methods

Hope this works out for you :).

Otherwise, you can also use ngResource ($resource) for this but in my opinion, it needs some "love" and "sugar".

Bests

Solution 3 - Javascript

For simple interaction you can use Angular-Resource (http://docs.angularjs.org/api/ngResource.$resource) which can be quite handy for simple REST interaction (to download it go to http://code.angularjs.org/1.0.6/)

Sadly you only get limited control when using angular resource, and for anything more advanced you will need to create your own services based on Angularjs $http service - http://docs.angularjs.org/api/ng.$http.

Hope that helps.

Solution 4 - Javascript

After lots of research, here is a comprehensive list of all the solutions available:

but honestly I wasn't very happy, so I decided to add to the list my own solution haha. Check it out here: $modelFactory.

Your end-result code ends up looking something like:

var module = angular.module('services.zoo', ['modelFactory']);

module.factory('AnimalModel', function($modelFactory){
  return $modelFactory('api/zoo');
});

return module;

I believe this is a better solution over the rest because mainly the model definition closely resembles Angular's ngResource, adding just low-level features one needs that it lacks. Its super lightweight (1.45k gzip/min) and has only a few small dependencies ( no lodash, jquery, etc ).

Solution 5 - Javascript

ModelCore ( https://github.com/klederson/ModelCore ) works pretty much like this, and is very very easy to implement:

var ExampleApp = angular.module('ExampleApp', ['ModelCore']); //injecting ModelCore

ExampleApp.factory("Users",function(ModelCore) {
  return ModelCore.instance({
    $type : "Users", //Define the Object type
    $pkField : "idUser", //Define the Object primary key
    $settings : {
      urls : {
        base : "http://myapi.com/users/:idUser",
      }
    },
    $myCustomMethod : function(info) { //yes you can create and apply your own custom methods
        console.log(info);
    }
  });
});

//Controller
function MainCrtl($scope, Users) {
  //Setup a model to example a $find() call
  $scope.AllUsers = new Users();

  //Get All Users from the API
  $scope.AllUsers.$find();

  //Setup a model to example a $get(id) call
  $scope.OneUser = new Users();

  //Hey look there are promisses =)
  //Get the user with idUser 1 - look at $pkField
  $scope.OneUser.$get(1).success(function() {
    console.log("Done!",$scope.OneUser.$fetch());
});

Solution 6 - Javascript

Angular Rest-Mod is another good option for Angular-based Models / ORM.

Restmod creates objects that you can use from within Angular to interact with your RESTful API. It also supports collections, relations, lifecycle hooks, attribute renaming and much more.

Solution 7 - Javascript

One more example of helper for ngResource. This relies on fact that the vast majority of services is something like that:

http://host/api/posts
http://host/api/posts/123
http://host/api/posts/123/comments
http://host/api/posts/123/comments/456

So, the task is to make a helper that create AngularJS resource objects that maps on such services. Here it is:

'use strict';

var api = angular.module('api', ['ngResource']);

// RESTful API helper
api.addService = function (serviceNameComponents) {
	var serviceName = "";
	var resource = "/api"; // Root for REST services
	var params = {};

	serviceNameComponents.forEach(function (serviceNameComponent) {
		serviceName += serviceNameComponent;

		var lowerCaseServiceNameComponent = serviceNameComponent.toLowerCase();
		var collection = lowerCaseServiceNameComponent + 's';
		var id = lowerCaseServiceNameComponent + 'Id';

		resource += "/" + collection + "/:" + id;
		params[id] = '@' + id;
	});

	this.factory(serviceName, ['$resource',
		function ($resource) {
			return $resource(resource, {}, {
					query: {
						method: 'GET',
						params: params,
						isArray: true
					},
					save: {
						method: 'POST',
					},
					update: {
						method: 'PUT',
						params: params,
					},
					remove: {
						method: 'DELETE',
						params: params,
					}
				}
			);
		}
	]);
}

So, to use it simply call this helper

api.addService(["Post"]);
api.addService(["Post", "Comment"]);

And then you can use Post and PostComment in code with needed params like :post_id

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEdan MaorView Question on Stackoverflow
Solution 1 - JavascriptBob FangerView Answer on Stackoverflow
Solution 2 - JavascriptmgontoView Answer on Stackoverflow
Solution 3 - JavascriptGuy NesherView Answer on Stackoverflow
Solution 4 - JavascriptamcdnlView Answer on Stackoverflow
Solution 5 - JavascriptKlederson BuenoView Answer on Stackoverflow
Solution 6 - JavascriptamcdnlView Answer on Stackoverflow
Solution 7 - JavascriptDenisView Answer on Stackoverflow