ngrx-model
Version:
Model classes for integrating ngrx store with a REST API
178 lines (157 loc) • 6.31 kB
text/typescript
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpUtility } from '../http/http.service';
import { IConverter, ConverterService } from './converters.service';
export interface IRequestOptions<TDataType> {
endpoint: string;
useMock?: boolean;
logRequests?: boolean;
transform?: IConverter<TDataType> | { [index: string]: IConverter<any> }
}
export interface IGetListOptions<TDataType> extends IRequestOptions<TDataType> {
params: any;
getMockData?: { (): TDataType[] };
}
export interface IGetItemOptions<TDataType> extends IRequestOptions<TDataType> {
getMockData?: { (): TDataType };
}
export interface ICreateOptions<TDataType> extends IRequestOptions<TDataType> {
domainObject: TDataType;
addMockData?: { (data: TDataType): void };
}
export interface IUpdateOptions<TDataType> extends IRequestOptions<TDataType> {
domainObject: TDataType;
updateMockData?: { (data: TDataType): void };
}
export interface IDeleteOptions<TDataType> extends IRequestOptions<TDataType> {
domainObject: TDataType;
removeMockData?: { (data: TDataType): void };
}
export interface ISearchResult<TDataType> {
dataSet: TDataType[];
}
export interface IRequestService {
getList<TDataType>(options: IGetListOptions<TDataType>): Observable<TDataType[]>;
search<TDataType, TResultType>(options: IGetListOptions<TDataType>): Observable<TResultType>;
getItem<TDataType>(options: IGetItemOptions<TDataType>): Observable<TDataType>;
create<TDataType>(options: ICreateOptions<TDataType>): Observable<TDataType>;
update<TDataType>(options: IUpdateOptions<TDataType>): Observable<TDataType>;
delete<TDataType>(options: IDeleteOptions<TDataType>): Observable<void>;
}
export class RequestService implements IRequestService {
private http: HttpUtility;
private converterService: ConverterService;
constructor(http: HttpUtility, converterService: ConverterService) {
this.http = http;
this.converterService = converterService;
}
getList<TDataType>(options: IGetListOptions<TDataType>): Observable<TDataType[]> {
let request: Observable<TDataType[]>;
if (options.useMock) {
request = Observable.of(options.getMockData());
} else {
request = this.http.get<TDataType[]>(options.endpoint, options.params);
}
return request.map((data: TDataType[]): TDataType[] => {
data = this.converterService.applyTransform(data, options.transform, false);
if (options.logRequests) {
this.log('getList', options.params, data, options.endpoint, options.useMock);
}
return data;
});
}
search<TDataType, TResultType extends ISearchResult<TDataType>>(options: IGetListOptions<TDataType>): Observable<TResultType> {
let request: Observable<TResultType>;
if (options.useMock) {
request = Observable.of<TResultType>(<any>{
dataSet: options.getMockData(),
});
} else {
request = this.http.post<TResultType>(options.endpoint, options.params);
}
return request.map((result: TResultType): TResultType => {
result.dataSet = this.converterService.applyTransform(result.dataSet, options.transform, false);
if (options.logRequests) {
this.log('search', options.params, result, options.endpoint, options.useMock);
}
return result;
})
}
getItem<TDataType>(options: IGetItemOptions<TDataType>): Observable<TDataType> {
let promise: Observable<TDataType>;
if (options.useMock) {
promise = Observable.of(options.getMockData());
} else {
promise = this.http.get<TDataType>(options.endpoint);
}
return promise.map((data: TDataType): TDataType => {
data = this.converterService.applyTransform(data, options.transform, false);
if (options.logRequests) {
this.log('get', null, data, options.endpoint, options.useMock);
}
return data;
});
}
create<TDataType>(options: ICreateOptions<TDataType>): Observable<TDataType> {
let promise: Observable<TDataType>;
options.domainObject = this.converterService.applyTransform(options.domainObject, options.transform, true);
if (options.useMock) {
options.addMockData(options.domainObject);
promise = Observable.of(options.domainObject);
} else {
promise = this.http.post<TDataType>(options.endpoint, options.domainObject);
}
return promise.map((data: TDataType): TDataType => {
data = this.converterService.applyTransform(data, options.transform, false);
if (options.logRequests) {
this.log('create', options.domainObject, data, options.endpoint, options.useMock);
}
return data;
});
}
update<TDataType>(options: IUpdateOptions<TDataType>): Observable<TDataType> {
let promise: Observable<TDataType>;
options.domainObject = this.converterService.applyTransform(options.domainObject, options.transform, true);
if (options.useMock) {
options.updateMockData(options.domainObject)
promise = Observable.of(options.domainObject);
} else {
promise = this.http.put<TDataType>(options.endpoint, options.domainObject);
}
return promise.map((data: TDataType): TDataType => {
data = this.converterService.applyTransform(data, options.transform, false);
if (options.logRequests) {
this.log('update', options.domainObject, data, options.endpoint, options.useMock);
}
return data;
});
}
delete<TDataType>(options: IDeleteOptions<TDataType>): Observable<void> {
let promise: Observable<void>;
if (options.useMock) {
options.removeMockData(options.domainObject);
promise = Observable.empty<void>();
} else {
promise = this.http.delete(options.endpoint);
}
return promise.map((): void => {
if (options.logRequests) {
this.log('delete', options.domainObject, null, options.endpoint, options.useMock);
}
});
}
private log(requestName: string, params: any, data: any, endpoint: string, useMock: boolean): void {
let mockString = useMock ? 'Mocked ' : '';
let endpointString = endpoint == null ? 'unspecified' : endpoint;
console.log(mockString + requestName + ' for endpoint ' + endpointString + ':');
if (params != null) {
console.log('params:');
console.log(params);
}
if (data != null) {
console.log('data:');
console.log(data);
}
}
}