refactor: change apiService to abstract
This commit is contained in:
parent
ad0940c087
commit
5ff24d49b5
158
src/api/api.service.ts
Normal file
158
src/api/api.service.ts
Normal file
@ -0,0 +1,158 @@
|
||||
import {catchError, mergeMap, Observable, retryWhen, timer} from "rxjs";
|
||||
import {HttpClient, HttpErrorResponse} from "@angular/common/http";
|
||||
import {NotifyColor, OpenNotifyService} from "@service/open-notify.service";
|
||||
import {environment} from "@/config/environment";
|
||||
import {Router} from "@angular/router";
|
||||
import {Injectable} from "@angular/core";
|
||||
|
||||
export function retryWithInterval<T>(): (source: Observable<T>) => Observable<T> {
|
||||
return (source: Observable<T>) =>
|
||||
source.pipe(
|
||||
retryWhen((errors: Observable<any>) =>
|
||||
errors.pipe(
|
||||
mergeMap((error, index) => {
|
||||
if (index < (environment.maxRetry < 0 ? Infinity : environment.maxRetry - 1) && !error.status.toString().startsWith('4') && !error.status.toString().startsWith('5')) {
|
||||
console.log(`Retrying after ${environment.retryDelay}ms...`);
|
||||
return timer(environment.retryDelay);
|
||||
} else {
|
||||
if (error.status.toString().startsWith('4'))
|
||||
console.error(`Server returned a client code error`);
|
||||
else
|
||||
console.error(`Exceeded maximum retries (${environment.maxRetry})`);
|
||||
|
||||
throw error;
|
||||
}
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
*/
|
||||
|
||||
export enum AvailableVersion {
|
||||
v1
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export default abstract class ApiService {
|
||||
constructor(private http: HttpClient, private notify: OpenNotifyService, private router: Router) {
|
||||
}
|
||||
|
||||
private urlApi = environment.apiUrl;
|
||||
protected abstract basePath: string;
|
||||
protected abstract version: AvailableVersion;
|
||||
|
||||
private static addQuery(endpoint: string, queryParams?: Record<string, string | number | boolean | Array<any> | null> | null): string {
|
||||
const url = new URL(endpoint);
|
||||
|
||||
if (queryParams) {
|
||||
Object.keys(queryParams).forEach(key => {
|
||||
const value = queryParams[key];
|
||||
if (value !== null && value !== undefined) {
|
||||
if (typeof(value) === typeof(Array)) {
|
||||
(value as Array<any>).forEach(x => url.searchParams.append(key, x.toString()));
|
||||
}
|
||||
else
|
||||
url.searchParams.append(key, value.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return url.href;
|
||||
}
|
||||
|
||||
private static combineUrls(...parts: string[]): string {
|
||||
let test = parts.map(part => part.replace(/(^\/+|\/+$)/g, '')).join('/');
|
||||
console.log(test);
|
||||
return test;
|
||||
}
|
||||
|
||||
public get<Type>(endpoint: string = '', queryParams: Record<string, string | number | boolean | Array<any> | null> | null = null): Observable<Type> {
|
||||
return this.http.get<Type>(ApiService.addQuery(ApiService.combineUrls(this.urlApi, AvailableVersion[this.version], this.basePath, endpoint), queryParams), {withCredentials: true}).pipe(
|
||||
retryWithInterval<Type>(),
|
||||
catchError(error => {
|
||||
this.handleError(error);
|
||||
throw error;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public post<Type>(endpoint: string, data: any, queryParams: Record<string, string | number | boolean | Array<any> | null> | null = null): Observable<Type> {
|
||||
return this.http.post<Type>(ApiService.addQuery(ApiService.combineUrls(this.urlApi, AvailableVersion[this.version], this.basePath, endpoint), queryParams), data, {withCredentials: true}).pipe(
|
||||
retryWithInterval<Type>(),
|
||||
catchError(error => {
|
||||
this.handleError(error);
|
||||
throw error;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public put<Type>(endpoint: string, data: any, queryParams: Record<string, string | number | boolean | Array<any> | null> | null = null): Observable<Type> {
|
||||
return this.http.put<Type>(ApiService.addQuery(ApiService.combineUrls(this.urlApi, AvailableVersion[this.version], this.basePath, endpoint), queryParams), data, {withCredentials: true}).pipe(
|
||||
retryWithInterval<Type>(),
|
||||
catchError(error => {
|
||||
this.handleError(error);
|
||||
throw error;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public delete<Type>(endpoint: string): Observable<Type> {
|
||||
return this.http.delete<Type>(ApiService.combineUrls(this.urlApi, AvailableVersion[this.version], this.basePath, endpoint), {withCredentials: true}).pipe(
|
||||
retryWithInterval<Type>(),
|
||||
catchError(error => {
|
||||
this.handleError(error);
|
||||
throw error;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private handleError(error: HttpErrorResponse): void {
|
||||
// todo: change to Retry-After condition
|
||||
if (error.error.toString().includes("setup")) {
|
||||
this.router.navigate(['/setup/']);
|
||||
return;
|
||||
}
|
||||
|
||||
let message: string;
|
||||
if (error.error instanceof ErrorEvent) {
|
||||
message = `Произошла ошибка: ${error.error.message}`;
|
||||
} else {
|
||||
switch (error.status) {
|
||||
case 0:
|
||||
message = 'Неизвестная ошибка. Пожалуйста, попробуйте позже.';
|
||||
break;
|
||||
case 400:
|
||||
message = 'Ошибка запроса. Пожалуйста, проверьте отправленные данные.';
|
||||
break;
|
||||
case 401:
|
||||
message = 'Ошибка авторизации. Пожалуйста, выполните вход с правильными учетными данными.';
|
||||
break;
|
||||
case 403:
|
||||
message = 'Отказано в доступе. У вас нет разрешения на выполнение этого действия.';
|
||||
break;
|
||||
case 404:
|
||||
message = 'Запрашиваемый ресурс не найден.';
|
||||
break;
|
||||
case 500:
|
||||
message = 'Внутренняя ошибка сервера. Пожалуйста, попробуйте позже.';
|
||||
break;
|
||||
case 503:
|
||||
message = 'Сервер на обслуживании. Пожалуйста, попробуйте позже.';
|
||||
break;
|
||||
default:
|
||||
message = `Сервер вернул код ошибки: ${error.status}`;
|
||||
break;
|
||||
}
|
||||
if (error.error?.Error) {
|
||||
message += ` ${error.error.Error}`;
|
||||
}
|
||||
}
|
||||
this.notify.open(message, NotifyColor.Danger);
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {catchError, mergeMap, Observable, retryWhen, throwError, timer} from "rxjs";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {NotifyColor, OpenNotifyService} from "@service/open-notify.service";
|
||||
import {environment} from "@/config/environment";
|
||||
|
||||
export function retryWithInterval<T>(): (source: Observable<T>) => Observable<T> {
|
||||
return (source: Observable<T>) =>
|
||||
source.pipe(
|
||||
retryWhen((errors: Observable<any>) =>
|
||||
errors.pipe(
|
||||
mergeMap((error, index) => {
|
||||
if (index < (environment.maxRetry < 0 ? Infinity : environment.maxRetry - 1) && !error.status.toString().startsWith('4')) {
|
||||
console.log(`Retrying after ${environment.retryDelay}ms...`);
|
||||
return timer(environment.retryDelay);
|
||||
} else {
|
||||
console.error(`Exceeded maximum retries (${environment.maxRetry})`);
|
||||
return throwError(error);
|
||||
}
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
|
||||
export class ApiService {
|
||||
constructor(private http: HttpClient, private notify: OpenNotifyService) {
|
||||
}
|
||||
|
||||
private urlApi = environment.apiUrl;
|
||||
|
||||
get<Type>(endpoint: string): Observable<Type> {
|
||||
return this.http.get<Type>(this.urlApi + endpoint).pipe(
|
||||
retryWithInterval<Type>(),
|
||||
catchError(error => {
|
||||
this.handleError(error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
post<Type>(endpoint: string, data: any): Observable<Type> {
|
||||
return this.http.post<Type>(this.urlApi + endpoint, data).pipe(
|
||||
retryWithInterval<Type>(),
|
||||
catchError(error => {
|
||||
this.handleError(error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
put<Type>(endpoint: string, data: any): Observable<Type> {
|
||||
return this.http.put<Type>(this.urlApi + endpoint, data).pipe(
|
||||
retryWithInterval<Type>(),
|
||||
catchError(error => {
|
||||
this.handleError(error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
delete<Type>(endpoint: string): Observable<Type> {
|
||||
return this.http.delete<Type>(this.urlApi + endpoint).pipe(
|
||||
retryWithInterval<Type>(),
|
||||
catchError(error => {
|
||||
this.handleError(error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private handleError(error: any): void {
|
||||
let message: string;
|
||||
if (error.error instanceof ErrorEvent) {
|
||||
message = `Произошла ошибка: ${error.error.message}`;
|
||||
} else {
|
||||
switch (error.status) {
|
||||
case 0:
|
||||
message = 'Неизвестная ошибка. Пожалуйста, попробуйте позже.';
|
||||
break;
|
||||
case 400:
|
||||
message = 'Ошибка запроса. Пожалуйста, проверьте отправленные данные.';
|
||||
break;
|
||||
case 401:
|
||||
message = 'Ошибка авторизации. Пожалуйста, выполните вход с правильными учетными данными.';
|
||||
break;
|
||||
case 403:
|
||||
message = 'Отказано в доступе. У вас нет разрешения на выполнение этого действия.';
|
||||
break;
|
||||
case 404:
|
||||
message = 'Запрашиваемый ресурс не найден.';
|
||||
break;
|
||||
case 500:
|
||||
message = 'Внутренняя ошибка сервера. Пожалуйста, попробуйте позже.';
|
||||
break;
|
||||
default:
|
||||
message = `Сервер вернул код ошибки: ${error.status}`;
|
||||
break;
|
||||
}
|
||||
if (error.error?.Error) {
|
||||
message += ` ${error.error.Error}`;
|
||||
}
|
||||
}
|
||||
this.notify.open(message, NotifyColor.Danger);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user