Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save billgeek/aaa4e2cb9e72fefdd23dc30fb82812c9 to your computer and use it in GitHub Desktop.
Save billgeek/aaa4e2cb9e72fefdd23dc30fb82812c9 to your computer and use it in GitHub Desktop.
Angular 5 HTTP Interceptor and Loader

Overview

The below sample will demonstrate how to implement an HTTP interceptor in Angular 5 as well as append authorization tokens where neccessary. (This was built in Angular 4 originally and was not modified when upgrading, so it should still work with Angular 4)

To make a call including an auth token, simply pass "true" as the last argument.

Note that the "app-loader-indicator" needs to be the last element on the app component markup to ensure it's always visible and always "on top". The loader service and loader indicator component can be enhanced to make use of Observables, though for my project it was not required.

Lastly the loader indicator is simply the font awesome "fa-spin" class as per the example on the Font Awesome homepage.

<router-outlet></router-outlet>
<app-loader-indicator></app-loader-indicator>
import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions, RequestOptionsArgs } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/Rx';
import { LoaderService } from './loader.service';
import { environment } from '@env/environment';
@Injectable()
export class GlobalInterceptorService {
constructor(private http: Http, private loader: LoaderService) { }
showLoader() {
this.loader.show();
}
hideLoader() {
this.loader.hide();
}
getFullUrl(url: string): string {
var apiUrl = environment.apiUrl;
if (!apiUrl.endsWith('/')) {
apiUrl += '/';
}
if (url === 'token') {
return apiUrl + url;
}
return apiUrl + 'api/' + url;
}
private getRequestOptions(includeUserToken: boolean = false) {
var requestOptions: RequestOptions = new RequestOptions();
var authData = this.getAuthenticationData();
if (includeUserToken && authData.isAuthenticated) {
requestOptions.headers = new Headers();
requestOptions.headers.append('Authorization', `Bearer ${authData.userToken}`);
}
return requestOptions;
}
get(url: string, includeToken: boolean = false) {
this.showLoader();
return this.http.get(this.getFullUrl(url), this.getRequestOptions(includeToken)).finally(() => {
this.hideLoader();
});
}
postWithOptions(url: string, body: string, options: RequestOptionsArgs) {
this.showLoader();
return this.http.post(this.getFullUrl(url), body, options).finally(() => {
this.hideLoader();
});
}
post(url: string, body: any, includeToken: boolean = false) {
this.showLoader();
return this.http.post(this.getFullUrl(url), body, this.getRequestOptions(includeToken)).finally(() => {
this.hideLoader();
});
}
put(url: string, body: any, includeToken: boolean = false) {
this.showLoader();
return this.http.put(this.getFullUrl(url), body, this.getRequestOptions(includeToken)).finally(() => {
this.hideLoader();
});
}
delete(url: string, includeToken: boolean = false) {
this.showLoader();
return this.http.delete(this.getFullUrl(url), this.getRequestOptions(includeToken)).finally(() => {
this.hideLoader();
});
}
// Patch should not be called directly but is left here for brevity
patch(url: string, body: any) {
this.showLoader();
return this.http.patch(this.getFullUrl(url), body).finally(() => {
this.hideLoader();
});
}
private getAuthenticationData(): any {
var authString = localStorage.getItem('authData');
if (authString) {
return JSON.parse(authString);
}
else {
return {
isAuthenticated: false
}
}
}
}
.loader-background {
height:100%;
overflow:hidden;
}
.loader-container {
width: 100%;
text-align: center;
position: relative;
top: 50%;
transform: translateY(-50%);
}
<div class="loader-background" *ngIf="loaderService.loaderShown">
<div class="loader-container">
<i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i>
<span class="sr-only">Loading...</span>
</div>
</div>
import { Component, OnInit } from '@angular/core';
import { LoaderService } from '@app/api';
@Component({
selector: 'app-loader-indicator',
templateUrl: './loader-indicator.component.html',
styleUrls: ['./loader-indicator.component.css']
})
export class LoaderIndicatorComponent implements OnInit {
constructor(private loaderService: LoaderService) { }
ngOnInit() {
}
}
import { Injectable } from '@angular/core';
@Injectable()
export class LoaderService {
public loaderShown: boolean = false;
constructor() { }
show() {
this.loaderShown = true;
}
hide() {
this.loaderShown = false;
}
}
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Response } from '@angular/http'; // IMPORTANT! We want to use the Angular Response, not "standard" DOM response!
import { User } from '@app/core';
import { GlobalInterceptorService } from './../global-interceptor.service';
@Injectable()
export class UserService {
// Instead of injecting "Http", we inject our new GlobalInterceptorService
constructor(private http: GlobalInterceptorService) { }
getUserDetail(userId: number): Observable<User> {
return this.http.get(`user/${userId}`, true)
.map(response => response.json())
.catch(this._serverError);
}
private _serverError(err: any) {
if(err instanceof Response) {
return Observable.throw(err.json()["Message"] || 'Technical Issues');
}
return Observable.throw(err || 'Technical Issues');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment