64

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.

markus
  • 40,136
  • 23
  • 97
  • 142
Edan Maor
  • 9,772
  • 17
  • 62
  • 92
  • That sounds like you want some kind of angular-supported model framework. As far as I know there is nothing like that in angular built-in. – thalador Apr 24 '13 at 09:21
  • 3
    @thalador - I'm looking to even just hear best-practices to how to go about building my own. Should I be wrapping a "Resource" object with a service and adding methods to that? Wrapping up a "resource" object with a separate service? etc. – Edan Maor Apr 24 '13 at 12:20

7 Answers7

80

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

Bob Fanger
  • 28,949
  • 7
  • 62
  • 78
  • 1
    Breeze may well be the right choice for you (disclaimer: I'm one of the Breeze maintainers). To be clear, Breeze is a pure JavaScript library. It isn't an ORM. It doesn't care about OData. It does work well with ORMs, OData, and other .NET technologies out-of-the-box which is how we usually demo it. But you can hit *almost any* HTTP service (including REST services) written with *any* technology, as is demonstrated with the [Breeze Edmunds sample](http://www.breezejs.com/samples/edmunds). If you have a Breeze question, ask it on SO, tagged with "breeze" and we'll find it. – Ward May 01 '13 at 02:45
  • I think Breeze is the right long-term choice, and something we will definitely look into for our next project. For this one we're going to stick with ngResource together with custom functions. – Edan Maor May 04 '13 at 09:03
  • last link is dead. – Stefan Jan 15 '20 at 10:38
  • @Stefan Thanks, i've updated the links. Note these links are for the AngularJS 1.x versions. – Bob Fanger Jan 15 '20 at 22:38
15

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

mgonto
  • 6,605
  • 2
  • 29
  • 36
7

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.

Guy Nesher
  • 1,385
  • 2
  • 14
  • 26
5

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 ).

amcdnl
  • 8,470
  • 12
  • 63
  • 99
4

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());
});
Klederson Bueno
  • 330
  • 3
  • 6
3

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.

amcdnl
  • 8,470
  • 12
  • 63
  • 99
2

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

Denis
  • 433
  • 6
  • 14