This commit is contained in:
Jason Kulatunga
2020-08-19 16:04:21 -07:00
commit 8482272d45
336 changed files with 197309 additions and 0 deletions
@@ -0,0 +1 @@
export * from '@treo/lib/mock-api/mock-api.module';
@@ -0,0 +1,92 @@
import { Injectable } from '@angular/core';
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, switchMap } from 'rxjs/operators';
import { TreoMockApiRequestHandler } from '@treo/lib/mock-api/mock-api.request-handler';
import { TreoMockApiService } from '@treo/lib/mock-api/mock-api.service';
@Injectable({
providedIn: 'root'
})
export class TreoMockApiInterceptor implements HttpInterceptor
{
/**
* Constructor
*
* @param {TreoMockApiService} _treoMockApiService
*/
constructor(
private _treoMockApiService: TreoMockApiService
)
{
}
/**
* Intercept
*
* @param request
* @param next
*/
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
{
// Try to get the request handler
const requestHandler: TreoMockApiRequestHandler = this._treoMockApiService.requestHandlers[request.method.toLowerCase()].get(request.url);
// If the request handler exists..
if ( requestHandler )
{
// Set the intercepted request on the requestHandler
requestHandler.interceptedRequest = request;
// Subscribe to the reply function observable
return requestHandler.replyCallback.pipe(
delay(requestHandler.delay),
switchMap((response) => {
// Throw a not found response, if there is no response data
if ( !response )
{
response = new HttpErrorResponse({
error : 'NOT FOUND',
status : 404,
statusText: 'NOT FOUND'
});
return throwError(response);
}
// Parse the response data
const data = {
status: response[0],
body : response[1]
};
// If the status is in between 200 and 300,
// it's a success response
if ( data.status >= 200 && data.status < 300 )
{
response = new HttpResponse({
body : data.body,
status : data.status,
statusText: 'OK'
});
return of(response);
}
// Error response
response = new HttpErrorResponse({
error : data.body.error,
status : data.status,
statusText: 'ERROR'
});
return throwError(response);
}));
}
// Pass through if the request handler does not exists
return next.handle(request);
}
}
@@ -0,0 +1,4 @@
export interface TreoMockApi
{
register(): void;
}
@@ -0,0 +1,37 @@
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { TreoMockApiInterceptor } from '@treo/lib/mock-api/mock-api.interceptor';
import { TreoMockApiService } from '@treo/lib/mock-api/mock-api.service';
@NgModule({
providers: [
TreoMockApiService,
{
provide : HTTP_INTERCEPTORS,
useClass: TreoMockApiInterceptor,
multi : true
}
]
})
export class TreoMockApiModule
{
/**
* forRoot method for setting user configuration
*
* @param mockDataServices
*/
static forRoot(mockDataServices: any[]): ModuleWithProviders
{
return {
ngModule : TreoMockApiModule,
providers: [
{
provide : APP_INITIALIZER,
deps : mockDataServices,
useFactory: () => () => null,
multi : true
},
]
};
}
}
@@ -0,0 +1,160 @@
import { Injectable } from '@angular/core';
import { HttpRequest } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { take } from 'rxjs/operators';
@Injectable()
export class TreoMockApiRequestHandler
{
// Private
private _delay: number;
private _executionCount: number;
private _executionLimit: number;
private _interceptedRequest: HttpRequest<any>;
private _replyCallback: any;
private _url: string;
/**
* Constructor
*/
constructor()
{
// Set the private defaults
this._executionCount = 0;
this._executionLimit = 0;
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Setter and getter for delay
*
* @param value
*/
set delay(value: number)
{
// Return, if the value is the same
if ( this._delay === value )
{
return;
}
// Store the delay
this._delay = value;
}
get delay(): number
{
return this._delay;
}
/**
* Setter and getter for url
*
* @param value
*/
set url(value: string)
{
// Return, if the value is the same
if ( this._url === value )
{
return;
}
// Store the url
this._url = value;
}
get url(): string
{
return this._url;
}
/**
* Setter and getter for intercepted request
*
* @param value
*/
set interceptedRequest(value: HttpRequest<any>)
{
// Return, if the value is the same
if ( this._interceptedRequest === value )
{
return;
}
// Store the intercepted request
this._interceptedRequest = value;
}
get interceptedRequest(): HttpRequest<any>
{
return this._interceptedRequest;
}
/**
* Getter for reply callback
*/
get replyCallback(): Observable<any>
{
// Throw an error, if the execution limit has been reached
if ( this._executionLimit > 0 && this._executionCount === this._executionLimit )
{
return throwError('Execution limit reached');
}
// Throw an error, if the intercepted request has not been set
if ( !this.interceptedRequest )
{
return throwError('Intercepted request does not exist!');
}
// Increase the execution count
this._executionCount++;
// Execute the reply callback
const replyCallbackResult = this._replyCallback(this.interceptedRequest);
// If the result of the reply function is an observable...
if ( replyCallbackResult instanceof Observable )
{
// Return the result as it is
return replyCallbackResult.pipe(take(1));
}
// Otherwise, return the result as an observable
return of(replyCallbackResult).pipe(take(1));
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Reply
*
* @param callback
*/
reply(callback: (req: HttpRequest<any>) => ([number, any | string] | Observable<any>)): void
{
// Store the reply callback
this._replyCallback = callback;
}
/**
* Reply once
*
* @param callback
*/
replyOnce(callback: (req: HttpRequest<any>) => ([number, any | string] | Observable<any>)): void
{
// Set the execute limit to 1
this._executionLimit = 1;
// Call reply as normal
this.reply(callback);
}
}
@@ -0,0 +1,114 @@
import { Injectable } from '@angular/core';
import { TreoMockApiRequestHandler } from '@treo/lib/mock-api/mock-api.request-handler';
@Injectable({
providedIn: 'root'
})
export class TreoMockApiService
{
requestHandlers: any;
/**
* Constructor
*/
constructor()
{
// Set the defaults
this.requestHandlers = {
delete: new Map<string, TreoMockApiRequestHandler>(),
get : new Map<string, TreoMockApiRequestHandler>(),
patch : new Map<string, TreoMockApiRequestHandler>(),
post : new Map<string, TreoMockApiRequestHandler>(),
put : new Map<string, TreoMockApiRequestHandler>()
};
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Register 'delete' request handler
*
* @param url
* @param delay
*/
onDelete(url: string, delay: number = 0): TreoMockApiRequestHandler
{
return this._registerRequestHandler('delete', url, delay);
}
/**
* Register 'get' request handler
*
* @param url
* @param delay
*/
onGet(url: string, delay: number = 0): TreoMockApiRequestHandler
{
return this._registerRequestHandler('get', url, delay);
}
/**
* Register 'patch' request handler
*
* @param url
* @param delay
*/
onPatch(url: string, delay: number = 0): TreoMockApiRequestHandler
{
return this._registerRequestHandler('patch', url, delay);
}
/**
* Register 'post' request handler
*
* @param url
* @param delay
*/
onPost(url: string, delay: number = 0): TreoMockApiRequestHandler
{
return this._registerRequestHandler('post', url, delay);
}
/**
* Register 'put' request handler
*
* @param url
* @param delay
*/
onPut(url: string, delay: number = 0): TreoMockApiRequestHandler
{
return this._registerRequestHandler('put', url, delay);
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Register a request handler
*
* @param requestType
* @param url
* @param delay
* @private
*/
private _registerRequestHandler(requestType, url, delay): TreoMockApiRequestHandler
{
// Create a new instance of TreoMockApiRequestHandler
const treoMockHttp = new TreoMockApiRequestHandler();
// Store the url
treoMockHttp.url = url;
// Store the delay
treoMockHttp.delay = delay;
// Store the request handler to access them from the interceptor
this.requestHandlers[requestType].set(url, treoMockHttp);
// Return the instance
return treoMockHttp;
}
}
@@ -0,0 +1,38 @@
export class TreoMockApiUtils
{
/**
* Constructor
*/
constructor()
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Generate a globally unique id
*/
static guid(): string
{
/* tslint:disable */
let d = new Date().getTime();
// Use high-precision timer if available
if ( typeof performance !== 'undefined' && typeof performance.now === 'function' )
{
d += performance.now();
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
/* tslint:enable */
}
}