init
This commit is contained in:
@@ -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 */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user