Is it possible to specify the order of parameters using the Angular $ http service?
In my Angular app, I have a service that it uses $http
to fetch data from the server. The server endpoint uses HMAC authentication and expects the query string parameters to be in a specific order in the URL.
Angular sorts the parameters $http
when building the URL , so it is not possible to specify the order of the custom parameters.
Here's an example:
this.apiCall = function() {
return $http({
method: 'GET',
url: 'http://example.com/url/v1/endpoint',
params: {
'c': 'cdata',
'a': 'adata',
'b': 'bdata'
}
});
};
Angular build a URL like http://example.com/url/v1/endpoint?a=adata&b=bdata&c=cdata
, but I need to keep the order of the parameters as indicated http://example.com/url/v1/endpoint?c=cdata&a=adata&b=bdata
.
I understand that I can just bind the parameters to the URL string manually, but this is not very convenient and does not make it easy to manage interceptors $http
.
Angular probably sorts the parameters to maintain uniform behavior across browser implementations, since object ordering is not specified in ECMAScript.
Regardless , does anyone know how to get around Angular's default parameter sorting behavior in order to create a URL that stores the parameters specified?
source to share
I improved your solution by making something more streaming and guaranteed to work:
$httpProvider.interceptors.push(function() {
return {
request: function (config) {
if (!config.paramOrder) {
return config;
}
// avoid leaking config modifications
config = angular.copy(config, {});
var orderedParams = [];
config.paramOrder.forEach(function (key) {
if (config.params.hasOwnProperty(key)) {
orderedParams.push(encodeURIComponent(key) + '=' + encodeURIComponent(config.params[key]));
// leave only the unordered params in the `params` config
delete config.params[key];
}
});
config.url += (config.url.indexOf('?') === -1) ? '?' : '&';
config.url += orderedParams.join('&');
return config;
},
};
});
Call the following:
$http({
method: 'GET',
url: 'http://example.com/url/v1/endpoint',
params: {
a: 'aValue',
b: 'bValue',
c: 'cValue'
},
paramOrder: ['c', 'a']
});
to get the query string starting with the key c
and then a
. Parameters not mentioned in paramOrder
will be added after the ordered parameters (in alphabetical order).
source to share
I ended up creating a rudimentary interceptor to save the "as specified" order of parameters. This interceptor is triggered if a $http
configuration variable is set for the call keepParamsOrder
.
In your module config:
$httpProvider.interceptors.push(function() {
return {
'request': function(config) {
if (!config.keepParamsOrder || !config.params) {
return config;
}
var queryStrings = [];
for (var key in config.params) {
if (config.params.hasOwnProperty(key)) {
queryStrings.push(key + '=' + config.params[key]);
}
}
// Reset the params to be empty
config.params = {};
config.url += (config.url.indexOf('?') === -1) ? '?' : '&';
config.url += queryStrings.join('&');
return config;
},
};
});
Tell it to run in the service invocation config:
this.apiCall = function() {
return $http({
method: 'GET',
url: 'http://example.com/url/v1/endpoint',
params: {
'c': 'cdata',
'a': 'adata',
'b': 'bdata'
},
keepParamsOrder: true
});
};
source to share