Choosing Between AngularJS $http and $resource for RESTful API Calls
Decide whether to use AngularJS’s $http or $resource for RESTful calls. Compare abstraction, CRUD support, custom endpoints, and testability in a concise table, then see concrete code examples and validation steps.
21 Mar 2026, 05:19 UTC

Decision Context
When building an AngularJS (1.x) application that consumes a RESTful backend, you’ll almost always need a way to issue HTTP requests. AngularJS ships with two built‑in services for this purpose: $http, a low‑level promise‑based API, and $resource, a higher‑level wrapper that maps REST endpoints to resource objects. The choice between them can affect code size, maintainability, performance, and testability.
Constraints to Consider
- Project scope: Do you need only CRUD operations or also custom actions?
- Team familiarity: Is the team comfortable with promises or with resource objects?
- Dependency footprint:
$resourcerequires thengResourcemodule;$httpis part of core. - Performance needs: For high‑traffic APIs, the overhead of
$resourcemay matter. - Testing strategy: How will you mock HTTP calls in unit tests?
- Future migration: AngularJS is end‑of‑life; consider whether you’ll migrate to Angular or another framework.
Option Comparison Table
| Feature | $http | $resource |
|---|---|---|
| Abstraction level | Low‑level, full control over request/response | High‑level, maps to CRUD methods (get, save, query, remove, delete) |
| CRUD support | Manual: you choose HTTP verb and payload | Automatic: methods generate URLs and payloads based on model |
| Custom endpoints | Easy: specify any URL and method | Possible via action config, but more verbose |
| Dependency | Core AngularJS (no extra module) | Requires angular-resource.js and ngResource module |
| Performance | Lower overhead | Small wrapper overhead, negligible for most apps |
| Testing | Stub $httpBackend for each call | Stub $httpBackend or use mockResource utilities |
| Interceptors | Full support via $httpProvider.interceptors | Indirect: interceptors see underlying $http calls |
| URL generation | Manual: you build the string | Auto‑generated based on url template and parameters |
| Stateful objects | No built‑in; you manage data yourself | Returns resource instances that can be updated with $save etc. |
Trade‑offs
Control vs. Convenience$http gives you granular control over headers, query parameters, and interceptors. If your API requires non‑standard headers or you need to manipulate the request payload in ways that don’t map to a simple CRUD pattern, $http is the safer choice.
Boilerplate Reduction
With $resource, you write a single definition and get a suite of methods for free. This reduces repetitive code, especially for CRUD‑heavy services.
Testing Complexity
Both services rely on $httpBackend for mocking, but $resource adds an extra abstraction layer that can make test expectations slightly more involved. However, many teams find the reduced boilerplate worth the extra test setup.
Performance
The overhead of $resource is minimal (a few micro‑seconds). In most applications, the difference is not noticeable. If you’re building a high‑throughput API client, benchmark both approaches to be sure.
Choosing the Right Tool
Use $resource when:
- Your API follows RESTful conventions (GET, POST, PUT/PATCH, DELETE).
- You want CRUD methods with minimal code.
- Stateful resource instances (e.g.,
item.$save()) improve readability.
Use $http when:
- You need custom endpoints, such as
/api/items/42/activatethat don’t fit CRUD. - Headers or request transformations are required on a per‑call basis.
- You want to avoid adding the
ngResourcedependency.
Concrete Implementation Example
Below is a minimal AngularJS module that demonstrates both approaches to fetching a list of items from /api/items and retrieving a single item by ID.
Using $resource
// app.js
angular.module('myApp', ['ngResource'])
.factory('Item', ['$resource', function($resource) {
return $resource('/api/items/:id', {id: '@id'}, {
query: {method: 'GET', isArray: true},
get: {method: 'GET'},
save: {method: 'POST'},
update: {method: 'PUT'},
delete: {method: 'DELETE'}
});
}])
.controller('ItemCtrl', ['Item', function(Item) {
// List all items
this.items = Item.query();
// Get a single item
this.load = function(id) {
this.item = Item.get({id: id});
};
}]);
Using $http
// app.js
angular.module('myApp', [])
.controller('ItemCtrl', ['$http', function($http) {
var vm = this;
// List all items
vm.list = function() {
return $http.get('/api/items').then(function(res) {
vm.items = res.data;
});
};
// Get a single item
vm.load = function(id) {
return $http.get('/api/items/' + id).then(function(res) {
vm.item = res.data;
});
};
}]);
Testing & Validation
Both services can be unit‑tested with $httpBackend. The following outlines a typical validation workflow:
- Start a browser and open the dev tools network tab.
- Trigger the controller’s
list()orload()method. - Verify that the request URL matches the expected pattern (e.g.,
/api/itemsor/api/items/42). - Check that the HTTP method is correct (GET for read, POST/PUT for create/update).
- Confirm that the response payload is assigned to the scope variable (e.g.,
vm.items). - In unit tests, use
$httpBackend.expectGET('/api/items').respond(200, [{id:1}])and assert that the controller receives the array.
For $resource, you can also use angular-mocks’ $resourceBackend helper to mock responses if you prefer to avoid $httpBackend directly.
Limitations & Migration Note
AngularJS is in end‑of‑life mode. For new projects, consider migrating to Angular (v12+) or another modern framework. If you must stay on AngularJS, keep the ngResource dependency minimal and document any custom actions clearly to aid future migration.
Practical Checklist
- Do you need a CRUD‑style API?
$resourcemay be the fastest path. - Are you calling non‑CRUD endpoints or setting custom headers? Use
$http. - Do you want to reduce boilerplate and use resource instances?
$resourceis ideal. - Is dependency size a concern?
$httphas no extra module. - Do you have an existing test suite that mocks
$httpBackend? You can extend it for$resourcewith minimal changes.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.