Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix / Enhancement For Error Handler, Update Documentation #18787

Merged
merged 7 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 12 additions & 12 deletions docs/en/UI/Angular/HTTP-Requests.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,23 +219,23 @@ import { ContentProjectionService, PROJECTION_STRATEGY } from '@abp/ng.core';
import { ToasterService } from '@abp/ng.theme.shared';
import { HttpErrorResponse } from '@angular/common/http';
import { Injector } from '@angular/core';
import { throwError } from 'rxjs';
import { of, EMPTY } from 'rxjs';
import { Error404Component } from './error404/error404.component';

export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) {
if (httpError.status === 400) {
const toaster = injector.get(ToasterService);
toaster.error(httpError.error?.error?.message || 'Bad request!', '400');
return;
return EMPTY;
}

if (httpError.status === 404) {
const contentProjection = injector.get(ContentProjectionService);
contentProjection.projectContent(PROJECTION_STRATEGY.AppendComponentToBody(Error404Component));
return;
return EMPTY;
}

return throwError(httpError);
return of(httpError);
}

// app.module.ts
Expand Down Expand Up @@ -267,22 +267,22 @@ In the example above:

![custom-error-handler-404-component](images/custom-error-handler-404-component.jpg)

- Since `throwError(httpError)` is returned at bottom of the `handleHttpErrors`, the `ErrorHandler` will handle the HTTP errors except 400 and 404 errors.
- Since `of(httpError)` is returned at bottom of the `handleHttpErrors`, the `ErrorHandler` will handle the HTTP errors except 400 and 404 errors.


**Note 1:** If you put `return` to next line of handling an error, default error handling will not work for that error.
**Note 1:** If you put `return EMPTY` to next line of handling an error, default error handling will not work for that error. `EMPTY` can be imported from `rxjs`

```js
export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) {
if (httpError.status === 403) {
// handle 403 errors here
return; // put return to skip default error handling
return EMPTY; // put return to skip default error handling
}
}
```

**Note 2:** If you put `return throwError(httpError)`, default error handling will work.
- `throwError` is a function. It can be imported from `rxjs`.
**Note 2:** If you put `return of(httpError)`, default error handling will work.
- `of` is a function. It can be imported from `rxjs`.
- `httpError` is the second parameter of the error handler function which is registered to the `HTTP_ERROR_HANDLER` provider. Type of the `httpError` is `HttpErrorResponse`.

```js
Expand All @@ -291,11 +291,11 @@ import { throwError } from 'rxjs';
export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) {
if (httpError.status === 500) {
// handle 500 errors here
return;
return EMPTY;
}

// you can return the throwError(httpError) at bottom of the function to run the default handler of ABP for HTTP errors that you didn't handle above.
return throwError(httpError)
// you can return the of(httpError) at bottom of the function to run the default handler of ABP for HTTP errors that you didn't handle above.
return of(httpError)
}
```

Expand Down
6 changes: 3 additions & 3 deletions npm/ng-packs/packages/core/src/lib/services/rest.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ export class RestService {
protected externalHttp: ExternalHttpClient,
protected environment: EnvironmentService,
protected httpErrorReporter: HttpErrorReporterService,
) {}
) { }

protected getApiFromStore(apiName: string | undefined): string {
return this.environment.getApiUrl(apiName);
}

handleError(err: any): Observable<any> {
this.httpErrorReporter.reportError(err);
return throwError(err);
return throwError(() => err);
}

