Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit d96e58f

Browse files
kaufholdrgkalpak
authored andcommitted
feat($resource): add hasBody action configuration option
By default, only `PUT`, `POST` and `PATCH` requests have a body, but you can use `hasBody` to configure any action to either have or not have a body, regardless of its HTTP method. Fixes #10128 Closes #12181
1 parent 70dbb15 commit d96e58f

File tree

2 files changed

+84
-6
lines changed

2 files changed

+84
-6
lines changed

src/ngResource/resource.js

+14-6
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ function shallowClearAndCopy(src, dst) {
125125
* URL `/path/greet?salutation=Hello`.
126126
*
127127
* If the parameter value is prefixed with `@`, then the value for that parameter will be
128-
* extracted from the corresponding property on the `data` object (provided when calling a
129-
* "non-GET" action method).
128+
* extracted from the corresponding property on the `data` object (provided when calling actions
129+
* with a request body).
130130
* For example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of
131131
* `someParam` will be `data.someProp`.
132132
* Note that the parameter will be ignored, when calling a "GET" action method (i.e. an action
@@ -193,6 +193,8 @@ function shallowClearAndCopy(src, dst) {
193193
* - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
194194
* `response` and `responseError`. Both `response` and `responseError` interceptors get called
195195
* with `http response` object. See {@link ng.$http $http interceptors}.
196+
* - **`hasBody`** - `{boolean}` - allows to specify if a request body should be included or not.
197+
* If not specified only POST, PUT and PATCH requests will have a body.
196198
*
197199
* @param {Object} options Hash with custom settings that should extend the
198200
* default `$resourceProvider` behavior. The supported options are:
@@ -237,9 +239,15 @@ function shallowClearAndCopy(src, dst) {
237239
* The action methods on the class object or instance object can be invoked with the following
238240
* parameters:
239241
*
240-
* - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
241-
* - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
242-
* - non-GET instance actions: `instance.$action([parameters], [success], [error])`
242+
* - "class" actions without a body: `Resource.action([parameters], [success], [error])`
243+
* - "class" actions with a body: `Resource.action([parameters], postData, [success], [error])`
244+
* - instance actions: `instance.$action([parameters], [success], [error])`
245+
*
246+
*
247+
* When calling instance methods, the instance itself is used as the request body (if the action
248+
* should have a body). By default, only actions using `POST`, `PUT` or `PATCH` have request
249+
* bodies, but you can use the `hasBody` configuration option to specify whether an action
250+
* should have a body or not (regardless of its HTTP method).
243251
*
244252
*
245253
* Success callback is called with (value (Object|Array), responseHeaders (Function),
@@ -643,7 +651,7 @@ angular.module('ngResource', ['ng']).
643651
};
644652

645653
forEach(actions, function(action, name) {
646-
var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
654+
var hasBody = action.hasBody === true || (action.hasBody !== false && /^(POST|PUT|PATCH)$/i.test(action.method));
647655
var numericTimeout = action.timeout;
648656
var cancellable = isDefined(action.cancellable) ?
649657
action.cancellable : route.defaults.cancellable;

test/ngResource/resourceSpec.js

+70
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,76 @@ describe('basic usage', function() {
9797
$httpBackend.flush();
9898
});
9999

100+
it('should include a request body when calling custom method with hasBody is true', function() {
101+
var instant = {name: 'info.txt'};
102+
var condition = {at: '2038-01-19 03:14:08'};
103+
104+
$httpBackend.expect('CREATE', '/fooresource', instant).respond({fid: 42});
105+
$httpBackend.expect('DELETE', '/fooresource', condition).respond({});
106+
107+
var r = $resource('/fooresource', {}, {
108+
create: {method: 'CREATE', hasBody: true},
109+
delete: {method: 'DELETE', hasBody: true}
110+
});
111+
112+
var creationResponse = r.create(instant);
113+
var deleteResponse = r.delete(condition);
114+
115+
$httpBackend.flush();
116+
117+
expect(creationResponse.fid).toBe(42);
118+
expect(deleteResponse.$resolved).toBe(true);
119+
});
120+
121+
it('should not include a request body if hasBody is false on POST, PUT and PATCH', function() {
122+
function verifyRequest(method, url, data) {
123+
expect(data).toBeUndefined();
124+
return [200, {id: 42}];
125+
}
126+
127+
$httpBackend.expect('POST', '/foo').respond(verifyRequest);
128+
$httpBackend.expect('PUT', '/foo').respond(verifyRequest);
129+
$httpBackend.expect('PATCH', '/foo').respond(verifyRequest);
130+
131+
var R = $resource('/foo', {}, {
132+
post: {method: 'POST', hasBody: false},
133+
put: {method: 'PUT', hasBody: false},
134+
patch: {method: 'PATCH', hasBody: false}
135+
});
136+
137+
var postResponse = R.post();
138+
var putResponse = R.put();
139+
var patchResponse = R.patch();
140+
141+
$httpBackend.flush();
142+
143+
expect(postResponse.id).toBe(42);
144+
expect(putResponse.id).toBe(42);
145+
expect(patchResponse.id).toBe(42);
146+
});
147+
148+
it('should expect a body if hasBody is true', function() {
149+
var username = 'yathos';
150+
var loginRequest = {name: username, password: 'Smile'};
151+
var user = {id: 1, name: username};
152+
153+
$httpBackend.expect('LOGIN', '/user/me', loginRequest).respond(user);
154+
155+
$httpBackend.expect('LOGOUT', '/user/me', null).respond(null);
156+
157+
var UserService = $resource('/user/me', {}, {
158+
login: {method: 'LOGIN', hasBody: true},
159+
logout: {method: 'LOGOUT', hasBody: false}
160+
});
161+
162+
var loginResponse = UserService.login(loginRequest);
163+
var logoutResponse = UserService.logout();
164+
165+
$httpBackend.flush();
166+
167+
expect(loginResponse.id).toBe(user.id);
168+
expect(logoutResponse.$resolved).toBe(true);
169+
});
100170

101171
it('should build resource', function() {
102172
expect(typeof CreditCard).toBe('function');

0 commit comments

Comments
 (0)