An introduction to $http intercetors or $http middlewares

$http service in angular.js is like $.ajax module in jQuery. Both work in same way. But unlike $.ajax, $http provides promised based api and can be configured.

Basically with $http service, you can send ajax requests to external web servers. It uses browsers XMLHttpRequest api. But a lot of problem arises when you need a common functionality for all or some ajax requests. Let’s say that you need to log in console when a http request is sent and when response was received from that request. $.ajaxSetup in case of jQuery provides support for setting global options of ajax request but they don’t exactly preprocess requests and they are not recommended.

If you have used express.js then you might be familiar with term middleware. You can add a middleware in $httpservice which have access to request and response object. As we are intercepting request before it is sent and response before is it consumed by client, this middleware called as interceptor.

Basically, angular provides $httpProvider which is used to decorate $http service. $httpProvider containinterceptors field which is an array of middlewares. So you can push new middleware like below

myApp.config(function($httpProvider){
$httpProvider.interceptors.push(middleware);
});

Creating a middleware

A middleware is a angular factory/service with following properties

$provide.factory('myHttpInterceptor', function($q){
return {
'request': function(request) {
return request;
},
        'requestError': function(request) {
return $q.reject(request);
},
        'response': function(response) {
return response;
},
        'responseError': function(response) {
return $q.reject(response);
}
};
});

Above myHttpInterceptor factory is basic middleware which is ready to be pushed in http interceptors.

myApp.config(function($httpProvider){
$httpProvider.interceptors.push('myHttpInterceptor');
});

Before I explain what these four property mean, I just want to clarify something. As we have seen above, we are pushing name of the factory inside http interceptors, it will look for that factory in angular global namespace. But sometimes, we don’t want to make that factory public, rather it should be anonymous.

Well, that is possible and can be done by pushing factory constructor in interceptors rather than it’s name.

myApp.config(function($httpProvider){
$httpProvider.interceptors.push(function($q){
return {
'request': function(request) {
return request;
},
...
}
});
});

Great. Now let’s take a look at each options.

request

interceptors get called with a http config object. The function is free to modify the config object or create a new one. The function needs to return the config object directly, or a promise containing the config or a new config object.

What this means is that all the request payload you sent with a http request will be intercepted here. You are free to transform it in any way possible, but you need to return that payload so that request can carry it out further. You can also return promise which should return response object when it resolves.

'request': function(request) {
request.myfield = 'Hello World!';
    console.log('request sent!');
return request;
// return $q.when(request);
},

requestError

interceptor gets called when a previous interceptor threw an error or resolved with a rejection.

As a request has to go through series of interceptors and if any of previous interceptor/middleware threw an error because you are very bad at writing a javascript or if you validate something in previous middleware which did not work so you returned rejected promise, then that will caught by this block.

'requestError': function(request) {
console.log('request could not be sent!');
return $q.reject(request);
},

Here instead of returning plain request object, you need to send rejected promise so that your $http block can use rejected callback of then function.

$http({}).then(fn, function(){
//=> 'request could not be sent!'
});

response

interceptors get called with http response object. The function is free to modify the response object or create a new one. The function needs to return the response object directly, or as a promise containing the response or a new response object.

This block is used after a response was received from a request which has status code between 100–399. You have access to response object which you can modify and then return. You can also get request object which was used for this request from response.config.

'response': function(response) {
//key1,key2 => ['key1', 'key2']
response.keywords = response.keywords.split(',');
    console.log('response received!');
return response;
// return $q.when(response);
},

responseError

interceptor gets called when a previous interceptor threw an error or resolved with a rejection.

This is same as requestError in every way but in this block you have access to response object and this block will be used when response was received with 400–500 status code. Here instead of returning plain response object, you need to send rejected promise so that your $http block can use rejected callback of then function.

'responseError': function(response) {
console.log('bad response from a server!');
return $q.reject(response);
},

$http interceptors are very useful when you need to process some/all http requests for some sort of validation or magic. I have created a spinner animation module ng-spin for angular using http interceptors where a spinner is shown on a page when a request is sent and removed when request fails or on response. You should give it a try and it is super easy to use.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.