In AngularJS, $httpInterceptor
is a powerful mechanism to intercept HTTP requests and responses globally. This helps in adding headers, logging, modifying responses, handling errors, and implementing authentication logic without modifying every $http
request.
1. What is $httpInterceptor
?
- It is a factory that allows us to intercept every HTTP request and response.
- We can modify them before they are sent or processed.
- It is added using
$httpProvider.interceptors.push()
.
2. Creating an $httpInterceptor
We define an interceptor as a factory service and push it to $httpProvider
.
Basic Structure of $httpInterceptor
myApp.factory('ApiInterceptor', function($q, $rootScope, $injector) {
return {
// Intercept the request before sending
request: function(config) {
console.log('Outgoing request:', config);
return config;
},
// Handle request errors
requestError: function(rejection) {
console.error('Request error:', rejection);
return $q.reject(rejection);
},
// Intercept the response before passing it to the caller
response: function(response) {
console.log('Incoming response:', response);
return response;
},
// Handle response errors
responseError: function(response) {
console.error('Response error:', response);
return $q.reject(response);
}
};
});
// Add interceptor to $httpProvider
myApp.config(function($httpProvider) {
$httpProvider.interceptors.push('ApiInterceptor');
});
Key Points:
✔ request
→ Modify or log request before it is sent.
✔ requestError
→ Handle request failures (e.g., network issues).
✔ response
→ Modify or log the response before it reaches the caller.
✔ responseError
→ Handle errors globally (e.g., 401 Unauthorized, 500 Server Error).
3. Adding Authentication Token to Requests
A common use case is adding a JWT token or API key in headers for authentication.
myApp.factory('AuthInterceptor', function($q, $injector) {
return {
request: function(config) {
var token = localStorage.getItem('authToken'); // Get stored token
if (token) {
config.headers.Authorization = 'Bearer ' + token;
}
return config;
},
responseError: function(response) {
if (response.status === 401) {
console.warn('Unauthorized! Redirecting to login...');
var $state = $injector.get('$state');
$state.go('login'); // Redirect user to login page
}
return $q.reject(response);
}
};
});
// Register the interceptor
myApp.config(function($httpProvider) {
$httpProvider.interceptors.push('AuthInterceptor');
});
Benefits:
✔ Automatically attaches tokens to every request.
✔ Redirects unauthenticated users to the login page.
4. Handling API Errors Globally
Instead of handling errors in every $http
call, use an interceptor.
myApp.factory('ErrorInterceptor', function($q, $rootScope) {
return {
responseError: function(response) {
switch (response.status) {
case 400:
alert("Bad Request: " + response.data.message);
break;
case 401:
$rootScope.$broadcast('unauthorized');
break;
case 403:
alert("Forbidden: You don't have permission!");
break;
case 404:
alert("Not Found: The requested resource doesn't exist.");
break;
case 500:
alert("Server Error: Please try again later.");
break;
}
return $q.reject(response);
}
};
});
// Register the interceptor
myApp.config(function($httpProvider) {
$httpProvider.interceptors.push('ErrorInterceptor');
});
Advantages:
✔ Centralized error handling for all API requests.
✔ Avoids duplicate error handling in controllers.
5. Logging API Requests & Responses
For debugging, log every request and response.
myApp.factory('LoggerInterceptor', function() {
return {
request: function(config) {
console.log('Request:', config.method, config.url);
return config;
},
response: function(response) {
console.log('Response:', response.status, response.config.url);
return response;
}
};
});
myApp.config(function($httpProvider) {
$httpProvider.interceptors.push('LoggerInterceptor');
});
Advantages:
✔ Helps in debugging API issues.
✔ Logs every request and response.
6. Implementing Retry Logic for API Calls
If an API call fails, retry it a few times before failing completely.
myApp.factory('RetryInterceptor', function($q, $injector) {
return {
responseError: function(response) {
var retries = response.config.retries || 3; // Default 3 retries
if (retries > 0) {
console.log(`Retrying ${response.config.url}, attempts left: ${retries - 1}`);
var $http = $injector.get('$http');
response.config.retries = retries - 1;
return $http(response.config);
}
return $q.reject(response);
}
};
});
// Register the interceptor
myApp.config(function($httpProvider) {
$httpProvider.interceptors.push('RetryInterceptor');
});
Benefits:
✔ Retries failed API calls automatically.
✔ Reduces network failure impact.
7. Combining Multiple Interceptors
We can use multiple interceptors together:
myApp.config(function($httpProvider) {
$httpProvider.interceptors.push('AuthInterceptor');
$httpProvider.interceptors.push('ErrorInterceptor');
$httpProvider.interceptors.push('LoggerInterceptor');
});