request<T, R>(
Expand All @@ -51,7 +51,7 @@ export class RestService {
}),
...options,
} as any)
.pipe(catchError(err => (skipHandleError ? throwError(err) : this.handleError(err))));
.pipe(catchError(err => (skipHandleError ? throwError(() => err) : this.handleError(err))));
}
private getHttpClient(isExternal: boolean) {
return isExternal ? this.externalHttp : this.http;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { inject, Injectable, Injector } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { catchError, filter, switchMap } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { filter, switchMap } from 'rxjs/operators';

import { HttpErrorReporterService } from '@abp/ng.core';

import { CustomHttpErrorHandlerService } from '../models/common';
import { CustomHttpErrorHandlerService, HttpErrorHandler } from '../models/common';
import { Confirmation } from '../models/confirmation';

import { CUSTOM_ERROR_HANDLERS, HTTP_ERROR_HANDLER } from '../tokens/http-error.token';
Expand All @@ -21,10 +21,8 @@ export class ErrorHandler {
protected readonly confirmationService = inject(ConfirmationService);
protected readonly routerErrorHandlerService = inject(RouterErrorHandlerService);
protected readonly httpErrorConfig = inject(HTTP_ERROR_CONFIG);
protected readonly customErrorHandlers = inject(CUSTOM_ERROR_HANDLERS);
protected readonly defaultHttpErrorHandler = (_, err: HttpErrorResponse) => throwError(() => err);
protected readonly httpErrorHandler =
inject(HTTP_ERROR_HANDLER, { optional: true }) || this.defaultHttpErrorHandler;
protected readonly defaultErrorHandlers = inject(CUSTOM_ERROR_HANDLERS);
protected readonly httpErrorHandler = inject(HTTP_ERROR_HANDLER, { optional: true });

constructor(protected injector: Injector) {
this.listenToRestError();
Expand All @@ -42,10 +40,11 @@ export class ErrorHandler {
}

protected executeErrorHandler = (error: HttpErrorResponse) => {
const errHandler = this.httpErrorHandler(this.injector, error);
const isObservable = errHandler instanceof Observable;

return (isObservable ? errHandler : of(null)).pipe(catchError(err => of(err)));
if (this.httpErrorHandler) {
return this.httpErrorHandler(this.injector, error);
}

return of(error);
};

protected sortHttpErrorHandlers(
Expand All @@ -56,17 +55,17 @@ export class ErrorHandler {
}

protected handleError(err: unknown) {
if (this.customErrorHandlers && this.customErrorHandlers.length) {
const canHandleService = this.customErrorHandlers
if (this.defaultErrorHandlers && this.defaultErrorHandlers.length) {
const errorHandlerService = this.defaultErrorHandlers
.sort(this.sortHttpErrorHandlers)
.find(service => service.canHandle(err));

if (canHandleService) {
canHandleService.execute();
if (errorHandlerService) {
errorHandlerService.execute();
return;
}
}

this.showError().subscribe();
}

Expand Down
4 changes: 2 additions & 2 deletions npm/ng-packs/packages/theme-shared/src/lib/models/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Type } from '@angular/core';
import { Injector, Type } from '@angular/core';
import { Validation } from '@ngx-validate/core';
import { Observable } from 'rxjs';
import { ConfirmationIcons } from '../tokens/confirmation-icons.token';
Expand All @@ -20,7 +20,7 @@ export interface HttpErrorConfig {
hideCloseIcon?: boolean;
};
}
export type HttpErrorHandler<T = any> = (httpError: HttpErrorResponse) => Observable<T>;
export type HttpErrorHandler<T = any> = (injector: Injector, httpError: HttpErrorResponse) => Observable<T>;
export type LocaleDirection = 'ltr' | 'rtl';

export interface CustomHttpErrorHandlerService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { AbpFormatErrorHandlerService } from '../services/abp-format-error-handl
import { StatusCodeErrorHandlerService } from '../services/status-code-error-handler.service';
import { UnknownStatusCodeErrorHandlerService } from '../services/unknown-status-code-error-handler.service';

export const ERROR_HANDLERS_PROVIDERS: Provider[] = [
export const DEFAULT_HANDLERS_PROVIDERS: Provider[] = [
{
provide: CUSTOM_ERROR_HANDLERS,
multi: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { NgxDatatableListDirective } from './directives/ngx-datatable-list.direc
import { DocumentDirHandlerService } from './handlers/document-dir.handler';
import { ErrorHandler } from './handlers/error.handler';
import { RootParams } from './models/common';
import { ERROR_HANDLERS_PROVIDERS, NG_BOOTSTRAP_CONFIG_PROVIDERS } from './providers';
import { DEFAULT_HANDLERS_PROVIDERS, NG_BOOTSTRAP_CONFIG_PROVIDERS } from './providers';
import { THEME_SHARED_ROUTE_PROVIDERS } from './providers/route.provider';
import { THEME_SHARED_APPEND_CONTENT } from './tokens/append-content.token';
import { HTTP_ERROR_CONFIG, httpErrorConfigFactory } from './tokens/http-error.token';
Expand Down Expand Up @@ -149,7 +149,7 @@ export class ThemeSharedModule {
},
},
tenantNotFoundProvider,
ERROR_HANDLERS_PROVIDERS,
DEFAULT_HANDLERS_PROVIDERS,
],
};
}
Expand Down