import { Observable, of as observableOf, combineLatest as observableCombineLatest } from 'rxjs'; import { distinctUntilChanged, map, mergeMap, startWith, switchMap, tap } from 'rxjs/operators'; import { RequestService } from '../data/request.service'; import { GlobalConfig } from '../../../config/global-config.interface'; import { EndpointMapRequest } from '../data/request.models'; import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; import { RESTURLCombiner } from '../url-combiner/rest-url-combiner'; import { Inject, Injectable } from '@angular/core'; import { GLOBAL_CONFIG } from '../../../config'; import { EndpointMap, EndpointMapSuccessResponse } from '../cache/response.models'; import { getResponseFromEntry } from './operators'; import { URLCombiner } from '../url-combiner/url-combiner'; @Injectable() export class HALEndpointService { constructor(private requestService: RequestService, @Inject(GLOBAL_CONFIG) private EnvConfig: GlobalConfig) { } protected getRootHref(): string { return new RESTURLCombiner(this.EnvConfig, '/').toString(); } protected getRootEndpointMap(): Observable { return this.getEndpointMapAt(this.getRootHref()); } private getEndpointMapAt(href): Observable { const request = new EndpointMapRequest(this.requestService.generateRequestId(), href); this.requestService.configure(request); return this.requestService.getByHref(request.href).pipe( getResponseFromEntry(), map((response: EndpointMapSuccessResponse) => response.endpointMap), distinctUntilChanged()); } public getEndpoint(linkPath: string): Observable { return this.getEndpointAt(this.getRootHref(), ...linkPath.split('/')); } private getEndpointAt(href: string, ...halNames: string[]): Observable { if (isEmpty(halNames)) { throw new Error('cant\'t fetch the URL without the HAL link names') } const nextHref$ = this.getEndpointMapAt(href).pipe( map((endpointMap: EndpointMap): string => { /*TODO remove if/else block once the rest response contains _links for facets*/ const nextName = halNames[0]; if (hasValue(endpointMap) && hasValue(endpointMap[nextName])) { return endpointMap[nextName]; } else { return new URLCombiner(href, nextName).toString(); } }) ) as Observable; if (halNames.length === 1) { return nextHref$; } else { return nextHref$.pipe( switchMap((nextHref) => this.getEndpointAt(nextHref, ...halNames.slice(1))) ); } } public isEnabledOnRestApi(linkPath: string): Observable { return this.getRootEndpointMap().pipe( // TODO this only works when there's no / in linkPath map((endpointMap: EndpointMap) => isNotEmpty(endpointMap[linkPath])), startWith(undefined), distinctUntilChanged() ) } }