UNPKG

resilient-http-client

Version:

This is an augmented [Angular HttpClient][angular-http-client] which overrides the get method to enrich resilience behaviour.

1 lines 14.5 kB
{"version":3,"file":"resilient-http-client.mjs","sources":["../../../projects/resilient-http-client/src/lib/util/rx/resilience.rx-operator.ts","../../../projects/resilient-http-client/src/lib/util/rx/resilience.rx-operator.config.ts","../../../projects/resilient-http-client/src/lib/service/resilient-http-client.service.ts","../../../projects/resilient-http-client/src/public-api.ts","../../../projects/resilient-http-client/src/resilient-http-client.ts"],"sourcesContent":["import { concatMap, delay, map, MonoTypeOperatorFunction, of, retry, Subject, take, tap } from 'rxjs';\nimport { IResilienceConfig, TTopicPropName } from '../../model/type/resilience.rx-operator.type';\n\nexport const getTopicSpecificBooleanOrDefault = (config: IResilienceConfig, propertyName: TTopicPropName): boolean => {\n const topicConfig = config.topicToConfigDict[config.topic];\n const isDefinedByTopicConfig = topicConfig && topicConfig[propertyName] !== undefined;\n\n return isDefinedByTopicConfig ? (topicConfig[propertyName] as boolean) : config[propertyName];\n};\n\nconst isRetryDisabled = (config: IResilienceConfig): boolean =>\n getTopicSpecificBooleanOrDefault(config, 'disableRetry');\n\nconst waitForUserDecision = (config: IResilienceConfig): boolean =>\n getTopicSpecificBooleanOrDefault(config, 'waitForUserDecision');\n\nexport const shouldLogResult = (config: IResilienceConfig): boolean =>\n getTopicSpecificBooleanOrDefault(config, 'logResult');\n\nexport const shouldTrace = (config: IResilienceConfig): boolean => getTopicSpecificBooleanOrDefault(config, 'trace');\n\nexport const applyResilience = <T>(config: IResilienceConfig, uuid: string): MonoTypeOperatorFunction<T> => {\n const userRetryOrCancelSubject = new Subject<boolean>();\n let retryCount = 0;\n\n return retry<T>({\n delay: (error) =>\n of(error).pipe(\n concatMap((err) => {\n if (isRetryDisabled(config) || !config.retryOnStatusCodeList.includes(err.status)) {\n const topicSpecificMessageOrEmpty = config.topicToConfigDict[config.topic]?.failMessage || '';\n\n config.onFail(config.topic, uuid, topicSpecificMessageOrEmpty);\n throw err;\n }\n retryCount = retryCount + 1;\n const retries = retryCount;\n\n if (retryCount <= config.retryIntervalInMillisList.length) {\n return of(err).pipe(\n tap(() =>\n config.onRequestRetry(\n config.topic,\n uuid,\n retries,\n config.retryIntervalInMillisList[retries - 1],\n err.status,\n ),\n ),\n delay(config.retryIntervalInMillisList[retryCount - 1]),\n );\n } else {\n retryCount = 0;\n\n if (waitForUserDecision(config)) {\n config.onWaitingForUserDecision(\n config.topic,\n uuid,\n retries,\n err.status,\n userRetryOrCancelSubject,\n );\n return userRetryOrCancelSubject.asObservable().pipe(\n take(1),\n map((shouldRetry) => {\n if (shouldRetry) {\n config.onRequestRetry(\n config.topic,\n uuid,\n retries,\n config.retryIntervalInMillisList[retries - 1],\n err.status,\n );\n return of(err);\n }\n const topicSpecificMessageOrEmpty =\n config.topicToConfigDict[config.topic]?.failMessage || '';\n\n config.onFail(config.topic, uuid, topicSpecificMessageOrEmpty);\n throw err;\n }),\n );\n } else {\n const topicSpecificMessageOrEmpty =\n config.topicToConfigDict[config.topic]?.failMessage || '';\n\n config.onFail(config.topic, uuid, topicSpecificMessageOrEmpty);\n throw err;\n }\n }\n }),\n ),\n });\n};\n","import { IResilienceConfig } from '../../model/type/resilience.rx-operator.type';\nimport { HttpStatusCode } from '@angular/common/http';\n\nexport const DEFAULT_RESILIENCE_CONFIG: Partial<IResilienceConfig> = {\n isDelayedAfterMs: 3000,\n disableRetry: false,\n logResult: false,\n trace: false,\n waitForUserDecision: false,\n retryOnStatusCodeList: [\n HttpStatusCode.RequestTimeout,\n HttpStatusCode.TooManyRequests,\n HttpStatusCode.InternalServerError,\n HttpStatusCode.BadGateway,\n HttpStatusCode.ServiceUnavailable,\n HttpStatusCode.GatewayTimeout,\n ],\n retryIntervalInMillisList: [0, 200, 500, 1000, 1000],\n topicToConfigDict: {},\n onWaitingForUserDecision: (): void => {},\n onFail: (): void => {},\n onRequestDelayed: (): void => {},\n onRequestRetry: (): void => {},\n onRequestStart: (): void => {},\n onRequestFinalize: (): void => {},\n};\n","import { HttpClient, HttpResponse } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { catchError, finalize, map, Observable, of, take, tap, throwError, timer } from 'rxjs';\nimport { applyResilience, shouldLogResult, shouldTrace } from '../util/rx/resilience.rx-operator';\nimport { v4 as uuidv4 } from 'uuid';\nimport { THttpGetOption } from '../model/type/http-get-options.type';\nimport { IResilienceConfig } from '../model/type/resilience.rx-operator.type';\nimport { DEFAULT_RESILIENCE_CONFIG } from '../util/rx/resilience.rx-operator.config';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ResilientHttpClientService {\n constructor(private readonly httpClient: HttpClient) {}\n\n public get<T>(url: string, resilienceConfig: Partial<IResilienceConfig>, options?: THttpGetOption): Observable<T> {\n const finalConfig = {\n ...DEFAULT_RESILIENCE_CONFIG,\n ...resilienceConfig,\n } as IResilienceConfig;\n const uuid = uuidv4();\n const isDelayedSubscription = timer(finalConfig.isDelayedAfterMs)\n .pipe(take(1))\n .subscribe(() => {\n finalConfig.onRequestDelayed(finalConfig.topic, uuid);\n });\n const timeStart = Date.now();\n\n finalConfig.onRequestStart(finalConfig.topic, uuid);\n\n return this.httpClient\n .get<T>(url, {\n ...options,\n observe: 'response',\n })\n .pipe(\n applyResilience(finalConfig, uuid),\n map((res: HttpResponse<T>) => res.body as T),\n tap((res) => {\n if (shouldLogResult(finalConfig)) {\n // eslint-disable-next-line no-console\n console.log(finalConfig.topic, res);\n }\n }),\n catchError((err) => {\n const topicRelatedConfig = finalConfig.topicToConfigDict[finalConfig.topic];\n\n if (topicRelatedConfig) {\n if (topicRelatedConfig.failoverResponse) {\n return of(topicRelatedConfig.failoverResponse as T);\n }\n }\n return throwError(() => err);\n }),\n finalize(() => {\n if (shouldTrace(finalConfig)) {\n const timeEnd = Date.now();\n // eslint-disable-next-line no-console\n console.log(\n `Fetch time in ms of call-topic ${finalConfig.topic}:`,\n finalConfig.topic,\n uuid,\n timeEnd - timeStart,\n );\n }\n finalConfig.onRequestFinalize(finalConfig.topic, uuid);\n isDelayedSubscription.unsubscribe();\n }),\n );\n }\n}\n","/*\n * Public API Surface of resilient-http-client\n */\n\nexport * from './lib/model/type/resilience.rx-operator.type';\nexport * from './lib/model/type/http-get-options.type';\nexport * from './lib/util/rx/resilience.rx-operator';\nexport * from './lib/util/rx/resilience.rx-operator.config';\nexport * from './lib/service/resilient-http-client.service';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["uuidv4"],"mappings":"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"}