Mapping an Angular Resource Service to a Web API

Thursday, February 28, 2013

Previously I was calling an ASP.NET Web API controller from an AngularJS controller using the $http service.

$http.get(serviceUrl).success(function (data) {
    $scope.videos = data;
});

With a little bit of work I can use a higher level of abstraction in Angular – a custom service based on $resource. $resource is a factory that can create an object with methods that map to the WebAPI action methods I need to invoke. If I scaffold a VideoController for the WebAPI, the default actions will let me:

- GET all videos

- GET a video by ID.

- POST a new video

- PUT an updated video

- DELETE a video

To configure a service that will map JavaScript methods to these controller actions on the server, I'll need to use the .module API.

angular.module("videoService", ["ngResource"]).
       factory("Video", function ($resource) {
           return $resource(
               "/api/videos/:Id",
               {Id: "@Id" },
               { "update": {method:"PUT"} }    
          );
      });

These lines of code are registering a videoService that depends on ngResource (another module in Angular). When a controller requires a video service, the factory method will take care of configuring the service using $resource. There are a few interesting lines of code here.

- "/api/videos/:Id" is the URL to interact with the resource on the server (you could send this value to the client instead of hard coding the value). The :id part tells Angular how part of the URL path is parameterized with data.

- {Id: "@Id"} tells Angular to grab the ID parameter for the URL from an object's Id property.

- { "update": {method:"PUT"}} tells Angular to add a custom method to the resource. The custom method has the name "update" and it will use HTTP PUT when sending a message to the server. The default methods for a resource include query, save, and delete, which map to GET, POST, and DELETE verbs, so we needed one more for PUT. 

Another call to .module will tell Angular that my app requires the videoService as a dependency.

angular.module("videoApp", ["videoService"]);

And now the controller can "ask" for Angular to inject a video service by adding another parameter named "Video" to the constructor (Video was the first parameter to .factory, above):

var VideoController = function ($scope, Video) {
    /// ...
}

What used to require three lines of code to grab all videos from the server now requires a single line of code*.

$scope.videos = Video.query();

The resource service returns an empty array in this scenario, but there is a promise working behind the scenes to populate the array with data (which data binding will then automatically push into the view). The delete, save, and update methods are also available on these objects once they return from the server.

$scope.createVideo = function (newVideo) {
    newVideo.$save();
    $scope.videos.push(newVideo);           
};

$scope.updateVideo = function(video) {                
    video.$update();
};

$scope.deleteVideo = function (video) {
    video.$delete();
    $scope.videos = _.without($scope.videos, video);
};

The code is naïve and assumes a call to the server will always work. There are a couple strategies for error handling, including passing an error handler to the resource methods, or registering an $http interceptor to process HTTP messages at a global level (that's foreshadowing). For now, the heart of the code is in an updated gist.

* Still not entirely comfortable with the naming conventions I want to use for this scenario.


Comments
gravatar Roberto Hernandez Thursday, February 28, 2013
Awesome! Thanks for the valuable tip.
peco Friday, March 1, 2013
Im liking these series. Please make a module on pluralsight about this!
gravatar Khuzema Saturday, March 2, 2013
Dear Sir, Can you please have a course on angularjs (Frontend/client side) on pluralsight using microsoft stack of technologies (Backend/server-side), please. Please also have a good demo application for the same, will be highly appreciated.
gravatar Vicente Saturday, March 2, 2013
Should I stop using Razor?
gravatar Scott Allen Sunday, March 3, 2013
@Vicente Razor is still a great way to make HTML on the server. @Khuzema A couple authors @Pluralsight already working on the topic. Might be able to add on in the future.
Khuzema Sunday, March 3, 2013
Hope the angularjs course is released soon, your Bootstrap course came right on time, thank you. I hope you also do the AngularJS course too, may be on different topic.
gravatar Ryan Riley Friday, March 15, 2013
Have you tried using the angular XSRF protection? Are you taking a different approach? I'm running into issues and looking for help: http://stackoverflow.com/q/15444781/2089257
gravatar Scott Allen Monday, April 1, 2013
@Ryan: Haven't run into this problem as yet, but will let you know.
gravatar santosh poojari Wednesday, April 3, 2013
Thanks for sharing this. www.santoshpoojari.blogspot.com
gravatar Salman Farsi Wednesday, April 3, 2013
Thanks for sharing, its really good and very informative. Is it start of end of Razor?
gravatar David Wednesday, April 3, 2013
Hi Scott, I remember reading one of your posts regarding the JavaScript libraries/frameworks. My understanding was you don’t really like them. Now after reading this post can I ask you to provide your opinion on what to use with MS MVC WebAPI (Angular, Knockout or something else). By the way I got a log of knowledge from your pluralsight courses. I find them most structural and very helpful. Thanks for your work. David K.
gravatar James Wednesday, April 3, 2013
Good question about Pluralsight... Scott, I'm finding it very strange that Pluralsight doesn't have yet any courses on Angular. Do you think that the close relationship with Microsoft may be behind it? I mean, is it a political reason? And please do a Pluralsight Course on the topic. Your C# series is mind blowing. Thank you for your genius mind.
gravatar Scott Allen Thursday, April 4, 2013
@David: It's not that I don't like frameworks, they are required to build a complex single page. JavaScript frameworks tend to be opinionated and have to match well with a developer's mental model of how things should work,. AngularJS does that for me - I like it. It's not that other frameworks are bad, or I can't be successful with them, but they just make me feel like I'm "working" and not "creating". @James: No conspiracy here :) There is an AngularJS course in the works, and there is a good chance there will be multiple courses. It just takes time to make a good set of videos.
gravatar Scott Allen Thursday, April 4, 2013
@David: Also see my post on why I prefer to work with AngularJS (for today): http://odetocode.com/blogs/scott/archive/2013/02/26/why-use-angularjs.aspx
gravatar Scott Allen Thursday, April 4, 2013
@Salman: I think there is still a place for server-side rendering. Maybe not 5 years from now, but today we still need Razor.
gravatar ccliu Friday, April 5, 2013
AngularJS seems cover everything, my question: Do AngularJS support OData query with LINQ-like syntax? Should have to use AngularJS with Breeze.js to achieve it?
Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!