MireaFrontend/src/api/api.service.ts

159 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}