first-npm-package-nicule
Version:
This isi first npm package
102 lines (85 loc) • 4 kB
text/typescript
import { Observable } from 'rxjs';
import { ProgressTracker } from './progress-tracker';
import { Hypermedia, HypermediaAction, HypermediaField } from '../interfaces';
import { SessionService } from '@core/services';
import { Injectable, Type } from '@angular/core';
import { HeaderProvider } from './header-provider';
// import { ReflectiveModelBinderFactory } from 'hypermedia/models/services/reflective-model-binder';
// import { ReflectiveQueryMatcherFactory } from 'hypermedia/models/services/reflective-query-matcher';
import { filter, map, catchError } from 'rxjs/operators';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { ReflectiveModelBinderFactory } from '../../models/services/reflective-model-binder';
import { ReflectiveQueryMatcherFactory } from '../../models/services/reflective-query-matcher';
()
export class ActionExecutor {
private readonly fakeResponse = {
500: {
class: ['error'],
properties: {
msg: 'error.message.internalServerError'
}
}
};
constructor(private http: HttpClient,
private modelBinderFactory: ReflectiveModelBinderFactory,
private progressTracker: ProgressTracker,
private headerProvider: HeaderProvider,
private queryMatcherFactory: ReflectiveQueryMatcherFactory,
private sessionService: SessionService) { }
execute(action: HypermediaAction, fieldValues?: any, authorize: boolean = true, tokenOverride?: string): Observable<Hypermedia> {
const fields = this.computeActionFields(action.fields, fieldValues);
return this.http.request(action.method, action.href, {
body: {
name: action.name,
fields
},
headers: this.headerProvider.getHeaders(authorize, tokenOverride),
reportProgress: true
}).pipe(
map(response => this.computeHypermediaResponse(response)),
catchError(error => this.handleActionErrors(error))
);
}
executeAs<T>(action: HypermediaAction, type: Type<T>, fieldValues?: any, authorize: boolean = true): Observable<T> {
const modelBinder = this.modelBinderFactory.make(type);
const queryMatcher = this.queryMatcherFactory.make(type);
return this.execute(action, fieldValues, authorize)
.pipe(
filter(response => queryMatcher.matches(response)),
map(response => modelBinder.bind(response))
)
}
computeHypermediaResponse(response: Response | any): Hypermedia {
try {
return response as Hypermedia;
} catch (err) {
return { class: ['no-content'] } as Hypermedia;
}
}
computeActionFields(fields: Array<HypermediaField> = [], overrides: any = {}): any {
const fieldValues = fields.reduce((acc, { name, value }) => ({ ...acc, [name]: value }), {});
return { ...fieldValues, ...overrides };
}
private handleActionErrors(responseError: HttpErrorResponse): Array<Hypermedia> {
if (!(responseError instanceof HttpErrorResponse)) {
return [];
}
const { status } = responseError;
const responseData = responseError.error;
const { class: classes } = responseData;
if (status === 401) {
this.intercept401(classes);
}
if (classes instanceof Array) {
// if it's a valid hypermedia, emit on error
return [responseData];
}
return [this.fakeResponse[status]];
}
private intercept401(classes: Array<string>): void {
const requiredClasses = ['external', 'redirect', 'unauthorized'];
if (requiredClasses.every(requiredClass => classes.includes(requiredClass))) {
this.sessionService.renew();
}
}
}