Restangular: New AngularJS framework to handle Rest API Restful Resources properly and easily

posted in: AngularJS, Rest | 41

Hey,

I’ve been working with AngularJS this past months and I’ve extracted one service that I’ve created to facilitate the usage of Restful Resources. Nowadays, we work with Rest APIs on a daily basis. We’re also starting to use AngularJS more and more each day as it makes us be much more productive. Restangular will make it even easier to work with the Rest APIs that we’ve implemented. You can click here to check it out on GitHub.

What’s the idea of this Framework?

We’re used to creating REST APIs using Resources in our BackEnd. However, when using AngularJS it’s not easy to work with them using $resource and $http. I’ve built a service that will help you get, update and delete resources following the “tree” that you’ve created. I’ve tried this out with Play! Framework and Ruby On Rails and this fits perfectly with both.

How can I add this?

In order to add this, you must download restangular.js from here and then link to it in your HTML file. Restangular depends only on angular, angular-resource and underscore. After this, you must just declare the dependency to your app.

Let’s start using it!!!

I think that the best introduction for a Framework is Code. So let’s code :)

That’s it :) Please tell me what you guys think! If you want to read more about Restangular¬†You can click here to check it out.

Share!FacebookTwitterRedditGoogle+LinkedInbufferEmailflattr
  • luca

    nice, useful…

    • Martin Gontovnikas

      Hey, thanks!!! I’ve just added Post as well now :)

      • Vincent Zhou

        Hi Martin,
        I like to know if the restangular is suitable to work with Google cloud endpoints? How it’s able to handle the oauth2? Thanks.

        • Martin Gontovnikas

          Hey,

          You’d have to do the OAuth2 login by yourself. Then, you need to send the OAuth headers in the methods you use.

          For example: account.getList(‘buildings’, {}, {‘authToken’: ’1234′})

          I hope this clarifies things :)

          Bests

          • Vincent Zhou

            Thanks.

  • http://www.odiseo.net/ odiseo42

    Really cool. For me AngularJS built-in Resource features were already rad to work with RESTful services, but this makes it even better.

    • Martin Gontovnikas

      Thanks! $resource is really cool, but it lacked integration with your models and Restful Resources in my opinion. This way it’s transparent to you

  • http://www.facebook.com/petri.wessman Petri Wessman

    Nice! Much cleaner to use than the default way.

    • Martin Gontovnikas

      Thanks! Please let me know if you think some feature is missing!

  • http://twitter.com/paul_dijou Paul Dijou

    Wooot! Awesome work. A few questions before diving more into it.

    1) Any plan to have an alternate build using Lodash? I’m no longer a huge fan of underscore. I’ve browse quickly your code, looks like all methods you are using from underscore are also in Lodash so it should only be a matter of creating a new repo and updating the component.json to Lodash.

    2) I saw at the end of your code sample, a way to add parameters to the GET query. Is it possible for all methods? Including POST?

    3) Any way to add new methods without forking/making PR to your project? (like a PATCH method)

    4) Any plan to support custom headers like in AngularJS 1.1.x?

    • Martin Gontovnikas

      Hey, Thanks!

      1) I’m actually using underscore, but as you can see, I don’t use AMD so I “assume” that _ is actually underscore. As you just said, Lodash supports all of the things I’m doing, so you actually can include Lodash in your HTML instead of underscore and Restangular will keep on working anyway, which is really cool :)

      2) Yes. All methods support params. In the case of post, it’d be elem.post(‘buildings’, myBuilding, {hey: ‘jude’}

      3) For the time being you cannot add new method, but create an issue for this, and I’ll do this one of this days, or you can submit a PR with this done. Check out https://github.com/mgonto/restangular/blob/master/src/restangular.js#L86 as you can see there, it’s really straight forward the way I add this new methods.

      4) Yes, I do plan to include them. Anyway, for the time being, I’m also sending HTTP Headers by configuring them in $httoProvider. This works great with current implementation: http://docs.angularjs.org/api/ng.$http check out Setting HTTP headers.

      • http://twitter.com/paul_dijou Paul Dijou

        Thanks for the quick answer.

        1) True. But there would still be a dependencies to underscore in the component.json … I guess I can live with that but a clean component.json with Lodash in place of underscore would be better (btw, component.json is supposed to be renamed to bower.json I think…)

        2) Hmmm, maybe I’m missing something but looking at the signature of the POST function ( https://github.com/mgonto/restangular/blob/master/src/restangular.js#L160 ), it doesn’t really appears to take any params, just the “what”, which is a String and will be transformed as, and on optional element which is the data of the POST (if I understand correctly).

        Should it be something like :

        function postFunction(what, elem, params) {
        return _.bind(elemFunction, this)(“post”, _.merge(params, {what: what}), elem);
        }

        Or function postFunction(what, params, elem) { … }

        In this case, a small warning about the fact that “what” is a bit generic as param name and might conflict with a user param. Why not namespacing it like “restangularWhat” or something… It should be invisible to the user anyway.

        3) Roger that.

        4) Right, but sometime I want custom headers for only one particular request, like when using Google services or stuff like that.

        • Martin Gontovnikas

          Hey,

          1) Yes, components.json is going to be bower.json, I’m going to update it soon as well. Otherwise, just fork it and change only the dependency and then register to bower like restangular-lodash

          2) I’ve implemented it a few minutes ago with headers for the post funciton, so right now if you enter to the link you just copied me, you’ll see that it takes params and headers :). Regarding params, I just forgot to add it, and implementation is very similar to what you mention. I used _.extend instead of _,merge but the rest is the same.

          • http://twitter.com/paul_dijou Paul Dijou

            Perfect… no more to add for now :-) Thanks for the blazing fast implementation of custom headers.

            I will try to do a PR during week-end for other HTTP methods support.

          • Martin Gontovnikas

            No problem! It’s just really easy to implement new things to the library due to the generic way it’s done :).

            Please do a PR for other HTTP methods, it’d be awesome! Thanks, and let me know if you encounter any problems with current impl :)

    • Martin Gontovnikas

      Hey :)

      I made some time today and I’ve implemented #4 :). Now you can send your custom headers if you want, besides using $httpProvider :). Hope it works for you!!

    • Martin Gontovnikas

      Hey,

      Regarding #1, I’ve been trying out, testing, checking features on Lodash and I really like it :). I want to change Underscore for Lodash in Restangular. Thx for the tip BTW. However, I’m running into problems with bower and lodash, have you can any problem with it? Could you please check https://github.com/mgonto/restangular/issues/9 and let me know if you know what’s going on?

      Thankss!!

  • jbland

    Is it possible to add support for response interceptors. For example, i have a web service which wraps all responses in an envelope containing metadata like
    {
    meta : {
    status : ’0k’
    }
    data : {
    name :’alice’
    id ’1000′
    }
    }

    in this case, what im after is response.data

    • Martin Gontovnikas

      Hey,

      Yes, it’s possible and actually not that hard to add this configuration.

      Could you please create an issue on GitHub for this? I’ll try to implement this today :).

  • Jhon Pierre

    Buenisimo!

  • Jhon Pierre

    What about the unit test with Jasmine? is it possible to continue using the $httpbackend object and the when() methods?

  • Gokhan Aykan

    how can I integrate it with MongoLab ?

    • Martin Gontovnikas

      Hey, If MongoLab uses a Restful API to fetch things, you can actually integrate it very easily. Check the Github repo and if you have any doubt, create an issue @Github

    • Martin Gontovnikas

      Check out this example of MongoLab integration http://plnkr.co/edit/bs5Qu8D6mYXzJXR74b87?p=preview

      • Gokhan Aykan

        Thanks for kind effort…
        What is the development path for the future.
        Will it stay as a passive interface or do you plan to add some dynamic features to fetch data regularly.

        • Martin Gontovnikas

          I don’t know exactly what you mean by “dynamic features”.

          Regarding the fetch data regularly, you can implement that in your service using Restangular.

          You could have your own service which just calls Restangukar.one(“elements”, 123).get() with a setInterval and that way, it’ll get updated every 10 seconds. I don’t think this should be part of the library itself.

      • Gokhan Aykan

        When I use restangular.js source from plunkr it is ok, but when I use

        I get :

        Uncaught TypeError: Object [object Object] has no method ‘setDefaultRequestParams’ from MainApp app.js:34
        (anonymous function)app.js:34
        invokeangular.js:2872
        (anonymous function)angular.js:2794
        forEachangular.js:151
        loadModulesangular.js:2782
        createInjectorangular.js:2724
        resumeBootstrapInternalangular.js:983
        bootstrapangular.js:998
        angularInitangular.js:959
        (anonymous function)angular.js:16310
        cjquery.min.js:3
        p.fireWithjquery.min.js:3
        b.extend.readyjquery.min.js:3
        H

        • Martin Gontovnikas

          Hey that’s because I haven’t yet published the latest version ot the CDN. I’ll be doing that tomorrow

  • Emin Jasarevic

    I’m returning a JSON string from a POST request, but I get this error:
    TypeError: Object # has no method ‘push’

    This is the JSON string returned from the server. And I can see it in the request response just fine.

    [{"id":"1","user_id":"1","message":"A little test shout!","location":"Kungsholmen","created_at":"2013-05-23 19:51:44","updated_at":"2013-05-23 19:51:44","user":{"id":"1","username":"emin"}}]

    If I just return some text string from the server, I get every single letter in a separate object in the response.

    This is my code:
    var shouts = Restangular.all(‘shouts’);
    var newShout = {name: “Gonto’s account”};

    shouts.post(newShout).then(function(response) {
    console.log(“Object saved OK”);
    console.log(response); // I want my JSON data here!
    }, function() {
    console.log(“There was an error saving”);
    });

    Grateful for help!

    • Martin Gontovnikas

      Hey,

      So the problem is that when you do a POST, a Restful API should actually return the created element, not a list of element.

      So, the API expects an object response and it has an array, that’s why that “push” bug is returned.

      If you do need to answer this list, please create an issue @Github and I’ll see how to fix this or how to implement this somehow.

      Bests

      • Emin Jasarevic

        Thank you! :)

        Now I have this other problem.

        I have a model that I populate like this:

        var shouts = Restangular.all(‘shouts’);
        $scope.shouts = shouts.getList();

        Works fine, and I can ng-repeat that list in the view, just as usual.

        But when I try to “unshift” that response to this model, I get:
        TypeError: Object # has no method ‘unshift’

        shouts.post(newShout).then(function(response) {
        console.log(“Object saved OK”);
        $scope.shouts.unshift(response);
        }, function(response) {
        console.log(“There was an error saving”);
        console.log(response);
        });

        If I do:
        $scope.shouts.$$v.unshift(response);

        It works.

        But I have a feeling this isn’t the correct way to do it?

        • Martin Gontovnikas

          That response is actually a promise. So you should do something like this to unshift it:

          Restangular.all(‘shouts’).getList().success(function(shouts) {

          $scope.shouts = shouts;

          });

          That way, you’re saying once the promise is OK, set it to the scope. And there, you have the real list, to which you can call unshift.

          Other optoin is to actually use Enhanced promises (something I’ve added to Restangular).

          Take a look here https://github.com/mgonto/restangular#enhanced-promises

  • Guest

    Hey, just looking into this and really happy to see a solid extension built for AngularJS. However, not being fully familiar with either framework’s every nuance, can you tell me what made you decide to build this over using the ngResource module that came default in Angular?

    • Martin Gontovnikas

      Hey,

      I decided to built it on top of $resource to use all of its features, some of which were missing in $http.

      However, I’m now having problems with my decision as $resource kind of sucks and it really buggy, so I’m planning to changing this and implementing $http instead :).

  • codedungeon

    So, I am stumped here trying to get this working. My consistent error is the standard:

    No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:3000′ is therefore not allowed access.

    I am trying to access the beers database


    RestangularProvider.setBaseUrl('http://api.openbeerdatabase.com/v1/');
    RestangularProvider.setRequestSuffix('.json');

    Then, in my controller, I call


    $scope.locations = Restangular.all("beers").getList();

    I am sure I am missing something here, but I am stumped. I was able to do this easily with $http (using the JSONP method) but not so easy with Restangular.


    var api = 'http://api.openbeerdatabase.com/v1/beers.json?callback=JSON_CALLBACK';
    $http({method: 'JSONP', data: options, url: api}).success(...)

  • finestglasses j.

    For the online stores casually prescribed glasses, you will get these Designer Glasses with way more affordable prices compared to those for the actual physical retailers.