9

I'm having trouble writing an angular http interceptor in plain TypeScript. The code I'm trying to convert is the following:

.config(['$httpProvider', function ($httpProvider) {

    var interceptor = ['$rootScope', '$q', 'httpBuffer', function ($rootScope, $q, httpBuffer) {
        function success(response) {
            return response;
        }

        function error(response) {
            if (response.status === 401 && !response.config.ignoreAuthModule) {
                var deferred = $q.defer();
                httpBuffer.append(response.config, deferred);
                $rootScope.$broadcast('event:auth-loginRequired', response);
                return deferred.promise;
            }
            // otherwise, default behaviour
            return $q.reject(response);
        }

        return function (promise) {
            return promise.then(success, error);
        };

    }];
    $httpProvider.responseInterceptors.push(interceptor);
}])

The first parts are clear, write a class with a constructor that takes the three dependencies $rootScope, $q and httpBuffer. Also write two private methods success and response.

class MyInterceptorClass {
    constructor(private $rootScope: ng.IRootScopeService, private $q: ng.IQService, private httpBuffer: HttpBuffer) {
    }

    private success(response: ng.IHttpPromiseCallbackArg<any>): ng.IHttpPromiseCallbackArg<any> {
        return response;
    }

    private error(response: ng.IHttpPromiseCallbackArg<any>): ng.IHttpPromiseCallbackArg<any> {
        if (response.status == 401 && !((<any>response.config).ignoreAuthModule)) {
            var deferred = this.$q.defer();
            this.httpBuffer.append(response.config, deferred);
            this.$rootScope.$broadcast('event:auth-loginRequired', response);

            return deferred.promise;
        }

        // Otherwise, default behavior
        return this.$q.reject(response);
    }
}

Also the registration of the interceptor should be clear:

.config(['$httpProvider', ($httpProvider: ng.IHttpProvider)=> {
    $httpProvider.responseInterceptors.push(['$rootScope', '$q', 'httpBuffer', MyInterceptorClass]);
}]);

What I am having trouble with is the last part of the original JavaScript, the return value of an anonymous function. How would I create this in TypeScript? As far as I understood this would be a nameless method in TypeScript, but this is not possible.

5 Answers 5

6

The config settings are as follows

    .config(['$httpProvider', function ($httpProvider: ng.IHttpProvider) {
        $httpProvider.interceptors.push(AuthenticationInterceptor.Factory);
    }])

and your actual class should look as follows

module Common.Security {
'use strict';

export class AuthenticationInterceptor {

    public static Factory($q: ng.IQService) {
        return new AuthenticationInterceptor($q);
    }

    constructor(private $q: ng.IQService) {
    }

    //Method name should be exactly "response" - http://docs.angularjs.org/api/ng/service/$http
    public response(response) {
        console.log(response);
        return response || this.$q.when(response);
    }

    public responseError(rejection) {
        console.log(rejection.status);
        if (rejection.status === 401) {
        }
        // Otherwise, default behavior
        return this.$q.reject(rejection);
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

I am facing issue in this code. Getting error for $q. It shows undefined. Also, could you explain how this works? I mean when this will be invoked and how instance is created. I am pretty new to angular and Typescripts
this will not work see the thread stackoverflow.com/questions/23211692/…
@Abhijeet How do you make the Factory() declaration minification-safe?
6

this is how i write httpinterceptor as a class

module services {

export class ErrorHttpInterceptor {
    public $log:ng.ILogService;
    public $injector:ng.auto.IInjectorService;

    public responseError = (_rejection)=>{
       //handle error here
    };
    public request = (config)=>{
        config.withCredentials = true;
        return config;
    };
    public requestError = (rejection)=>{
        var $q:ng.IQService = this.$injector.get("$q");
        this.$log.log("requestError", rejection);
        return $q.reject(rejection);
    };
    static $inject = ['$injector', '$rootScope', '$q', '$window'];
    constructor($injector:ng.auto.IInjectorService, public $rootScope, public $q, public $window){
        this.$log = $injector.get('$log');
        this.$injector = $injector;
    }
  }
}

to register

 var app =angular.module('foo',[]);
 app.config(['$httpProvider', (_$httpProvider:ng.IHttpProvider)=>{
    _$httpProvider.interceptors.push('ErrorHttpInterceptor');

}]);

3 Comments

How do you register such interceptors? What parameters do you pass to $httpProvider.interceptors.push(...);?
How would this work? I have the impression that when we pass a string in interceptors, angular requires that a service be registered with that name using module.factory(...).
Hi, I noticed that none of the solutions provided include any types. Is this best practice? Or is there some type that the functions should return? I had my response returning ng.IHttpPromiseCallbackArg<any>, which worked if I just wanted to return the response, but type clashed when I tried to return a rejection. Removing the types fixes it ... but it really seems like we should be using some kind of type.
4

You need to do: public response = (response) => {}

public responseError = (rejection) => { }

Because in other way your 'this' will be undefined. To understand why you need this : https://www.youtube.com/watch?v=tvocUcbCupA&hd=1

Comments

4

The config settings are as follows

    .config(['$httpProvider', function ($httpProvider: ng.IHttpProvider) {
        $httpProvider.interceptors.push(AuthenticationInterceptor.Factory);
    }])

and your actual class should look as follows

module Common {
'use strict';

export class AuthenticationInterceptor {

    private static _instance: AuthenticationInterceptor;

    public static Factory($q: ng.IQService) {
        AuthenticationInterceptor._instance = new AuthenticationInterceptor($q);

        return AuthenticationInterceptor._instance;
    }

    constructor(private $q: ng.IQService) {
    }

    //Method name should be exactly "response" - http://docs.angularjs.org/api/ng/service/$http
    public response(response) {
        var self = Common.AuthenticationInterceptor._instance;

        console.log(response);
        return response || self.$q.when(response);
    }

    public responseError(rejection) {
        var self = Common.AuthenticationInterceptor._instance;

        console.log(rejection.status);
        if (rejection.status === 401) {
        }

        // Otherwise, default behavior
        return self.$q.reject(rejection);
    }
}

It is necessary to get the instance of the class with the full namespace because when receiving a callback from Angular 'this' is undefined.

1 Comment

Thanks for this answer. I was also having the problem that 'this' was always undefined. Why is this happening?
2

Register it by name : $httpProvider.interceptors.push('myInterceptorClass');

And then make sure you class is also registerd as a service :

yourApp.service('myInterceptorClass',MyInterceptorClass)

1 Comment

That doesn't help my question on how to implement the last anonymous method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.