Sunday, September 6, 2015

Thin Angular Controller

An example of caller of Authentication API:

App.Login.Controller.ts:
module App.Login {

    export class Controller {


        username:string;
        password:string;

        // Dependency-injected sweet alert, so it can be easily mocked
        constructor(public authApi:InhouseLib.AuthApi, public $http:ng.IHttpService, public $state:any,
                    public TheSweetAlert:SweetAlert.SweetAlertStatic,
                    public appWide:SharedState.AppWide) {
        }


        login():void {


            this.authApi.verify(this.username, this.password)
                .then(success => {
                    console.log(success.data.isValidUser);
                    this.appWide.isUploadVisible = true;
                    this.$http.defaults.headers["common"]["Authorization"] = success.data.theBasicAuthHeaderToUse;
                    this.$state.go('root.app.home');
                }, error => {
                    console.log(error.data.isValidUser);                    
                    this.appWide.isUploadVisible = false;
                    delete this.$http.defaults.headers["common"]["Authorization"];
                    this.TheSweetAlert("Oops...", "Not authorized", "error");                
                });

            }//login
            
        }//Controller
}


An example of Authentication API, AuthApi.ts:

///<reference path="../../typings/angularjs/angular.d.ts"/>
///<reference path="../../shared/dto/LoginDto.ts"/>
///<reference path="../../shared/dto/LoginResponseDto.ts"/>

module InhouseLib {

    export class AuthApi {

        constructor(public $http : ng.IHttpService) {

        }

        verify(username: string, password: string) : ng.IHttpPromise<Dto.LoginResponseDto> {

            var u = new Dto.LoginDto();
            u.username = username;
            u.password = password;


            return this.$http.post<Dto.LoginResponseDto>('/api/member/verify', u);

        }

    }

}


// Angular initialization code:
// mod.service('AuthApi', ['$http', InhouseLib.AuthApi]);



The problem with the caller(Login Controller) of the Authentication API is it does things that should not be of concern to it. One concern that should not be in the controller is the assigning and invalidating of Basic Authentication to angular's $http pipeline.


To improve that. The assigning and invalidating of Basic Authentication information to angular's $http pipeline should be done on AuthApi.ts. Following is an example. First, we must remove the code related to Basic Authentication away from the concerns of Login controller.

login():void {

    this.authApi.verify(this.username, this.password)
        .then(success => {
             console.log(success.isValidUser);
             this.appWide.isUploadVisible = true;
             this.$state.go('root.app.home');
        }, error => {
             console.log(error.isValidUser);                
             this.appWide.isUploadVisible = false;
             this.TheSweetAlert("Oops...", "Not authorized", "error");
        });


}


Then move that concern to AuthApi.ts:

verify(username: string, password: string) : ng.IPromise<Dto.LoginResponseDto> {

    var deferred = this.$q.defer();

    var u = new Dto.LoginDto();
    u.username = username;
    u.password = password;


    this.$http.post<Dto.LoginResponseDto>('/api/member/verify', u)
    .then(success => {

        this.$http.defaults.headers["common"]["Authorization"] = success.data.theBasicAuthHeaderToUse;

        // This goes to then's success callback parameter
        deferred.resolve(success.data);

    }, error => {

        delete this.$http.defaults.headers["common"]["Authorization"];

        // this goes to then's error callback parameter
        deferred.reject(error.data);

    });

    return deferred.promise;

}


If the caller code (Login Controller) has a need receive http status code returned by the server, return a promise of IHttpPromiseCallbackArg with an argument of the other information(Dto.LoginResponseDto) instead.

verify(username: string, password: string) :     
    ng.IPromise<ng.IHttpPromiseCallbackArg<Dto.LoginResponseDto>> 
{

    var deferred = this.$q.defer();

    var u = new Dto.LoginDto();
    u.username = username;
    u.password = password;


    this.$http.post<Dto.LoginResponseDto>('/api/member/verify', u)
        .then(success => {
            this.$http.defaults.headers["common"]["Authorization"] = success.data.theBasicAuthHeaderToUse;

            // This goes to then's success callback parameter
            deferred.resolve(success);

        }, error => {

            delete this.$http.defaults.headers["common"]["Authorization"];

            // this goes to then's error callback parameter
            deferred.reject(error);

        });

    return deferred.promise;

}


To access the other information(Dto.LoginResponseDto), access it via success.data and error.data. For the http status code, access it from success or error parameter, e.g., error.status.

login():void {


     this.authApi.verify(this.username, this.password)
         .then(success => {
             console.log(success.data.isValidUser);
             this.appWide.isUploadVisible = true;
             this.$state.go('root.app.home');
         }, error => {
             console.log(error.data.isValidUser);                
             this.appWide.isUploadVisible = false;
             this.TheSweetAlert(error.status.toString(), "Not authorized", "error");
         });

}

No comments:

Post a Comment