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

Commit a8f7e9c

Browse files
realitykingpetebacondarwin
authored andcommitted
feat($httpProvider): add 'useLegacyPromiseExtensions' configuration
The legacy methods, `success` and `error`, have been deprecated. Set this to `false` to cause `$http` to throw an error if these methods are used in the application. For now it defaults to `true`. In a future release we will remove these methods altogether. DEPRECATION NOTICE: The legacy methods 'success' and 'error' on promises returned by $http are now deprecated. Closes #12112 Closes #10508
1 parent 7b8a16b commit a8f7e9c

File tree

3 files changed

+155
-50
lines changed

3 files changed

+155
-50
lines changed

docs/content/error/$http/legacy.ngdoc

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
@ngdoc error
2+
@name $http:legacy
3+
@fullName The `success` and `error` methods on the promise returned from `$http` have been disabled.
4+
@description
5+
6+
This error occurs when the legacy promise extensions (`success` and `error`)
7+
{@link $httpProvider#useLegacyPromiseExtensions legacy `$http` promise extensions} have been disabled.
8+
9+
To resolve this error, either turn on the legacy extensions by adding
10+
`$httpProvider.useLegacyPromiseExtensions(true);` to your application's configuration; or refactor you
11+
use of `$http` to use `.then()` rather than `.success()` and `.error()`.
12+
13+
For example if you code looked like this:
14+
15+
```js
16+
// Simple GET request example :
17+
$http.get('/someUrl').
18+
success(function(data, status, headers, config) {
19+
// This callback will be called asynchronously
20+
// when the response is available
21+
}).
22+
error(function(data, status, headers, config) {
23+
// called asynchronously if an error occurs
24+
// or server returns response with an error status.
25+
});
26+
```
27+
28+
then you would change it to look like:
29+
30+
```js
31+
// Simple GET request example :
32+
$http.get('/someUrl').
33+
then(function(response) {
34+
// (The response object contains the data, status, headers and config properties)
35+
// This callback will be called asynchronously
36+
// when the response is available.
37+
}, function(response) {
38+
// called asynchronously if an error occurs
39+
// or server returns response with an error status.
40+
});
41+
```
42+
43+
For more information, see the
44+
{@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`}
45+
documentation.

src/ng/http.js

+80-50
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ var JSON_ENDS = {
88
'{': /}$/
99
};
1010
var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
11+
var $httpMinErr = minErr('$http');
12+
var $httpMinErrLegacyFn = function(method) {
13+
return function() {
14+
throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);
15+
};
16+
};
1117

1218
function serializeValue(v) {
1319
if (isObject(v)) {
@@ -330,6 +336,30 @@ function $HttpProvider() {
330336
return useApplyAsync;
331337
};
332338

339+
var useLegacyPromse = true;
340+
/**
341+
* @ngdoc method
342+
* @name $httpProvider#useLegacyPromiseExtensions
343+
* @description
344+
*
345+
* Configure `$http` service to return promises without the shorthand methods `success` and `error`.
346+
* This should be used to make sure that applications work without these methods.
347+
*
348+
* Defaults to false. If no value is specified, returns the current configured value.
349+
*
350+
* @param {boolean=} value If true, `$http` will return a normal promise without the `success` and `error` methods.
351+
*
352+
* @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
353+
* otherwise, returns the current configured value.
354+
**/
355+
this.useLegacyPromiseExtensions = function(value) {
356+
if (isDefined(value)) {
357+
useLegacyPromse = !!value;
358+
return this;
359+
}
360+
return useLegacyPromse;
361+
};
362+
333363
/**
334364
* @ngdoc property
335365
* @name $httpProvider#interceptors
@@ -396,17 +426,15 @@ function $HttpProvider() {
396426
*
397427
* ## General usage
398428
* The `$http` service is a function which takes a single argument — a configuration object —
399-
* that is used to generate an HTTP request and returns a {@link ng.$q promise}
400-
* with two $http specific methods: `success` and `error`.
429+
* that is used to generate an HTTP request and returns a {@link ng.$q promise}.
401430
*
402431
* ```js
403432
* // Simple GET request example :
404433
* $http.get('/someUrl').
405-
* success(function(data, status, headers, config) {
434+
* then(function(response) {
406435
* // this callback will be called asynchronously
407436
* // when the response is available
408-
* }).
409-
* error(function(data, status, headers, config) {
437+
* }, function(response) {
410438
* // called asynchronously if an error occurs
411439
* // or server returns response with an error status.
412440
* });
@@ -415,21 +443,23 @@ function $HttpProvider() {
415443
* ```js
416444
* // Simple POST request example (passing data) :
417445
* $http.post('/someUrl', {msg:'hello word!'}).
418-
* success(function(data, status, headers, config) {
446+
* then(function(response) {
419447
* // this callback will be called asynchronously
420448
* // when the response is available
421-
* }).
422-
* error(function(data, status, headers, config) {
449+
* }, function(response) {
423450
* // called asynchronously if an error occurs
424451
* // or server returns response with an error status.
425452
* });
426453
* ```
427454
*
455+
* The response object has these properties:
428456
*
429-
* Since the returned value of calling the $http function is a `promise`, you can also use
430-
* the `then` method to register callbacks, and these callbacks will receive a single argument –
431-
* an object representing the response. See the API signature and type info below for more
432-
* details.
457+
* - **data** – `{string|Object}` – The response body transformed with the transform
458+
* functions.
459+
* - **status** – `{number}` – HTTP status code of the response.
460+
* - **headers** – `{function([headerName])}` – Header getter function.
461+
* - **config** – `{Object}` – The configuration object that was used to generate the request.
462+
* - **statusText** – `{string}` – HTTP status text of the response.
433463
*
434464
* A response status code between 200 and 299 is considered a success status and
435465
* will result in the success callback being called. Note that if the response is a redirect,
@@ -453,8 +483,8 @@ function $HttpProvider() {
453483
* request data must be passed in for POST/PUT requests.
454484
*
455485
* ```js
456-
* $http.get('/someUrl').success(successCallback);
457-
* $http.post('/someUrl', data).success(successCallback);
486+
* $http.get('/someUrl').then(successCallback);
487+
* $http.post('/someUrl', data).then(successCallback);
458488
* ```
459489
*
460490
* Complete list of shortcut methods:
@@ -468,6 +498,14 @@ function $HttpProvider() {
468498
* - {@link ng.$http#patch $http.patch}
469499
*
470500
*
501+
* ## Deprecation Notice
502+
* <div class="alert alert-danger">
503+
* The `$http` legacy promise methods `success` and `error` have been deprecated.
504+
* Use the standard `then` method instead.
505+
* If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to
506+
* `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.
507+
* </div>
508+
*
471509
* ## Setting HTTP Headers
472510
*
473511
* The $http service will automatically add certain HTTP headers to all requests. These defaults
@@ -511,7 +549,7 @@ function $HttpProvider() {
511549
* data: { test: 'test' }
512550
* }
513551
*
514-
* $http(req).success(function(){...}).error(function(){...});
552+
* $http(req).then(function(){...}, function(){...});
515553
* ```
516554
*
517555
* ## Transforming Requests and Responses
@@ -743,7 +781,6 @@ function $HttpProvider() {
743781
* In order to prevent collisions in environments where multiple Angular apps share the
744782
* same domain or subdomain, we recommend that each application uses unique cookie name.
745783
*
746-
*
747784
* @param {object} config Object describing the request to be made and how it should be
748785
* processed. The object has following properties:
749786
*
@@ -788,20 +825,9 @@ function $HttpProvider() {
788825
* - **responseType** - `{string}` - see
789826
* [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
790827
*
791-
* @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
792-
* standard `then` method and two http specific methods: `success` and `error`. The `then`
793-
* method takes two arguments a success and an error callback which will be called with a
794-
* response object. The `success` and `error` methods take a single argument - a function that
795-
* will be called when the request succeeds or fails respectively. The arguments passed into
796-
* these functions are destructured representation of the response object passed into the
797-
* `then` method. The response object has these properties:
828+
* @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
829+
* when the request succeeds or fails.
798830
*
799-
* - **data** – `{string|Object}` – The response body transformed with the transform
800-
* functions.
801-
* - **status** – `{number}` – HTTP status code of the response.
802-
* - **headers** – `{function([headerName])}` – Header getter function.
803-
* - **config** – `{Object}` – The configuration object that was used to generate the request.
804-
* - **statusText** – `{string}` – HTTP status text of the response.
805831
*
806832
* @property {Array.<Object>} pendingRequests Array of config objects for currently pending
807833
* requests. This is primarily meant to be used for debugging purposes.
@@ -843,13 +869,12 @@ function $HttpProvider() {
843869
$scope.response = null;
844870
845871
$http({method: $scope.method, url: $scope.url, cache: $templateCache}).
846-
success(function(data, status) {
847-
$scope.status = status;
848-
$scope.data = data;
849-
}).
850-
error(function(data, status) {
851-
$scope.data = data || "Request failed";
852-
$scope.status = status;
872+
then(function(response) {
873+
$scope.status = response.status;
874+
$scope.data = response.data;
875+
}, function(response) {
876+
$scope.data = response.data || "Request failed";
877+
$scope.status = response.status;
853878
});
854879
};
855880
@@ -954,23 +979,28 @@ function $HttpProvider() {
954979
promise = promise.then(thenFn, rejectFn);
955980
}
956981

957-
promise.success = function(fn) {
958-
assertArgFn(fn, 'fn');
982+
if (useLegacyPromse) {
983+
promise.success = function(fn) {
984+
assertArgFn(fn, 'fn');
959985

960-
promise.then(function(response) {
961-
fn(response.data, response.status, response.headers, config);
962-
});
963-
return promise;
964-
};
986+
promise.then(function(response) {
987+
fn(response.data, response.status, response.headers, config);
988+
});
989+
return promise;
990+
};
965991

966-
promise.error = function(fn) {
967-
assertArgFn(fn, 'fn');
992+
promise.error = function(fn) {
993+
assertArgFn(fn, 'fn');
968994

969-
promise.then(null, function(response) {
970-
fn(response.data, response.status, response.headers, config);
971-
});
972-
return promise;
973-
};
995+
promise.then(null, function(response) {
996+
fn(response.data, response.status, response.headers, config);
997+
});
998+
return promise;
999+
};
1000+
} else {
1001+
promise.success = $httpMinErrLegacyFn('success');
1002+
promise.error = $httpMinErrLegacyFn('error');
1003+
}
9741004

9751005
return promise;
9761006

test/ng/httpSpec.js

+30
Original file line numberDiff line numberDiff line change
@@ -1975,6 +1975,36 @@ describe('$http with $applyAsync', function() {
19751975
});
19761976
});
19771977

1978+
describe('$http without useLegacyPromiseExtensions', function() {
1979+
var $httpBackend, $http;
1980+
beforeEach(module(function($httpProvider) {
1981+
$httpProvider.useLegacyPromiseExtensions(false);
1982+
}, provideLog));
1983+
1984+
beforeEach(inject(['$httpBackend', '$http', '$rootScope', function($hb, $h, $rs) {
1985+
$httpBackend = $hb;
1986+
$http = $h;
1987+
}]));
1988+
1989+
it('should throw when the success or error methods are called if useLegacyPromiseExtensions is false', function() {
1990+
$httpBackend.expect('GET', '/url').respond('');
1991+
var promise = $http({url: '/url'});
1992+
1993+
function callSucess() {
1994+
promise.success();
1995+
}
1996+
1997+
function callError() {
1998+
promise.error();
1999+
}
2000+
2001+
expect(callSucess).toThrowMinErr(
2002+
'$http', 'legacy', 'The method `success` on the promise returned from `$http` has been disabled.');
2003+
expect(callError).toThrowMinErr(
2004+
'$http', 'legacy', 'The method `error` on the promise returned from `$http` has been disabled.');
2005+
});
2006+
});
2007+
19782008
describe('$http param serializers', function() {
19792009

19802010
var defSer, jqrSer;

0 commit comments

Comments
 (0)