ffffng/frontend/src/utils/Api.ts
2022-07-07 10:59:41 +02:00

90 lines
2.4 KiB
TypeScript

import {toIsArray, type TypeGuard} from "@/types";
import type {Headers} from "request";
import {parseInteger} from "@/utils/Numbers";
interface PagedListResult<T> {
entries: T[];
total: number;
}
interface Response<T> {
result: T;
headers: Headers;
}
class Api {
private baseURL: string = import.meta.env.BASE_URL;
private apiPrefix = "api/";
constructor(apiPrefix?: string) {
if (apiPrefix) {
this.apiPrefix = apiPrefix;
}
}
private toURL(path: string, queryParams?: object): string {
let queryString = "";
if (queryParams) {
const queryStrings: string[] = [];
for (const [key, value] of Object.entries(queryParams)) {
queryStrings.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
}
if (queryStrings.length > 0) {
queryString = `?${queryStrings.join("&")}`;
}
}
return this.baseURL + this.apiPrefix + path + queryString;
}
private async doGet<T>(path: string, isT: TypeGuard<T>, queryParams?: object): Promise<Response<T>> {
const url = this.toURL(path, queryParams);
const result = await fetch(url);
const json = await result.json();
if (!isT(json)) {
console.log(json);
throw new Error(`API get result has wrong type. ${url} => ${json}`);
}
return {
result: json,
headers: result.headers,
};
}
async get<T>(path: string, isT: TypeGuard<T>): Promise<T> {
const response = await this.doGet(path, isT);
return response.result;
}
async getPagedList<T>(
path: string,
isT: TypeGuard<T>,
page: number,
itemsPerPage: number,
filter?: object,
): Promise<PagedListResult<T>> {
const response = await this.doGet(path, toIsArray(isT), {
_page: page,
_perPage: itemsPerPage,
...filter,
});
const totalStr = response.headers.get("x-total-count");
const total = parseInteger(totalStr, 10);
return {
entries: response.result,
total,
}
}
}
export const api = new Api();
class InternalApi extends Api {
constructor() {
super("internal/api/");
}
}
export const internalApi = new InternalApi();