In angular 1.x are interceptors always factories? - angularjs

I'm trying to wrap my head around interceptors, I still can't figure them out. Can someone explain a tad more for me about if they are a service, a config, etc?

Interceptors can be either a named factory or an anonymous factory.
app.config(function ($httpProvider) {
//register the interceptor factory
$httpProvider.interceptors.push('myHttpInterceptor');
// alternatively, register the interceptor via an anonymous factory
$httpProvider.interceptors.push(function($q, dependency1, dependency2) {
return {
'request': function(config) {
// request transform
},
'response': function(response) {
// response transform
}
};
});
});
Interceptors are registered during the config phase of the AngularJS app. Their factory functions (either named or anonymous) are invoked during the $get phase of the $http service.
For more information, see AngularJS $http Service API Reference - Interceptors

Related

Angular load controller after service has aquired a swagger api file

I have a controller that uses a swagger-js enabled api. However the api is unavailable until the swagger library aquires the swagger sepcification file. I would like that the controller that has this as an API to load only after the swagger API is avaible and ready to use.
How can I achieve this?
You will have to keep your controller (did you mean service?) in an initialization phase while Swagger is getting configured.
I would do it by having a $q Promise which resolves when Swagger is configured and then design all other functions on the controller (I would write a service wrapper around it, though), to return Promises which depends on the then branch of the initialization promise.
The implementation will be something along these lines:
angular.module('myModule', [])
.service('swaggerService', ['$q', function ($q) {
var deferred = $q.Promise(),
initPromise = deferred.promise;
// This function should be called when Swagger is done initializing.
// It may be best to initialize Swagger here itself, if that is an option.
swatterInitCb(function (err) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve();
}
});
return {
// This function will return a Promise.
getData: function (dataId) {
return initPromise.then(function (dataId) {
// Use Swagger (which is now guaranteed to be intialised)
// to get data from dataId
return data;
});
}
}
});

Inject http into httpProvider in AngularJS

I want to make it so that users are automatically logged out by having the client terminate the session (as opposed to letting the session die on its own). I pushed an interceptor onto the $httpProvider which allows me to set and reset the timeout timer, but the problem is that I can't figure out how to call the logout function which requires $http. This always produces a circular dependency. Is there any way to do this?
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(
function() {
return {
response: function(response) { $http({ ... }); }
})}
If I make $http a dependency, I get a circular dependency, but without the $http dependency, the call to $http obviously doesn't work.
You should be careful using $http inside an interceptor as it has the potential to cause an infinite loop. Consider refactoring so $http isn't required
That said you can try injecting the $injector instead. Then where you want to make the $http request just use $injector.get('$http')
app.config(['$httpProvider, $injector', function($httpProvider, $injector) {
$httpProvider.interceptors.push(
function() {
return {
response: function(response) { $injector.get('$http') }
})}
You need to inject $http dependancy inside theinceptor.push function, you could also inject other dependencies from there.
Code
app.config(['$httpProvider',
function($httpProvider) {
$httpProvider.interceptors.push(
function($http) { //<--here you could make dependency available.
return {
response: function(response) {
$http({...});
}
})
}])
I used a crossover of the previous answers (use $injector, but in the push() ) to get it working as expected:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(function($q, $injector) {
...
//now get $http like this and use it as needed:
$injector.get('$http')

Configuring external http service in angularjs

I have a single page angular app which calls a RESTish service. How can I configure the base URL for my REST server so that in my services I can use relative URLs? Also, as I was playing around with the following interceptor I got an error where angular-ui router seemed to be using http to get views so this was affected by the middleware. Basically I guess I want a second http service to inject into my services that has this middleware, how can I do this?
app.config(["$httpProvider", function($httpProvider) {
$httpProvider.interceptors.push('middleware');
}]);
app.factory('middleware', function() {
return {
request: function(config) {
// need more controlling when there is more than 1 domain involved
config.url = "http://localhost:8080" + config.url;
return config;
}
};
});
The $http services is very important (and widely used) inside Angular.
You shouldn't alter it like this.
For handling requests to an API, it is best to create a dedicated service (even if it's a wrapper around $http).
E.g.:
.service('API', function ($http) {
var baseUrl = 'http://localhost:8080/';
this.get = function (path, config) {
return $http.get(baseUrl + path, config);
}
...
});
Then you can use your service for all API calls:
.controller('someCtrl', function (API) {
API.get('items').success(function (data) {
$scope.items = data;
});
});

AngularJS $resource interceptors

How do I add interceptors to a $resource call?
Let's say I have a resource factory called Users, like so;
app.factory('Users', ['$resource', 'resourceInterceptor',
function ($resource, resourceInterceptor) {
return $resource(
'users/:user_id',
{
user_id: '#id'
},
{
query: {
method: 'GET', // Not changing the default method, just adding an interceptor
interceptor: resourceInterceptor // Is there any better way to do this.. like globally?
},
save: {
method: 'POST', // Same here
interceptor: resourceInterceptor // Again...
},
..., // And so on
}
);
}]);
and my resourceInterceptor service looks like;
app.factory('resourceInterceptor', ['$rootScope',
function ($rootScope) {
return {
request: function () {
// This function isn't executed at all?
$rootScope.loading = true;
},
response: function () {
$rootScope.loading = false;
},
responseError: function () {
$rootScope.loading = false;
}
};
}]);
First of all, the request intercept function is never executed, why not?
Secondly, having to hardcode the interceptor to existing $resource methods is very tedious , is there a way to easier assign interceptors to specific $resource calls, or maybe even assign an interceptor to all $resource calls?
To use an interceptor in a resource you should:
1 - Make an httpInterceptor with you request, response, responseError:
app.factory('myInterceptor', function () {
//Code
//return { request:...,
});
2 - Config this Interceptor in your app:
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('myInterceptor');
}]);
Right now as you have config your httpProvider to has an interceptor wherever you inject $http you will use this provider so... you will excute your request, response and responseError funciton.
3 - Using it in a resource.
As $resource use $http and you have config a httpProvider globaly you will call your interceptors' func when you use your resource.
Second question:
You can not set an interceptor to a concrete $http object, they (interceptors) are set globally.
(Even if you set the interceptor before your module definition and then you remove it, you can not know the execution order)
What you can do if you do not want to override the interceptor property in each $resource action (as you write in your question) you can improve your interceptor.
app.factory('userLoadingInterceptor', function () {
//Code
return {
request: function(){
//Check if your are working with a url related with users
// and if so do things...
}
});
From the docs:
The interceptor object has two optional methods - response and responseError
I don't know what you want to achieve but generic HTTP interceptors might be an alternative.
A generic HTTP Interceptor should do what you want. You can find a sample here: Handle HTTP 302 response from proxy in angularjs.

Restangular - $http interceptors

Morning,
I have a $http interceptor:
app.factory('Unauthed', ['$q', 'alertService',function($q,alertService) {
return {
response: function (response) {
if (response.status == 401)
alertService.error('Authentication failure.',15000);
return response || $q.when(response);
}
};
}]);
This runs fine for all requests which are going through $http but non which go through Restangular. Looking through the soure Restangular uses $http so I am not sure what is going on here?
Cheers
Maybe the order of execution matters, where are you registering restangular? Also maybe order of dependnecies of angular modules, try declaring restangular as dependency of submodules but not in main app module so that $http is already decorated when you add restangular.

Resources