refactor: implement RequestBuilder for main request

This commit is contained in:
Polianin Nikita 2024-06-27 01:50:58 +03:00
parent e36376db3a
commit 8e738d9b3d
9 changed files with 151 additions and 75 deletions

View File

@ -1,9 +1,10 @@
import {catchError, mergeMap, Observable, retryWhen, timer} from "rxjs"; import {catchError, mergeMap, Observable, retryWhen, tap, timer} from "rxjs";
import {HttpClient, HttpErrorResponse} from "@angular/common/http"; import {HttpClient, HttpErrorResponse} from "@angular/common/http";
import {NotifyColor, OpenNotifyService} from "@service/open-notify.service"; import {NotifyColor, OpenNotifyService} from "@service/open-notify.service";
import {environment} from "@environment"; import {environment} from "@environment";
import {Router} from "@angular/router"; import {Router} from "@angular/router";
import {Injectable} from "@angular/core"; import {Injectable} from "@angular/core";
import {RequestBuilder, RequestData, SetRequestBuilderAfterBuild} from "@api/RequestBuilder";
export function retryWithInterval<T>(): (source: Observable<T>) => Observable<T> { export function retryWithInterval<T>(): (source: Observable<T>) => Observable<T> {
return (source: Observable<T>) => return (source: Observable<T>) =>
@ -28,24 +29,23 @@ export function retryWithInterval<T>(): (source: Observable<T>) => Observable<T>
); );
} }
/*
@Injectable({
providedIn: 'root'
})
*/
export enum AvailableVersion { export enum AvailableVersion {
v1 v1
} }
@Injectable() @Injectable()
export default abstract class ApiService { export default abstract class ApiService implements SetRequestBuilderAfterBuild {
constructor(private http: HttpClient, private notify: OpenNotifyService, private router: Router) { constructor(private http: HttpClient, private notify: OpenNotifyService, private router: Router) {
} }
private urlApi = environment.apiUrl; private urlApi = environment.apiUrl;
protected abstract basePath: string; protected abstract basePath: string;
protected abstract version: AvailableVersion; protected abstract version: AvailableVersion;
private request: RequestData = RequestBuilder.getStandardRequestData();
public setRequestBuilder(request: RequestData): void {
this.request = request;
}
private static addQuery(endpoint: string, queryParams?: Record<string, string | number | boolean | Array<any> | null> | null): string { private static addQuery(endpoint: string, queryParams?: Record<string, string | number | boolean | Array<any> | null> | null): string {
const url = new URL(endpoint); const url = new URL(endpoint);
@ -54,10 +54,9 @@ export default abstract class ApiService {
Object.keys(queryParams).forEach(key => { Object.keys(queryParams).forEach(key => {
const value = queryParams[key]; const value = queryParams[key];
if (value !== null && value !== undefined) { if (value !== null && value !== undefined) {
if (typeof(value) === typeof(Array)) { if (typeof (value) === typeof (Array)) {
(value as Array<any>).forEach(x => url.searchParams.append(key, x.toString())); (value as Array<any>).forEach(x => url.searchParams.append(key, x.toString()));
} } else
else
url.searchParams.append(key, value.toString()); url.searchParams.append(key, value.toString());
} }
}); });
@ -72,50 +71,59 @@ export default abstract class ApiService {
return test; return test;
} }
public get<Type>(endpoint: string = '', queryParams: Record<string, string | number | boolean | Array<any> | null> | null = null): Observable<Type> { private makeHttpRequest<Type>(method: 'get' | 'post' | 'delete' | 'put'): Observable<Type> {
return this.http.get<Type>(ApiService.addQuery(ApiService.combineUrls(this.urlApi, AvailableVersion[this.version], this.basePath, endpoint), queryParams), {withCredentials: true}).pipe( const doneEndpoint = ApiService.addQuery(ApiService.combineUrls(this.urlApi, AvailableVersion[this.version], this.basePath, this.request.endpoint), this.request.queryParams);
return this.http.request<Type>(method, doneEndpoint, {
withCredentials: true,
headers: this.request.httpHeaders,
body: this.request.data
}).pipe(
tap(_ => this.request = RequestBuilder.getStandardRequestData()),
retryWithInterval<Type>(), retryWithInterval<Type>(),
catchError(error => { catchError(error => {
if (!this.request.silenceMode)
this.handleError(error); this.handleError(error);
this.request = RequestBuilder.getStandardRequestData();
throw error; throw error;
}) })
); );
} }
public post<Type>(endpoint: string, data: any, queryParams: Record<string, string | number | boolean | Array<any> | null> | null = null): Observable<Type> { public createRequestBuilder() {
return this.http.post<Type>(ApiService.addQuery(ApiService.combineUrls(this.urlApi, AvailableVersion[this.version], this.basePath, endpoint), queryParams), data, {withCredentials: true}).pipe( this.request = RequestBuilder.getStandardRequestData();
retryWithInterval<Type>(), return new RequestBuilder(this);
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> { public get<Type>(endpoint: string = ''): Observable<Type> {
return this.http.put<Type>(ApiService.addQuery(ApiService.combineUrls(this.urlApi, AvailableVersion[this.version], this.basePath, endpoint), queryParams), data, {withCredentials: true}).pipe( if (endpoint)
retryWithInterval<Type>(), this.request.endpoint = endpoint;
catchError(error => { return this.makeHttpRequest<Type>('get');
this.handleError(error);
throw error;
})
);
} }
public delete<Type>(endpoint: string): Observable<Type> { public post<Type>(endpoint: string = ''): Observable<Type> {
return this.http.delete<Type>(ApiService.combineUrls(this.urlApi, AvailableVersion[this.version], this.basePath, endpoint), {withCredentials: true}).pipe( if (endpoint)
retryWithInterval<Type>(), this.request.endpoint = endpoint;
catchError(error => { return this.makeHttpRequest<Type>('post');
this.handleError(error); }
throw error;
}) public put<Type>(endpoint: string = ''): Observable<Type> {
); if (endpoint)
this.request.endpoint = endpoint;
return this.makeHttpRequest<Type>('put');
}
public delete<Type>(endpoint: string = ''): Observable<Type> {
if (endpoint)
this.request.endpoint = endpoint;
return this.makeHttpRequest<Type>('delete');
} }
private handleError(error: HttpErrorResponse): void { private handleError(error: HttpErrorResponse): void {
// todo: change to Retry-After condition // todo: change to Retry-After condition
if (error.error.toString().includes("setup")) { if (error.error.toString().includes("setup")) {
this.router.navigate(['/setup/']); this.router.navigate(['/setup/']).then();
return; return;
} }

View File

@ -5,8 +5,8 @@ import {CampusDetailsResponse} from "@api/v1/campusDetailsResponse";
@Injectable() @Injectable()
export class CampusService extends ApiService { export class CampusService extends ApiService {
protected basePath = 'Campus/'; public readonly basePath = 'Campus/';
protected version = AvailableVersion.v1; public readonly version = AvailableVersion.v1;
public getCampus() { public getCampus() {
return this.get<CampusBasicInfoResponse[]>(); return this.get<CampusBasicInfoResponse[]>();

View File

@ -4,11 +4,14 @@ import {DisciplineResponse} from "@api/v1/disciplineResponse";
@Injectable() @Injectable()
export class DisciplineService extends ApiService { export class DisciplineService extends ApiService {
protected basePath = 'Discipline/'; public readonly basePath = 'Discipline/';
protected version = AvailableVersion.v1; public readonly version = AvailableVersion.v1;
public getDisciplines(page: number | null = null, pageSize: number | null = null) { public getDisciplines(page: number | null = null, pageSize: number | null = null) {
return this.get<DisciplineResponse[]>('', {page: page, pageSize: pageSize}); return this.createRequestBuilder()
.setQueryParams({page: page, pageSize: pageSize})
.build<ApiService>()
.get<DisciplineResponse[]>();
} }
public getById(id: number) { public getById(id: number) {

View File

@ -5,11 +5,14 @@ import {FacultyDetailsResponse} from "@api/v1/facultyDetailsResponse";
@Injectable() @Injectable()
export class FacultyService extends ApiService { export class FacultyService extends ApiService {
protected basePath = 'Faculty/'; public readonly basePath = 'Faculty/';
protected version = AvailableVersion.v1; public readonly version = AvailableVersion.v1;
public getFaculties(page: number | null = null, pageSize: number | null = null) { public getFaculties(page: number | null = null, pageSize: number | null = null) {
return this.get<FacultyResponse[]>('', {page: page, pageSize: pageSize}); return this.createRequestBuilder()
.setQueryParams({page: page, pageSize: pageSize})
.build<ApiService>()
.get<FacultyResponse[]>();
} }

View File

@ -5,11 +5,14 @@ import {GroupDetailsResponse} from "@api/v1/groupDetailsResponse";
@Injectable() @Injectable()
export class GroupService extends ApiService { export class GroupService extends ApiService {
protected basePath = 'Group/'; public readonly basePath = 'Group/';
protected version = AvailableVersion.v1; public readonly version = AvailableVersion.v1;
public getGroups(page: number | null = null, pageSize: number | null = null) { public getGroups(page: number | null = null, pageSize: number | null = null) {
return this.get<GroupResponse[]>('', {page: page, pageSize: pageSize}); return this.createRequestBuilder()
.setQueryParams({page: page, pageSize: pageSize})
.build<ApiService>()
.get<GroupResponse[]>();
} }
public getById(id: number) { public getById(id: number) {

View File

@ -5,8 +5,8 @@ import {LectureHallDetailsResponse} from "@api/v1/lectureHallDetailsResponse";
@Injectable() @Injectable()
export class LectureHallService extends ApiService { export class LectureHallService extends ApiService {
protected basePath = 'LectureHall/'; public readonly basePath = 'LectureHall/';
protected version = AvailableVersion.v1; public readonly version = AvailableVersion.v1;
public getLectureHalls() { public getLectureHalls() {
return this.get<LectureHallResponse[]>(); return this.get<LectureHallResponse[]>();

View File

@ -4,11 +4,14 @@ import {ProfessorResponse} from "@api/v1/professorResponse";
@Injectable() @Injectable()
export class ProfessorService extends ApiService { export class ProfessorService extends ApiService {
protected basePath = 'Professor/'; public readonly basePath = 'Professor/';
protected version = AvailableVersion.v1; public readonly version = AvailableVersion.v1;
public getProfessors(page: number | null = null, pageSize: number | null = null) { public getProfessors(page: number | null = null, pageSize: number | null = null) {
return this.get<ProfessorResponse[]>('', {page: page, pageSize: pageSize}); return this.createRequestBuilder()
.setQueryParams({page: page, pageSize: pageSize})
.build<ApiService>()
.get<ProfessorResponse[]>();
} }
public getById(id: number) { public getById(id: number) {

View File

@ -8,8 +8,8 @@ import {map} from "rxjs";
@Injectable() @Injectable()
export class ScheduleService extends ApiService { export class ScheduleService extends ApiService {
protected basePath = 'Schedule/'; public readonly basePath = 'Schedule/';
protected version = AvailableVersion.v1; public readonly version = AvailableVersion.v1;
public startTerm() { public startTerm() {
return this.get<string>('StartTerm').pipe(map(date => new DateOnly(date))); return this.get<string>('StartTerm').pipe(map(date => new DateOnly(date)));
@ -20,22 +20,41 @@ export class ScheduleService extends ApiService {
} }
public postSchedule(data: ScheduleRequest) { public postSchedule(data: ScheduleRequest) {
return this.post<ScheduleResponse[]>('', data); return this.createRequestBuilder()
.setData(data)
.build<ApiService>()
.post<ScheduleResponse[]>();
} }
public getByGroup(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) { public getByGroup(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
return this.get<ScheduleResponse[]>('GetByGroup/' + id.toString(), {isEven: isEven, disciplines: disciplines, professors: professors, lectureHalls: lectureHalls}); return this.createRequestBuilder()
.setEndpoint('GetByGroup/' + id.toString())
.setQueryParams({isEven: isEven, disciplines: disciplines, professors: professors, lectureHalls: lectureHalls})
.build<ApiService>()
.get<ScheduleResponse[]>();
} }
public getByProfessor(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, lectureHalls: Array<number> | null = null) { public getByProfessor(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
return this.get<ScheduleResponse[]>('GetByProfessor/' + id.toString(), {isEven: isEven, disciplines: disciplines, groups: groups, lectureHalls: lectureHalls}); return this.createRequestBuilder()
.setEndpoint('GetByProfessor/' + id.toString())
.setQueryParams({isEven: isEven, disciplines: disciplines, groups: groups, lectureHalls: lectureHalls})
.build<ApiService>()
.get<ScheduleResponse[]>();
} }
public getByLectureHall(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null) { public getByLectureHall(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null) {
return this.get<ScheduleResponse[]>('GetByLectureHall/' + id.toString(), {isEven: isEven, disciplines: disciplines, groups: groups, professors: professors}); return this.createRequestBuilder()
.setEndpoint('GetByLectureHall/' + id.toString())
.setQueryParams({isEven: isEven, disciplines: disciplines, groups: groups, professors: professors})
.build<ApiService>()
.get<ScheduleResponse[]>();
} }
public getByDiscipline(id : number, isEven: boolean | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) { public getByDiscipline(id : number, isEven: boolean | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
return this.get<ScheduleResponse[]>('GetByDiscipline/' + id.toString(), {isEven: isEven, groups: groups, professors: professors, lectureHalls: lectureHalls}); return this.createRequestBuilder()
.setEndpoint('GetByDiscipline/' + id.toString())
.setQueryParams({isEven: isEven, groups: groups, professors: professors, lectureHalls: lectureHalls})
.build<ApiService>()
.get<ScheduleResponse[]>();
} }
} }

View File

@ -10,51 +10,88 @@ import {DateOnly} from "@model/DateOnly";
@Injectable() @Injectable()
export default class SetupService extends ApiService { export default class SetupService extends ApiService {
protected basePath = 'Setup/'; public readonly basePath = 'Setup/';
public readonly version = AvailableVersion.v1; public readonly version = AvailableVersion.v1;
public checkToken(token: string) { public checkToken(token: string) {
return this.get<boolean>('CheckToken', {token: token}); return this.createRequestBuilder()
.setEndpoint('CheckToken')
.setQueryParams({token: token})
.build<ApiService>()
.get<boolean>();
} }
public setPsql(data: DatabaseRequest) { public setPsql(data: DatabaseRequest) {
return this.post<boolean>('SetPsql', data); return this.createRequestBuilder()
.setEndpoint('SetPsql')
.setData(data)
.build<ApiService>()
.post<boolean>();
} }
public setMysql(data: DatabaseRequest) { public setMysql(data: DatabaseRequest) {
return this.post<boolean>('SetMysql', data); return this.createRequestBuilder()
.setEndpoint('SetMysql')
.setData(data)
.build<ApiService>()
.post<boolean>();
} }
public setSqlite(path: string | null = null) { public setSqlite(path: string | null = null) {
return this.post<boolean>('SetSqlite', null, {path: path}); return this.createRequestBuilder()
.setEndpoint('SetSqlite')
.setQueryParams({path: path})
.build<ApiService>()
.get<boolean>();
} }
public setRedis(data: CacheRequest) { public setRedis(data: CacheRequest) {
return this.post<boolean>('SetRedis', data); return this.createRequestBuilder()
.setEndpoint('SetRedis')
.setData(data)
.build<ApiService>()
.post<boolean>();
} }
public setMemcached() { public setMemcached() {
return this.post<boolean>('SetMemcached', null); return this.post<boolean>('SetMemcached');
} }
public createAdmin(data: CreateUserRequest) { public createAdmin(data: CreateUserRequest) {
return this.post<boolean>('CreateAdmin', data); return this.createRequestBuilder()
.setEndpoint('CreateAdmin')
.setData(data)
.build<ApiService>()
.post<boolean>();
} }
public setLogging(data: LoggingRequest | null = null) { public setLogging(data: LoggingRequest | null = null) {
return this.post<boolean>('SetLogging', data); return this.createRequestBuilder()
.setEndpoint('SetLogging')
.setData(data)
.build<ApiService>()
.post<boolean>();
} }
public setEmail(data: EmailRequest | null = null) { public setEmail(data: EmailRequest | null = null) {
return this.post<boolean>('SetEmail', data); return this.createRequestBuilder()
.setEndpoint('SetEmail')
.setData(data)
.build<ApiService>()
.post<boolean>();
} }
public setSchedule(data: ScheduleConfigurationRequest) { public setSchedule(data: ScheduleConfigurationRequest) {
data.startTerm = new DateOnly(data.startTerm).toString(); data.startTerm = new DateOnly(data.startTerm).toString();
return this.post<boolean>('SetSchedule', data);
return this.createRequestBuilder()
.setEndpoint('SetSchedule')
.setData(data)
.build<ApiService>()
.post<boolean>();
} }
public submit() { public submit() {
return this.post<boolean>('Submit', null); return this.post<boolean>('Submit');
} }
} }