Skip to content

Commit

Permalink
add request count and universal config
Browse files Browse the repository at this point in the history
  • Loading branch information
vojvodicn23 committed Sep 17, 2024
1 parent 5fd944d commit 59f9a02
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 69 deletions.
66 changes: 42 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.
Expand Down Expand Up @@ -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:

Expand All @@ -93,50 +93,68 @@ Delay between retries in milliseconds.
An Observable<T> 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',
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);

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<number> 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.
this.subs = pendingRequestsCount().subscribe(count => {
console.log('Pending request count: ', count);
});
}

ngOnDestroy(): void {
this.subs.unsubscribe();
}
}
```
66 changes: 42 additions & 24 deletions projects/angular-http-handler/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.
Expand Down Expand Up @@ -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:

Expand All @@ -93,50 +93,68 @@ Delay between retries in milliseconds.
An Observable<T> 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',
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);

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<number> 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.
this.subs = pendingRequestsCount().subscribe(count => {
console.log('Pending request count: ', count);
});
}

ngOnDestroy(): void {
this.subs.unsubscribe();
}
}
```
36 changes: 25 additions & 11 deletions projects/angular-http-handler/src/lib/http-handler.ts
Original file line number Diff line number Diff line change
@@ -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<number>(0);
let requests$ = requestsSubject.asObservable();

export function pendingRequestsCount(): Observable<number> {
return requests$;
}

export function handle<T>(
Expand All @@ -25,6 +34,8 @@ export function handle<T>(
retryDelay: number = defaultRetryDelay,
): (source$: Observable<T>) => Observable<T> {
return (source$: Observable<T>) => {
requestCount++;
requestsSubject.next(requestCount);
if(loadingSetter){
loadingSetter(true);
}
Expand All @@ -38,7 +49,7 @@ export function handle<T>(

tap((data: T) => dataSetter(data)),

catchError((error: HttpErrorResponse, caught: Observable<T>) => {
catchError((error: HttpErrorResponse) => {
if (errorHandler) {
errorHandler(error);
} else if (defaultErrorHandler) {
Expand All @@ -53,6 +64,9 @@ export function handle<T>(
}),

finalize(() => {
requestCount--;
requestCount = requestCount < 0 ? 0 : requestCount;
requestsSubject.next(requestCount);
if(loadingSetter){
loadingSetter(false);
}
Expand Down
46 changes: 37 additions & 9 deletions projects/http-handler-example/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -14,33 +15,60 @@ 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<Post[]>(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
(e) => console.log(e, 'custom'), // OPTIONAL - custom error handler
2, // OPTIONAL - retry count
1000, // OTIONAL - retry delay
)).subscribe();

this.http.get<Post>(this.apiUrl + '/1').pipe(handle(
(response) => {
console.log(response)
}
)).subscribe();

this.http.get<Post>(this.apiUrl).pipe(delay(3000),handle(
(response) => {
console.log(response)
}
)).subscribe();



}

ngOnDestroy(): void {
this.subs.unsubscribe();
}

}
1 change: 0 additions & 1 deletion projects/http-handler-example/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down

0 comments on commit 59f9a02

Please sign in to comment.