diff --git a/README.md b/README.md index cb60651..947ebc5 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ export class AppComponent implements OnInit { this.loading = loading; console.log(loading); }, + [], // OPTIONAL - custom fallback value (error) => { // OPTIONAL - custom error handler console.log(error); }, @@ -64,20 +65,10 @@ export class AppComponent implements OnInit { } ``` -## Fallback Response Behavior - -The `handle` function guarantees that a fallback response will always be returned in case of an error, based on the type of the response (`T`). - -- **If the expected response is an array type (e.g., `string[]`, `any[]`)**, the fallback will be an empty array (`[]`). -- **If the expected response is any other type (e.g., `string`, `number`, `object`)**, the fallback will be `null`. - -This ensures that the `dataSetter` will always receive a value of type `T` even in the case of an error, simplifying error handling and avoiding undefined values in your application. - ## API -The handle function manages HTTP requests with loading state, error handling and retry. - +The `handle` function manages HTTP requests with loading state, error handling and retry. Parameters: - dataSetter: (response: T) => void @@ -86,6 +77,9 @@ Function to set the data when the request succeeds (e.g., this.data = response). - loadingSetter?: (loading: boolean) => void Function to set the loading state (e.g., this.loading = loading). +- fallbackValue?: any +Value that will be returned in case of error. + - errorHandler?: (error: HttpErrorResponse) => void Optional function to handle errors (e.g., console.error(error)). @@ -96,4 +90,53 @@ Number of retries for failed requests. Defaults to 0. Delay between retries in milliseconds. - Returns -An Observable that handles the request, error, retry. \ No newline at end of file +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: +```typescript +import { HttpErrorResponse } from '@angular/common/http'; +import { Component, OnInit } from '@angular/core'; +import { setDefaultErrorHandler } from 'angular-http-handler'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent implements OnInit { + ngOnInit(): void { + setDefaultErrorHandler((error: HttpErrorResponse) => { + console.log('deafult handler', error); + customErrorHandlerFuction(error); + }); + } +} +``` + + +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: +```typescript +import { HttpErrorResponse } from '@angular/common/http'; +import { Component, OnInit } from '@angular/core'; +import { setDefaultRetryCount, setDefaultRetryDelay } from 'angular-http-handler'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent implements OnInit { + ngOnInit(): void { + setDefaultRetryCount(2); + setDefaultRetryDelay(500); + } +} +``` + + +## Fallback Response Behavior + +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 diff --git a/projects/angular-http-handler/README.md b/projects/angular-http-handler/README.md index cb60651..947ebc5 100644 --- a/projects/angular-http-handler/README.md +++ b/projects/angular-http-handler/README.md @@ -53,6 +53,7 @@ export class AppComponent implements OnInit { this.loading = loading; console.log(loading); }, + [], // OPTIONAL - custom fallback value (error) => { // OPTIONAL - custom error handler console.log(error); }, @@ -64,20 +65,10 @@ export class AppComponent implements OnInit { } ``` -## Fallback Response Behavior - -The `handle` function guarantees that a fallback response will always be returned in case of an error, based on the type of the response (`T`). - -- **If the expected response is an array type (e.g., `string[]`, `any[]`)**, the fallback will be an empty array (`[]`). -- **If the expected response is any other type (e.g., `string`, `number`, `object`)**, the fallback will be `null`. - -This ensures that the `dataSetter` will always receive a value of type `T` even in the case of an error, simplifying error handling and avoiding undefined values in your application. - ## API -The handle function manages HTTP requests with loading state, error handling and retry. - +The `handle` function manages HTTP requests with loading state, error handling and retry. Parameters: - dataSetter: (response: T) => void @@ -86,6 +77,9 @@ Function to set the data when the request succeeds (e.g., this.data = response). - loadingSetter?: (loading: boolean) => void Function to set the loading state (e.g., this.loading = loading). +- fallbackValue?: any +Value that will be returned in case of error. + - errorHandler?: (error: HttpErrorResponse) => void Optional function to handle errors (e.g., console.error(error)). @@ -96,4 +90,53 @@ Number of retries for failed requests. Defaults to 0. Delay between retries in milliseconds. - Returns -An Observable that handles the request, error, retry. \ No newline at end of file +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: +```typescript +import { HttpErrorResponse } from '@angular/common/http'; +import { Component, OnInit } from '@angular/core'; +import { setDefaultErrorHandler } from 'angular-http-handler'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent implements OnInit { + ngOnInit(): void { + setDefaultErrorHandler((error: HttpErrorResponse) => { + console.log('deafult handler', error); + customErrorHandlerFuction(error); + }); + } +} +``` + + +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: +```typescript +import { HttpErrorResponse } from '@angular/common/http'; +import { Component, OnInit } from '@angular/core'; +import { setDefaultRetryCount, setDefaultRetryDelay } from 'angular-http-handler'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent implements OnInit { + ngOnInit(): void { + setDefaultRetryCount(2); + setDefaultRetryDelay(500); + } +} +``` + + +## Fallback Response Behavior + +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 diff --git a/projects/angular-http-handler/package.json b/projects/angular-http-handler/package.json index 55d57f5..136d3ed 100644 --- a/projects/angular-http-handler/package.json +++ b/projects/angular-http-handler/package.json @@ -1,6 +1,6 @@ { "name": "angular-http-handler", - "version": "0.0.2", + "version": "1.0.0", "description": "This is the http handler utility for Angular http requests", "keywords": ["http", "angular", "loading", "error-handler"], "author": { diff --git a/projects/angular-http-handler/src/lib/http-handler.ts b/projects/angular-http-handler/src/lib/http-handler.ts index c77bacf..ff3b9c1 100644 --- a/projects/angular-http-handler/src/lib/http-handler.ts +++ b/projects/angular-http-handler/src/lib/http-handler.ts @@ -1,46 +1,64 @@ import { HttpErrorResponse } from "@angular/common/http"; import { catchError, finalize, Observable, of, retry, tap } from "rxjs"; +let defaultErrorHandler: ((error: HttpErrorResponse) => void) | undefined; +export function setDefaultErrorHandler(handler: (error: HttpErrorResponse) => void) { + defaultErrorHandler = handler; +} + +let defaultRetryCount: number = 0; +export function setDefaultRetryCount(count: number) { + defaultRetryCount = count; +} + +let defaultRetryDelay: number = 0; +export function setDefaultRetryDelay(delay: number) { + defaultRetryDelay = delay; +} + export function handle( dataSetter: (response: T) => void, loadingSetter?: (loading: boolean) => void, + fallbackValue?: any, errorHandler?: (error: HttpErrorResponse) => void, - retryCount: number = 0, - retryDelay?: number, + retryCount: number = defaultRetryCount, + retryDelay: number = defaultRetryDelay, ): (source$: Observable) => Observable { - return (source$: Observable) => - source$.pipe( - tap(() => { - if(loadingSetter){ - loadingSetter(true); - } - }), + return (source$: Observable) => { + if(loadingSetter){ + loadingSetter(true); + } + return source$.pipe( + retry({ count: retryCount, delay: retryDelay, resetOnSuccess: true }), + tap((data: T) => dataSetter(data)), - catchError((error) => { -/* const errorMsg = error.error instanceof ErrorEvent - ? `Error: ${error.error.message}` // Client-side error - : `Error Code: ${error.status}, Message: ${error.message}`; // Server-side error - console.error(errorMsg); */ - - // Call the provided error handler if it exists - if (errorHandler) { - errorHandler(error); - } - - const fallback = (Array.isArray([] as unknown as T) ? [] : null) as T; - - dataSetter(fallback); - return of(fallback); + + catchError((error: HttpErrorResponse, caught: Observable) => { + if (errorHandler) { + errorHandler(error); + } else if (defaultErrorHandler) { + defaultErrorHandler(error); + } + + if(fallbackValue !== undefined){ + dataSetter(fallbackValue as T); + return of(fallbackValue as T); + } + return of(null as T); }), + finalize(() => { if(loadingSetter){ loadingSetter(false); } }) - ); - } \ No newline at end of file + + ); + } +} + diff --git a/projects/http-handler-example/src/app/app.component.html b/projects/http-handler-example/src/app/app.component.html index e69de29..ef8cae6 100644 --- a/projects/http-handler-example/src/app/app.component.html +++ b/projects/http-handler-example/src/app/app.component.html @@ -0,0 +1,6 @@ +
+ Loading... +
+
+ {{response | json}} +
\ No newline at end of file diff --git a/projects/http-handler-example/src/app/app.component.ts b/projects/http-handler-example/src/app/app.component.ts index 7e1c80c..bedbc34 100644 --- a/projects/http-handler-example/src/app/app.component.ts +++ b/projects/http-handler-example/src/app/app.component.ts @@ -1,6 +1,13 @@ -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { Component, inject, OnInit } from '@angular/core'; -import { handle } from 'angular-http-handler'; +import { handle, setDefaultErrorHandler, setDefaultRetryCount, setDefaultRetryDelay } from 'angular-http-handler'; + +interface Post { + userId: number; + id: number; + title: string; + body: string; +} @Component({ selector: 'app-root', @@ -8,27 +15,32 @@ import { handle } from 'angular-http-handler'; styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { - private apiUrl = 'YOUR API URL'; + private apiUrl = 'https://jsonplaceholder.typicode.com/posts'; http = inject(HttpClient); loading = false; - response: any[] = []; + response: any = null; ngOnInit(): void { - this.http.get(this.apiUrl).pipe( - handle( - (response) => { - this.response = response; - console.log(response) - }, - (loading) => { // OPTIONAL - loader indicator - this.loading = loading; - console.log(loading) - }, - (e) => console.log(e, 'custom'), // OPTIONAL - custom error handler - 2, // OPTIONAL - retry count - 1000, // OTIONAL - retry delay - ) - ).subscribe(); + setDefaultErrorHandler((error: HttpErrorResponse) => { + console.log('deafult handler', error) + }); + setDefaultRetryCount(0); + setDefaultRetryDelay(500); + + this.http.get(this.apiUrl).pipe(handle( + (response) => { + this.response = response; + console.log(response) + }, + (loading) => { // OPTIONAL - loader indicator + this.loading = loading; + console.log(loading) + }, + [], // OPTIONAL - custom fallback value + (e) => console.log(e, 'custom'), // OPTIONAL - custom error handler + 2, // OPTIONAL - retry count + 1000, // OTIONAL - retry delay + )).subscribe(); } } diff --git a/projects/http-handler-example/src/app/app.module.ts b/projects/http-handler-example/src/app/app.module.ts index b70f711..817a096 100644 --- a/projects/http-handler-example/src/app/app.module.ts +++ b/projects/http-handler-example/src/app/app.module.ts @@ -2,6 +2,7 @@ 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({ @@ -16,4 +17,4 @@ import { AppComponent } from './app.component'; ], bootstrap: [AppComponent] }) -export class AppModule { } +export class AppModule {}