From 59f9a02171574679ff3b01ad4d1913aea5a827d9 Mon Sep 17 00:00:00 2001 From: vojvodicn23 Date: Tue, 17 Sep 2024 15:18:22 +0200 Subject: [PATCH] add request count and universal config --- README.md | 66 ++++++++++++------- projects/angular-http-handler/README.md | 66 ++++++++++++------- .../src/lib/http-handler.ts | 36 ++++++---- .../src/app/app.component.ts | 46 ++++++++++--- .../src/app/app.module.ts | 1 - 5 files changed, 146 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 947ebc5..7192892 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@ Supported Angular versions: 15, 16, 17, 18. - Handles errors with an optional error handler - Supports retry logic for failed requests - Provides a fallback value when the request fails -- Can return empty arrays or null based on the response type +- Provides a global loading indicator +- Provides a global request count ## Installation @@ -21,6 +22,7 @@ To install the library, run the following command: npm install angular-http-handler ``` + ## Usage In your Angular component, you can apply the handle function to any HTTP request. @@ -65,9 +67,7 @@ export class AppComponent implements OnInit { } ``` - -## API - +### API The `handle` function manages HTTP requests with loading state, error handling and retry. Parameters: @@ -93,12 +93,15 @@ Delay between retries in milliseconds. An Observable that handles the request, error, retry. -The `setDefaultErrorHandler` set default error handler for every handler request. In case custom error handler is passed as a parameter to handle function it will overwrite the default one. -Use it on root component on init method: +## Configuration (Optional) + +If you want to define custom default parameters you should do it in your root component before any http call. +- The `defaultErrorHandler` set default error handler for every request wrapped by handler. In case custom error handler is passed as a parameter to handle function it will overwrite the default one. +- The `defaultRetryCount` and `defaultRetryDelay` set default number of retry in case of error and time between the calls. ```typescript import { HttpErrorResponse } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; -import { setDefaultErrorHandler } from 'angular-http-handler'; +import { defaultErrorHandler } from 'angular-http-handler'; @Component({ selector: 'app-root', @@ -106,37 +109,52 @@ import { setDefaultErrorHandler } from 'angular-http-handler'; styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { + ngOnInit(): void { - setDefaultErrorHandler((error: HttpErrorResponse) => { - console.log('deafult handler', error); - customErrorHandlerFuction(error); + + configureHandler({ + defaultErrorHandler: (error: HttpErrorResponse) => { + console.log('deafult handler', error); + }, + defaultRetryCount: 0, + defaultRetryDelay: 0 }); } } ``` +### Fallback Response Behavior -The `defaultRetryCount` and `setDefaultRetryDelay` set default number of retry in case of error and time between the calls. If you pass it as a parameter it will overwrite the default value. -Use it on root component on init method: +The `handle` function returns a fallback response in case you define it as a 3rd parameter. In case you do not define it it will remain undefined and it will not trigger dataSetter function. + +## Aditional Options + +### `pendingRequestsCount()` +This function returns an Observable that emits the total number of pending requests. It helps track how many requests wrapped by handler are still in progress. ```typescript -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, OnInit } from '@angular/core'; -import { setDefaultRetryCount, setDefaultRetryDelay } from 'angular-http-handler'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { pendingRequestsCount } from 'angular-http-handler'; +import { Subscription } from 'rxjs'; + @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) -export class AppComponent implements OnInit { - ngOnInit(): void { - setDefaultRetryCount(2); - setDefaultRetryDelay(500); - } -} -``` +export class AppComponent implements OnInit, OnDestroy { + subs = new Subscription; -## Fallback Response Behavior + ngOnInit(): void { -The `handle` function returns a fallback response in case you define it as a 3rd parameter. In case you do not define it it will remain undefined and it will not trigger dataSetter function. \ No newline at end of file + this.subs = pendingRequestsCount().subscribe(count => { + console.log('Pending request count: ', count); + }); + } + + ngOnDestroy(): void { + this.subs.unsubscribe(); + } +} +``` \ No newline at end of file diff --git a/projects/angular-http-handler/README.md b/projects/angular-http-handler/README.md index 947ebc5..7192892 100644 --- a/projects/angular-http-handler/README.md +++ b/projects/angular-http-handler/README.md @@ -11,7 +11,8 @@ Supported Angular versions: 15, 16, 17, 18. - Handles errors with an optional error handler - Supports retry logic for failed requests - Provides a fallback value when the request fails -- Can return empty arrays or null based on the response type +- Provides a global loading indicator +- Provides a global request count ## Installation @@ -21,6 +22,7 @@ To install the library, run the following command: npm install angular-http-handler ``` + ## Usage In your Angular component, you can apply the handle function to any HTTP request. @@ -65,9 +67,7 @@ export class AppComponent implements OnInit { } ``` - -## API - +### API The `handle` function manages HTTP requests with loading state, error handling and retry. Parameters: @@ -93,12 +93,15 @@ Delay between retries in milliseconds. An Observable that handles the request, error, retry. -The `setDefaultErrorHandler` set default error handler for every handler request. In case custom error handler is passed as a parameter to handle function it will overwrite the default one. -Use it on root component on init method: +## Configuration (Optional) + +If you want to define custom default parameters you should do it in your root component before any http call. +- The `defaultErrorHandler` set default error handler for every request wrapped by handler. In case custom error handler is passed as a parameter to handle function it will overwrite the default one. +- The `defaultRetryCount` and `defaultRetryDelay` set default number of retry in case of error and time between the calls. ```typescript import { HttpErrorResponse } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; -import { setDefaultErrorHandler } from 'angular-http-handler'; +import { defaultErrorHandler } from 'angular-http-handler'; @Component({ selector: 'app-root', @@ -106,37 +109,52 @@ import { setDefaultErrorHandler } from 'angular-http-handler'; styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { + ngOnInit(): void { - setDefaultErrorHandler((error: HttpErrorResponse) => { - console.log('deafult handler', error); - customErrorHandlerFuction(error); + + configureHandler({ + defaultErrorHandler: (error: HttpErrorResponse) => { + console.log('deafult handler', error); + }, + defaultRetryCount: 0, + defaultRetryDelay: 0 }); } } ``` +### Fallback Response Behavior -The `defaultRetryCount` and `setDefaultRetryDelay` set default number of retry in case of error and time between the calls. If you pass it as a parameter it will overwrite the default value. -Use it on root component on init method: +The `handle` function returns a fallback response in case you define it as a 3rd parameter. In case you do not define it it will remain undefined and it will not trigger dataSetter function. + +## Aditional Options + +### `pendingRequestsCount()` +This function returns an Observable that emits the total number of pending requests. It helps track how many requests wrapped by handler are still in progress. ```typescript -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, OnInit } from '@angular/core'; -import { setDefaultRetryCount, setDefaultRetryDelay } from 'angular-http-handler'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { pendingRequestsCount } from 'angular-http-handler'; +import { Subscription } from 'rxjs'; + @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) -export class AppComponent implements OnInit { - ngOnInit(): void { - setDefaultRetryCount(2); - setDefaultRetryDelay(500); - } -} -``` +export class AppComponent implements OnInit, OnDestroy { + subs = new Subscription; -## Fallback Response Behavior + ngOnInit(): void { -The `handle` function returns a fallback response in case you define it as a 3rd parameter. In case you do not define it it will remain undefined and it will not trigger dataSetter function. \ No newline at end of file + this.subs = pendingRequestsCount().subscribe(count => { + console.log('Pending request count: ', count); + }); + } + + ngOnDestroy(): void { + this.subs.unsubscribe(); + } +} +``` \ No newline at end of file diff --git a/projects/angular-http-handler/src/lib/http-handler.ts b/projects/angular-http-handler/src/lib/http-handler.ts index ff3b9c1..b0dcf09 100644 --- a/projects/angular-http-handler/src/lib/http-handler.ts +++ b/projects/angular-http-handler/src/lib/http-handler.ts @@ -1,19 +1,28 @@ import { HttpErrorResponse } from "@angular/common/http"; -import { catchError, finalize, Observable, of, retry, tap } from "rxjs"; +import { BehaviorSubject, catchError, finalize, Observable, of, retry, tap } from "rxjs"; + +export interface IHandlerConfig { + defaultRetryCount?: number; + defaultRetryDelay?: number; + defaultErrorHandler?: (error: HttpErrorResponse) => void; +} let defaultErrorHandler: ((error: HttpErrorResponse) => void) | undefined; -export function setDefaultErrorHandler(handler: (error: HttpErrorResponse) => void) { - defaultErrorHandler = handler; +let defaultRetryCount = 0; +let defaultRetryDelay = 0; +export function configureHandler(config: IHandlerConfig) { + defaultErrorHandler = config.defaultErrorHandler; + defaultRetryCount = config.defaultRetryCount ?? 0; + defaultRetryDelay = config.defaultRetryDelay ?? 0; } -let defaultRetryCount: number = 0; -export function setDefaultRetryCount(count: number) { - defaultRetryCount = count; -} -let defaultRetryDelay: number = 0; -export function setDefaultRetryDelay(delay: number) { - defaultRetryDelay = delay; +let requestCount = 0; +let requestsSubject = new BehaviorSubject(0); +let requests$ = requestsSubject.asObservable(); + +export function pendingRequestsCount(): Observable { + return requests$; } export function handle( @@ -25,6 +34,8 @@ export function handle( retryDelay: number = defaultRetryDelay, ): (source$: Observable) => Observable { return (source$: Observable) => { + requestCount++; + requestsSubject.next(requestCount); if(loadingSetter){ loadingSetter(true); } @@ -38,7 +49,7 @@ export function handle( tap((data: T) => dataSetter(data)), - catchError((error: HttpErrorResponse, caught: Observable) => { + catchError((error: HttpErrorResponse) => { if (errorHandler) { errorHandler(error); } else if (defaultErrorHandler) { @@ -53,6 +64,9 @@ export function handle( }), finalize(() => { + requestCount--; + requestCount = requestCount < 0 ? 0 : requestCount; + requestsSubject.next(requestCount); if(loadingSetter){ loadingSetter(false); } diff --git a/projects/http-handler-example/src/app/app.component.ts b/projects/http-handler-example/src/app/app.component.ts index bedbc34..69240d3 100644 --- a/projects/http-handler-example/src/app/app.component.ts +++ b/projects/http-handler-example/src/app/app.component.ts @@ -1,6 +1,7 @@ import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Component, inject, OnInit } from '@angular/core'; -import { handle, setDefaultErrorHandler, setDefaultRetryCount, setDefaultRetryDelay } from 'angular-http-handler'; +import { Component, inject, OnDestroy, OnInit } from '@angular/core'; +import { configureHandler, handle, pendingRequestsCount } from 'angular-http-handler'; +import { delay, Subscription } from 'rxjs'; interface Post { userId: number; @@ -14,27 +15,34 @@ interface Post { templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) -export class AppComponent implements OnInit { +export class AppComponent implements OnInit, OnDestroy { + private apiUrl = 'https://jsonplaceholder.typicode.com/posts'; http = inject(HttpClient); loading = false; response: any = null; + subs = new Subscription; + ngOnInit(): void { - setDefaultErrorHandler((error: HttpErrorResponse) => { - console.log('deafult handler', error) + configureHandler({ + defaultErrorHandler: (error: HttpErrorResponse) => { + console.log('deafult handler', error); + }, + defaultRetryCount: 0, + defaultRetryDelay: 0 }); - setDefaultRetryCount(0); - setDefaultRetryDelay(500); + this.subs.add(pendingRequestsCount().subscribe(count => { + console.log('Pending request count: ', count); + })); this.http.get(this.apiUrl).pipe(handle( (response) => { this.response = response; - console.log(response) + console.log(response); }, (loading) => { // OPTIONAL - loader indicator - this.loading = loading; console.log(loading) }, [], // OPTIONAL - custom fallback value @@ -42,5 +50,25 @@ export class AppComponent implements OnInit { 2, // OPTIONAL - retry count 1000, // OTIONAL - retry delay )).subscribe(); + + this.http.get(this.apiUrl + '/1').pipe(handle( + (response) => { + console.log(response) + } + )).subscribe(); + + this.http.get(this.apiUrl).pipe(delay(3000),handle( + (response) => { + console.log(response) + } + )).subscribe(); + + + + } + + ngOnDestroy(): void { + this.subs.unsubscribe(); } + } diff --git a/projects/http-handler-example/src/app/app.module.ts b/projects/http-handler-example/src/app/app.module.ts index 817a096..f376f3e 100644 --- a/projects/http-handler-example/src/app/app.module.ts +++ b/projects/http-handler-example/src/app/app.module.ts @@ -2,7 +2,6 @@ import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule, HttpErrorResponse } from '@angular/common/http'; import { AppComponent } from './app.component'; -import { setDefaultErrorHandler } from 'angular-http-handler'; @NgModule({