Skip to main content
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with: Jason Dean
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with: Jason Dean ( @JasonPDean )

httpi - A Lightweight $resource-Inspired Module For AngularJS

By on

As I blogged about before, I'm not a huge fan of the $resource module in AngularJS. But, it does have some features that I do like; namely, URL interpolation and the encapsulation of URLs across requests to the same resource. I created the "httpi" module in an attempt to build these features on top of the $http service while still providing direct access to the flexibility of the $http service underneath.

View the httpi project on my GitHub account.

The httpi service is really just a preprocessor for the underlying $http service. It takes your configuration object, interpolates the URL (hence the "i" in "httpi"), and then passes the updated configuration object off to $http. It then returns the same promise that the $http service returned to it.

The httpi service can also create $resource-inspired objects that apply the same URL across different HTTP calls. But, like the httpi service, each HttpiResource instance method takes a normal configuration object, modifies it, and then passes it off to the underlying $http service.

NOTE: When I say "$resource-inspired," I do so very loosely. I do not mean to imply that I am recreating the $resource feature-set; rather, that I am extracting what I personally found useful in the $resource-oriented approach.

To see this in action, take a look at the code below (which is the example on my GitHub project page). I'm creating an httpi resource and then invoking several of the convenience methods:

<!doctype html>
<html ng-app="Demo">
<head>
	<meta charset="utf-8" />

	<title>
		Using The httpi Service To Make AJAX Requests In AngularJS
	</title>

</head>
<body ng-controller="DemoController">

	<h1>
		Using The httpi Service To Make AJAX Requests In AngularJS
	</h1>


	<!-- Initialize scripts. -->
	<script type="text/javascript" src="vendor/angular-1.2.16.min.js"></script>
	<script type="text/javascript" src="../lib/httpi.js"></script>
	<script type="text/javascript">

		// Define the module for our AngularJS application.
		var app = angular.module( "Demo", [ "httpi" ] );


		// -------------------------------------------------- //
		// -------------------------------------------------- //


		// I control the main demo.
		app.controller(
			"DemoController",
			function( $scope, httpi ) {

				console.warn( "None of the API endpoints exist - they will all throw 404." );

				// NOTE: The (.|.) notation will be stripped out automatically; it's only
				// here to improve readability of the "happy paths" for interpolation
				// labels. The following urls are pre-processed to be identical:
				// --
				// api/friends/( :listCommand | :id/:itemCommand )
				// api/friends/:listCommand:id/:itemCommand
				var resource = httpi.resource( "api/friends/( :listCommand | :id/:itemCommand )" );

				// Clear list of friends - matching listCommand.
				resource.post({
					data: {
						listCommand: "reset"
					}
				});

				// Create a new friend - no matching URL parameters.
				resource.post({
					data: {
						name: "Tricia"
					}
				});

				// Get a given friend - ID matching.
				resource.get({
					data: {
						id: 4
					}
				});

				// Make best friend - ID, itemCommand matching.
				resource.post({
					data: {
						id: 4,
						itemCommand: "make-best-friend"
					}
				});

				// Get gets friends - no matching URL parameters.
				resource.get({
					params: {
						limit: "besties"
					}
				});

				// Get a friend as a JSONP request.
				// --
				// NOTE: The "resource" will auto-inject the "JSON_CALLBACK" marker that
				// AngularJS will automatically replace with an internal callback name.
				resource.jsonp({
					data: {
						id: 43
					}
				});

			}
		);

	</script>

</body>
</html>

Notice that the configuration objects passed into the "resource" methods don't have to include the Method or URL properties - these are automatically interpolated and injected into the configuration object before they are passed-off to the underlying $http service.

When we run the above code, we get the following network activity:

POST /api/friends/reset
POST /api/friends
GET /api/friends/4
POST /api/friends/4/make-best-friend
GET /api/friends?limit=besties
GET /api/friends/43?callback=angular.callbacks._0

Of course, you don't have to use the resource part of the module; the resource is kind of like a preprocessor for the httpi service which is, itself, a preprocessor for the $http service. If you call the httpi service directly, you'll still get the URL interpolation - you simply have to pass-in the URL with each request.

Obviously, the value of this module is heavily colored by my own experience with the $resource module in AngularJS. If you're loving $resource, I am not suggesting that you stop using it. But, for me personally, it wasn't a huge value-add. So, I tried to take the parts that I did like and rebuild them on top of the $http service in a very transparent way.

Want to use code from this post? Check out the license.

Reader Comments

3 Comments

Couldn't this be written into a decorator in order to avoid having to inject the wrapping service instead of the original $http?

15,423 Comments

@Michael,

You probably could. I'm only recently learning about decorators; so, at the time I wrote this, it wasn't an option for me personally.

1 Comments

@Michael,

I tried to take a look in your implementation as decorator but the link is dead, perhaps you can update it. Thanks !

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel