feat(common/data-access): enhance error handling with ResponseArgsError operator

Add catchResponseArgsErrorPipe operator to transform HTTP errors into structured
ResponseArgsError instances. This provides consistent error handling across
data access services by automatically converting HttpErrorResponse objects
with ResponseArgs payloads into typed ResponseArgsError instances.

Changes include:
- New catchResponseArgsErrorPipe operator for standardized error transformation
- Enhanced DataAccessError with proper prototype chain setup
- Integration in CatalougeSearchService for loyalty items search
- Export operator from common data-access module

This improves error consistency and debugging capabilities across the application
by ensuring all API errors follow the same structure and typing.

Refs: #5258
This commit is contained in:
Nino
2025-09-15 14:04:34 +02:00
parent 707802ce0d
commit 0269473a18
4 changed files with 60 additions and 3 deletions

View File

@@ -1,7 +1,13 @@
import { inject, Injectable } from '@angular/core';
import { SearchService } from '@generated/swagger/cat-search-api';
import {
ListResponseArgsOfItemDTO,
SearchService,
} from '@generated/swagger/cat-search-api';
import { firstValueFrom, map, Observable } from 'rxjs';
import { takeUntilAborted } from '@isa/common/data-access';
import {
catchResponseArgsErrorPipe,
takeUntilAborted,
} from '@isa/common/data-access';
import { Item } from '../models';
import {
SearchByTermInput,
@@ -70,7 +76,10 @@ export class CatalougeSearchService {
skip,
take,
})
.pipe(takeUntilAborted(abortSignal));
.pipe(
takeUntilAborted(abortSignal),
catchResponseArgsErrorPipe<ListResponseArgsOfItemDTO>(),
);
const res = await firstValueFrom(req$);

View File

@@ -44,5 +44,7 @@ export class DataAccessError<TCode extends string, TData = void> extends Error {
public readonly data: TData,
) {
super(message);
Object.setPrototypeOf(this, new.target.prototype);
this.name = new.target.name;
}
}

View File

@@ -0,0 +1,45 @@
import { catchError } from 'rxjs/operators';
import { OperatorFunction, throwError } from 'rxjs';
import { ResponseArgsError } from '../errors';
import { HttpErrorResponse } from '@angular/common/http';
import { ResponseArgs } from '../models';
/**
*
* Operator that catches errors from an observable stream and transforms them into
*
* `ResponseArgsError` instances when applicable.
* This operator is useful for handling HTTP errors that return a structured
* response conforming to the `ResponseArgs` interface.
*
* If the error is already a `ResponseArgsError`, it is re-thrown as is.
* If the error is an `HttpErrorResponse` with a valid `ResponseArgs` payload,
* it creates and throws a new `ResponseArgsError`.
* For all other error types, it re-throws the original error.
*
*/
export const catchResponseArgsErrorPipe = <T>(): OperatorFunction<T, T> =>
catchError((err: unknown) => {
if (err instanceof ResponseArgsError) {
return throwError(() => err);
}
if (err instanceof HttpErrorResponse && err.error) {
const payload = err.error as Partial<ResponseArgs<unknown>>;
if (payload.error === true) {
return throwError(
() =>
new ResponseArgsError({
error: true,
message: payload.message,
invalidProperties: payload.invalidProperties ?? {},
}),
);
}
}
return throwError(() =>
err instanceof Error ? err : new Error(String(err)),
);
});

View File

@@ -1,2 +1,3 @@
export * from './take-until-aborted';
export * from './take-unitl-keydown';
export * from './catch-response-args-error';