Skip to content

Instantly share code, notes, and snippets.

@melvinodsa
Last active November 6, 2018 07:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save melvinodsa/20aa11caa814fa7721c0d28c5ca6d2e7 to your computer and use it in GitHub Desktop.
Save melvinodsa/20aa11caa814fa7721c0d28c5ca6d2e7 to your computer and use it in GitHub Desktop.
import { Injectable } from '@angular/core';
/**
* ConfigService has the configuration utilities required for the application
*/
@Injectable({
providedIn: 'root'
})
export class ConfigService {
/**
* api has the url and param configurations required for hitting an api
*/
static api: Map<string, APIRequest> = new Map<string, APIRequest>([
['SESSION', {
url: '/api/App/Session',
params: new Map<string, Param>([])
}],
['AUTHURLS', {
url: '/api/App/AuthUrls',
params: new Map<string, Param>([])
}]
]);
}
//APIRequest is the request to be send for hitting the api
export interface APIRequest {
//url is the url of the api
url: string;
//params is the map of the param mapped to a string key.
//advantage of this model is that, even if the name of the api param changes
//the code business logic in the code need not be changed.
//Just the configuration change would be sufficient.
params: Map<string, Param>;
}
/**
* Param is the parameter to be sent with a api request
*/
export interface Param {
//name is the name of the parameter
name: string;
//value is the value of the parameter
value?: string;
}
import { Injectable } from '@angular/core';
import { Observable, throwError, of } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map, catchError } from 'rxjs/operators';
import { ConfigService, Param, APIRequest } from './config.service';
import { SessionService } from './session.service';
@Injectable({
providedIn: 'root'
})
export class HttpService {
/**
* constructor initializes the http service. It will fetch the session information
* when the application boots up.
* @param http http client of the angular application
* @param session session service of the application
*/
constructor(private http: HttpClient, private session: SessionService) {
/*
* We will check whether the session exists.
* If session exists we will store the session's access token in the application variable
* Else we will set the session service's access token as empty
*/
this.get({
hash: 'SESSION'
}).subscribe(resp => {
session.setAuthToken(resp.AccessToken);
}, error => {
console.log(error);
session.setAuthToken('');
})
}
/**
* get is GET request for hitting resources/api
*
* @param {Request} req the request configuration required for hitting the api/resource
*/
get(req: Request): Observable<any> {
/*
* We will find whether api do exist for the given hash of the request argument
* We will set the parameters of the request
* We will set the header for auth if available
* We will set the loader if avalilable to loading state
* Then we will return the get request of http client piped with a transformation function.
*/
//checking whether the api exists with the hash of the request
let api = ConfigService.api.get(req.hash);
if(!api) {
return throwError('Could not find the api hash');
}
//variables for storing the request options
let params = this.getParams(req, api);
let options = { headers: new HttpHeaders()};
//joining the params
options['params'] = params.map(p => p.name+'='+p.value).join('&');
//setting the headers
options.headers.set('Content-Type', 'application/x-www-form-urlencoded');
//if session availanble will set the same
if(this.session.getAuthToken().length > 0) {
options.headers.set(SessionService.AuthHeader, this.session.getAuthToken());
}
//setting the loader of the request
if(req.loader) {
req.loader.l[req.loader.p] = false;
}
return this.http.get(api.url, options).pipe(
catchError(handleError({})),
map(postApi.bind(req))
);
}
/**
*
* @param {Request} req request from which the parameter values has to be taken.
* @param {APIRequest} api apirequest which ahs the parameter names of the api and the url
*/
getParams(req: Request, api: APIRequest) :Param[] {
/*
* We will proceed only if there exist params
* We will iterate through the params and add its value based on the parameter name.
*/
let params: Param[] = [];
//setting the parameters
if(!req.params) {
return params;
}
//we will iterate through the params given by the request and will find the corresponding params in the api
let it = req.params.entries();
let param = it.next();
while(param) {
//we have a valid parameter key. we will try to get it from the api parameters map
let paramKey = param.value[0];
let apiPK = api.params.get(paramKey);
if(!apiPK) {
//If couldn't find the api key in the api params, skip it
continue;
}
//we also have api param key . now add it to the params
params.push({name: apiPK.name, value: param.value[1]});
param = it.next();
}
return params;
}
}
/**
* Request is the interface to be implemented by an object
* to be a request for the HttpService
*/
export interface Request {
//hash is the hash with which the request is declared in the config service
hash: string;
//params are the parameters to be passed on with the web request
params?: Map<string, string>;
//loader to be used while making the api request
loader?: Loader;
}
/**
* Loader has to be implemented by any object that represent a loader.
* The p property of the l object will be set true by the http service.
*/
export interface Loader {
l: any; //l is the loader object
p: string; //p is the property of the loader to be set true after loading
}
/**
* postApi intercepts the response from the get/post request.
* It will do the session check and will disable the loader
* @param res respones after the apio hit
*/
function postApi(res: any): any {
/*
* Will disable the loader
* Will check whether the session is disabled or not. If so will inform the session service about the same.
*/
if(this.loader){
this.loader.l[this.loader.p] = true;
}
if(res.SessionExpired) {
this.session.setAuthToken('');
}
return res;
}
/**
* handleError handles any error happening in the api hit
* @param result result is the result from the api
*/
function handleError<T> (result?: T) {
return (error: any): Observable<T> => {
console.error(error); // log to console instead
// Let the app keep running by returning an empty result.
return of(result as T);
};
}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { PagesComponent } from './pages.component';
import { HomeComponent } from './home/home.component';
/**
* Routes has all the routes to the pages component.
*/
const routes: Routes = [
{ path: '', component: PagesComponent,
children: [
{ path: 'home', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: '', redirectTo: 'home', pathMatch: 'full' },
]
}
];
/**
* This module implements the routing of the pages module.
*/
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class PagesRoutingModule {}
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { HttpService, SessionService } from '../core/services';
import { DarkTheme } from '../theme/theme';
/**
* PagesComponent bootstraps the pages in the application.
* The session check is done at this level.
*/
@Component({
selector: 'brain-pages',
templateUrl: './pages.component.html',
styleUrls: ['./pages.component.scss']
})
export class PagesComponent implements OnInit, OnDestroy{
/**
* sessIns is the session instance of the application.
* This is subscribed to the session changes of the session service
* If when session become false, it will load the login page
*/
sessIns: Subscription;
/**
* sessionEnabled flag indicate whether the session is enabled or not.
*/
sessionEnabled: boolean;
/**
* themes is the object with keys as the page names mapped to the theme to applied to the page.
*/
themes= {
HEADER: new DarkTheme()
}
/**
* constructor of the pages component. It do require the following services to be inited before this component.
* @param http http service of the application
* @param session session service of the application
* @param router router of the angular
*/
constructor(private http: HttpService, private session: SessionService, private router: Router) {}
/**
* We will check whether the session is enabled or not. if not enabled will logout.
* We will basically subscribe to the session service for the same. So that any changes can dynamically can addressed.
*/
ngOnInit() {
this.sessIns = this.session.session().subscribe(isEnabled => {
this.sessionEnabled = isEnabled;
if(!this.sessionEnabled) {
this.router.navigate(['pages', 'login']);
}
})
}
/**
* We will unsubscribe to the session service
*/
ngOnDestroy() {
this.sessIns.unsubscribe();
}
}
import { Injectable, EventEmitter } from '@angular/core';
import { Observable } from 'rxjs';
/**
* SessionService provides the utilities for proving the session accross the application
*/
@Injectable({
providedIn: 'root'
})
export class SessionService {
/**
* AuthHeader is the header to be used for setting the auth token while hitting the api
*/
static AuthHeader = 'auth-header';
/**
* sessionSet is flag indicating whether the session for the application is set or not
*/
private sessionSet = false;
/**
* sessionEmit emits the session information to the subscribers
*/
private sessionEmit: EventEmitter<boolean> = new EventEmitter<boolean>();
/**
* authToken is the authentication token to be used for accessing the api
*/
private authToken: string = '';
/**
* getAuthToken returns the authentication token available in the application
*/
getAuthToken(): string {
return this.authToken;
}
/**
* setAuthToken sets the new auth token to the session
*
* @param {string} token is the auth token to be set
*/
setAuthToken(token: string) {
/*
* We will set the session set flag as true
* Then we will set the auth token
* And then emits the session emit to let the subscribers know that session has been changed
*/
this.sessionSet = true;
this.authToken = token;
this.sessionEmit.emit((this.authToken && this.authToken.length > 0?true: false))
}
/**
* session returns an observable stating whether the session exists or not.
* This function will wait for the first time to get the session set and let
* it's subscriber known whenever the session information changes.
*/
session() : Observable<boolean> {
/*
* If the session is already not set we will create an observable that emits the session when
* the sessionEmit event emitter emits the session information change
* If the session is already set we will create an observable that emits the session when
* the sessionemit event emitter emits the session information change. Also will emit the current session information.
*/
//when the session is not set simply create the observable that is subscribed to the session event emiter
if(!this.sessionSet) {
let ob = Observable.create((observer) => {
this.sessionEmit.subscribe((sess: boolean) => {
observer.next(sess);
});
});
return ob;
}
//if the session is already set create the observale that by default emits the session information along with the subscription to the vent emiter;
let ob = Observable.create((observer) => {
observer.next((this.authToken && this.authToken.length > 0?true: false));
this.sessionEmit.subscribe((sess: boolean) => {
observer.next(sess);
});
});
return ob;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment