From 982b88eb1c2af9029cebe89a2e2debc0586849ad Mon Sep 17 00:00:00 2001
From: Roland Bernard <rolbernard@unibz.it>
Date: Fri, 7 May 2021 23:51:12 +0200
Subject: [PATCH] Reduced code duplication

---
 client/src/adapters/project.ts | 138 ++++-------------
 client/src/adapters/task.ts    | 131 +++++-----------
 client/src/adapters/team.ts    | 266 +++++++--------------------------
 client/src/adapters/user.ts    |  88 +++--------
 client/src/adapters/util.ts    |  41 +++++
 5 files changed, 184 insertions(+), 480 deletions(-)
 create mode 100644 client/src/adapters/util.ts

diff --git a/client/src/adapters/project.ts b/client/src/adapters/project.ts
index a325024..38c62e5 100644
--- a/client/src/adapters/project.ts
+++ b/client/src/adapters/project.ts
@@ -1,7 +1,5 @@
 
-import { apiRoot } from 'config';
-
-import { getAuthHeader } from './auth';
+import { executeApiGet, executeApiPost, executeApiPut } from './util';
 import { Task } from './task';
 import { User } from './user';
 import { Work } from './work';
@@ -22,84 +20,38 @@ export interface AssignedUser extends User {
 
 export type ReducedProject = Exclude<Project, 'teams'>;
 
-export async function getProjects(): Promise<ReducedProject[]> {
-    try {
-        const response = await fetch(`${apiRoot}/project/`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).projects.map((project: any) => ({
-                ...project,
-                deadline: project.deadline ? new Date(project.deadline) : undefined,
-            }));
-        } else {
-            throw new Error("Failed to get projects");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getProjects(): Promise<ReducedProject[]> {
+    return executeApiGet(`project`, ({ projects }) => projects.map((project: any) => ({
+        ...project,
+        deadline: project.deadline ? new Date(project.deadline) : undefined,
+    })), "Failed to get projects");
 }
 
-export async function getProject(uuid: string): Promise<Project> {
-    try {
-        const response = await fetch(`${apiRoot}/project/${uuid}`, { headers: getAuthHeader() });
-        if (response.ok) {
-            const project = (await response.json()).project;
-            return {
-                ...project,
-                deadline: project.deadline ? new Date(project.deadline) : undefined,
-            }
-        } else {
-            throw new Error("Failed to get project");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getProject(uuid: string): Promise<Project> {
+    return executeApiGet(`project/${uuid}`, ({ project }) => ({
+        ...project,
+        deadline: project.deadline ? new Date(project.deadline) : undefined,
+    }), "Failed to get project");
 }
 
-export async function getProjectTasks(uuid: string): Promise<Task[]> {
-    try {
-        const response = await fetch(`${apiRoot}/project/${uuid}/tasks`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).tasks.map((task: any) => ({
-                ...task,
-                edited: new Date(task.edited),
-                created: new Date(task.created),
-            }));
-        } else {
-            throw new Error("Failed to get project tasks");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getProjectTasks(uuid: string): Promise<Task[]> {
+    return executeApiGet(`project/${uuid}/tasks`, ({ tasks }) => tasks.map((task: any) => ({
+        ...task,
+        edited: new Date(task.edited),
+        created: new Date(task.created),
+    })), "Failed to get project tasks");
 }
 
-export async function getProjectAssignees(uuid: string): Promise<AssignedUser[]> {
-    try {
-        const response = await fetch(`${apiRoot}/project/${uuid}/assigned`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).assigned;
-        } else {
-            throw new Error("Failed to get project assignees");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getProjectAssignees(uuid: string): Promise<AssignedUser[]> {
+    return executeApiGet(`project/${uuid}/assigned`, ({ assigned }) => assigned, "Failed to get project assignees");
 }
 
-export async function getProjectWork(uuid: string): Promise<Work[]> {
-    try {
-        const response = await fetch(`${apiRoot}/project/${uuid}/work`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).work.map((work: any) => ({
-                ...work,
-                started: new Date(work.started),
-                finished: work.finished ? new Date(work.finished) : undefined,
-            }));
-        } else {
-            throw new Error("Failed to get project work");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getProjectWork(uuid: string): Promise<Work[]> {
+    return executeApiGet(`project/${uuid}/work`, ({ work }) => work.map((work: any) => ({
+        ...work,
+        started: new Date(work.started),
+        finished: work.finished ? new Date(work.finished) : undefined,
+    })), "Failed to get project work");
 }
 
 interface NewTeamData {
@@ -110,24 +62,8 @@ interface NewTeamData {
     deadline?: Date;
 }
 
-export async function createProject(project: NewTeamData): Promise<string> {
-    try {
-        const response = await fetch(`${apiRoot}/project/`, {
-            method: 'POST',
-            headers: {
-                ...getAuthHeader(),
-                'Content-Type': 'application/json',
-            },
-            body: JSON.stringify(project),
-        });
-        if (response.ok) {
-            return (await response.json()).id;
-        } else {
-            throw new Error("Failed to create project");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function createProject(project: NewTeamData): Promise<string> {
+    return executeApiPost(`project`, project, ({ id }) => id, "Failed to create project");
 }
 
 interface UpdateTeamData {
@@ -140,24 +76,8 @@ interface UpdateTeamData {
     deadline?: string;
 }
 
-export async function updateProject(uuid: string, project: UpdateTeamData) {
-    try {
-        const response = await fetch(`${apiRoot}/project/${uuid}`, {
-            method: 'PUT',
-            headers: {
-                ...getAuthHeader(),
-                'Content-Type': 'application/json',
-            },
-            body: JSON.stringify(project),
-        });
-        if (response.ok) {
-            return (await response.json()).id;
-        } else {
-            throw new Error("Failed to update project");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function updateProject(uuid: string, project: UpdateTeamData) {
+    return executeApiPut(`project/${uuid}`, project, () => {}, "Failed to update project");
 }
 
 
diff --git a/client/src/adapters/task.ts b/client/src/adapters/task.ts
index 51c55d0..bbf0d34 100644
--- a/client/src/adapters/task.ts
+++ b/client/src/adapters/task.ts
@@ -1,7 +1,5 @@
 
-import { apiRoot } from 'config';
-
-import { getAuthHeader } from './auth';
+import { executeApiGet } from './util';
 import { Comment } from './comment';
 import { Work } from './work';
 
@@ -31,106 +29,51 @@ export interface Task {
     edited: Date;
 }
 
-export async function getTasks(): Promise<Task[]> {
-    try {
-        const response = await fetch(`${apiRoot}/task`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).tasks.map((task: any) => ({
-                ...task,
-                edited: new Date(task.edited),
-                created: new Date(task.created),
-            }));
-        } else {
-            throw new Error("Failed to get tasks");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getTasks(): Promise<Task[]> {
+    return executeApiGet(`task`, ({ tasks }) => tasks.map((task: any) => ({
+        ...task,
+        edited: new Date(task.edited),
+        created: new Date(task.created),
+    })), "Failed to get tasks");
 }
 
-export async function getTasksWithStatus(status: 'open' | 'closed' | 'suspended'): Promise<Task[]> {
-    try {
-        const response = await fetch(`${apiRoot}/task/${status}`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).tasks.map((task: any) => ({
-                ...task,
-                edited: new Date(task.edited),
-                created: new Date(task.created),
-            }));
-        } else {
-            throw new Error("Failed to get tasks with status");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getTasksWithStatus(status: 'open' | 'closed' | 'suspended'): Promise<Task[]> {
+    return executeApiGet(`task/${status}`, ({ tasks }) => tasks.map((task: any) => ({
+        ...task,
+        edited: new Date(task.edited),
+        created: new Date(task.created),
+    })), "Failed to get tasks with status");
 }
 
-export async function getPossibleTasks(): Promise<Task[]> {
-    try {
-        const response = await fetch(`${apiRoot}/task/possible`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).tasks.map((task: any) => ({
-                ...task,
-                edited: new Date(task.edited),
-                created: new Date(task.created),
-            }));
-        } else {
-            throw new Error("Failed to get possible tasks");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getPossibleTasks(): Promise<Task[]> {
+    return executeApiGet(`task/possible`, ({ tasks }) => tasks.map((task: any) => ({
+        ...task,
+        edited: new Date(task.edited),
+        created: new Date(task.created),
+    })), "Failed to get possible tasks");
 }
 
-export async function getTask(uuid: string): Promise<Task> {
-    try {
-        const response = await fetch(`${apiRoot}/task/${uuid}`, { headers: getAuthHeader() });
-        if (response.ok) {
-            const task = (await response.json()).task;
-            return {
-                ...task,
-                edited: new Date(task.edited),
-                created: new Date(task.created),
-            };
-        } else {
-            throw new Error("Failed to get task");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getTask(uuid: string): Promise<Task> {
+    return executeApiGet(`task/${uuid}`, ({ task }) => ({
+        ...task,
+        edited: new Date(task.edited),
+        created: new Date(task.created),
+    }), "Failed to get task");
 }
 
-export async function getTaskComments(uuid: string): Promise<Comment[]> {
-    try {
-        const response = await fetch(`${apiRoot}/task/${uuid}/comments`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).comments.map((comment: any) => ({
-                ...comment,
-                edited: new Date(comment.edited),
-                created: new Date(comment.created),
-            }));
-        } else {
-            throw new Error("Failed to get task comments");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getTaskComments(uuid: string): Promise<Comment[]> {
+    return executeApiGet(`task/${uuid}/comments`, ({ comments }) => comments.map((comment: any) => ({
+        ...comment,
+        edited: new Date(comment.edited),
+        created: new Date(comment.created),
+    })), "Failed to get task comments");
 }
 
-export async function getTaskWork(uuid: string): Promise<Work[]> {
-    try {
-        const response = await fetch(`${apiRoot}/task/${uuid}/work`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).work.map((work: any) => ({
-                ...work,
-                started: new Date(work.started),
-                finished: work.finished ? new Date(work.finished) : undefined,
-            }));
-        } else {
-            throw new Error("Failed to get task work");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getTaskWork(uuid: string): Promise<Work[]> {
+    return executeApiGet(`task/${uuid}/work`, ({ work }) => work.map((work: any) => ({
+        ...work,
+        started: new Date(work.started),
+        finished: work.finished ? new Date(work.finished) : undefined,
+    })), "Failed to get task work");
 }
 
diff --git a/client/src/adapters/team.ts b/client/src/adapters/team.ts
index 271087c..6bf0efa 100644
--- a/client/src/adapters/team.ts
+++ b/client/src/adapters/team.ts
@@ -1,7 +1,5 @@
 
-import { apiRoot } from 'config';
-
-import { getAuthHeader } from './auth';
+import { executeApiDelete, executeApiGet, executeApiPost, executeApiPut } from './util';
 import { User } from './user';
 import { ReducedProject } from './project';
 import { Work } from './work';
@@ -21,210 +19,62 @@ export interface TeamMember extends User {
     role: TeamRole;
 }
 
-export async function getTeams(): Promise<Team[]> {
-    try {
-        const response = await fetch(`${apiRoot}/team/`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).teams;
-        } else {
-            throw new Error("Failed to get teams");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function getTeam(uuid: string): Promise<Team> {
-    try {
-        const response = await fetch(`${apiRoot}/team/${uuid}`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).team;
-        } else {
-            throw new Error("Failed to get team");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function getTeamMembers(uuid: string): Promise<TeamMember[]> {
-    try {
-        const response = await fetch(`${apiRoot}/team/${uuid}/members`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).members;
-        } else {
-            throw new Error("Failed to get team members");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function getTeamRoles(uuid: string): Promise<TeamRole[]> {
-    try {
-        const response = await fetch(`${apiRoot}/team/${uuid}/roles`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).roles;
-        } else {
-            throw new Error("Failed to get team roles");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function getTeamProjects(uuid: string): Promise<ReducedProject[]> {
-    try {
-        const response = await fetch(`${apiRoot}/team/${uuid}/projects`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).projects.map((project: any) => ({
-                ...project,
-                deadline: new Date(project.deadline),
-            }));
-        } else {
-            throw new Error("Failed to get team projects");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function getTeamWork(uuid: string): Promise<Work[]> {
-    try {
-        const response = await fetch(`${apiRoot}/team/${uuid}/work`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).work.map((work: any) => ({
-                ...work,
-                started: new Date(work.started),
-                finished: work.finished ? new Date(work.finished) : undefined,
-            }));
-        } else {
-            throw new Error("Failed to get team work");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function createTeam(name: string): Promise<string> {
-    try {
-        const response = await fetch(`${apiRoot}/team/`, {
-            method: 'POST',
-            headers: {
-                ...getAuthHeader(),
-                'Content-Type': 'application/json',
-            },
-            body: JSON.stringify({
-                name: name,
-            }),
-        });
-        if (response.ok) {
-            return (await response.json()).id;
-        } else {
-            throw new Error("Failed to create team");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function removeTeamMember(team: string, user: string) {
-    try {
-        const response = await fetch(`${apiRoot}/team/${team}/members/${user}`, {
-            method: 'DELETE',
-            headers: getAuthHeader(),
-        });
-        if (!response.ok) {
-            throw new Error("Failed to create team");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function createTeamRole(team: string, name: string): Promise<TeamRole> {
-    try {
-        const response = await fetch(`${apiRoot}/team/${team}/roles`, {
-            method: 'POST',
-            headers: {
-                ...getAuthHeader(),
-                'Content-Type': 'application/json',
-            },
-            body: JSON.stringify({
-                name: name,
-            }),
-        });
-        if (response.ok) {
-            return (await response.json()).role;
-        } else {
-            throw new Error("Failed to create team role");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function deleteTeamRole(team: string, role: string) {
-    try {
-        const response = await fetch(`${apiRoot}/team/${team}/roles/${role}`, {
-            method: 'DELETE',
-            headers: getAuthHeader(),
-        });
-        if (!response.ok) {
-            throw new Error("Failed to delete team role");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function addTeamMember(team: string, member: { user: string, role: string }) {
-    try {
-        const response = await fetch(`${apiRoot}/team/${team}/members`, {
-            method: 'POST',
-            headers: {
-                ...getAuthHeader(),
-                'Content-Type': 'application/json',
-            },
-            body: JSON.stringify(member),
-        });
-        if (!response.ok) {
-            throw new Error("Failed to add team member");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function updateTeamMember(team: string, member: { user: string, role: string }) {
-    try {
-        const response = await fetch(`${apiRoot}/team/${team}/members`, {
-            method: 'PUT',
-            headers: {
-                ...getAuthHeader(),
-                'Content-Type': 'application/json',
-            },
-            body: JSON.stringify(member),
-        });
-        if (!response.ok) {
-            throw new Error("Failed to update team member");
-        }
-    } catch (e) {
-        throw e;
-    }
-}
-
-export async function leaveTeam(team: string) {
-    try {
-        const response = await fetch(`${apiRoot}/team/${team}`, {
-            method: 'DELETE',
-            headers: getAuthHeader(),
-        });
-        if (!response.ok) {
-            throw new Error("Failed to leave team");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getTeams(): Promise<Team[]> {
+    return executeApiGet(`team`, ({ teams }) => teams, "Failed to get teams");
+}
+
+export function getTeam(uuid: string): Promise<Team> {
+    return executeApiGet(`team/${uuid}`, ({ team }) => team, "Failed to get team");
+}
+
+export function getTeamMembers(uuid: string): Promise<TeamMember[]> {
+    return executeApiGet(`team/${uuid}/members`, ({ members }) => members, "Failed to get team members");
+}
+
+export function getTeamRoles(uuid: string): Promise<TeamRole[]> {
+    return executeApiGet(`team/${uuid}/roles`, ({ roles }) => roles, "Failed to get team roles");
+}
+
+export function getTeamProjects(uuid: string): Promise<ReducedProject[]> {
+    return executeApiGet(`team/${uuid}/projects`, ({ projects }) => projects.map((project: any) => ({
+        ...project,
+        deadline: new Date(project.deadline),
+    })), "Failed to get team projects");
+}
+
+export function getTeamWork(uuid: string): Promise<Work[]> {
+    return executeApiGet(`team/${uuid}/work`, ({ work }) => work.map((work: any) => ({
+        ...work,
+        started: new Date(work.started),
+        finished: work.finished ? new Date(work.finished) : undefined,
+    })), "Failed to get team work");
+}
+
+export function createTeam(name: string): Promise<string> {
+    return executeApiPost(`team`, { name: name }, ({ id }) => id, "Failed to create team");
+}
+
+export function removeTeamMember(team: string, user: string) {
+    return executeApiDelete(`team/${team}/members/${user}`, () => {}, "Failed to remove team member");
+}
+
+export function createTeamRole(team: string, name: string): Promise<TeamRole> {
+    return executeApiPost(`team/${team}/roles`, { name: name }, ({ role }) => role, "Failed to create team role");
+}
+
+export function deleteTeamRole(team: string, role: string) {
+    return executeApiDelete(`team/${team}/roles/${role}`, () => {}, "Failed to delete team role");
+}
+
+export function addTeamMember(team: string, member: { user: string, role: string }) {
+    return executeApiPost(`team/${team}/members`, member, () => {}, "Failed to add team member");
+}
+
+export function updateTeamMember(team: string, member: { user: string, role: string }) {
+    return executeApiPut(`team/${team}/members`, member, () => {}, "Failed to update team member");
+}
+
+export function leaveTeam(team: string) {
+    return executeApiDelete(`team/${team}`, () => {}, "Failed to leave team");
 }
 
diff --git a/client/src/adapters/user.ts b/client/src/adapters/user.ts
index 7f6ccf6..1eaf9f0 100644
--- a/client/src/adapters/user.ts
+++ b/client/src/adapters/user.ts
@@ -1,7 +1,7 @@
 
 import { apiRoot } from 'config';
 
-import { getAuthHeader } from './auth';
+import { executeApiGet, executeApiPut } from './util';
 import { Task } from './task';
 import { Work } from './work';
 
@@ -22,82 +22,32 @@ export async function exists(username: string) {
     }
 }
 
-export async function getCurrentUser(): Promise<User> {
-    try {
-        const response = await fetch(`${apiRoot}/user/`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).user;
-        } else {
-            throw new Error("Failed to get user");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getCurrentUser(): Promise<User> {
+    return executeApiGet(`user`, ({ user }) => user, "Failed to get user");
 }
 
-export async function getUserTasks(): Promise<Array<Task>> {
-    try {
-        const response = await fetch(`${apiRoot}/user/tasks`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).tasks.map((task: any) => ({
-                ...task,
-                edited: new Date(task.edited),
-                created: new Date(task.created),
-            }));
-        } else {
-            throw new Error("Failed to get user tasks");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getUserTasks(): Promise<Array<Task>> {
+    return executeApiGet(`user/tasks`, ({ tasks }) => tasks.map((task: any) => ({
+        ...task,
+        edited: new Date(task.edited),
+        created: new Date(task.created),
+    })), "Failed to get user tasks");
 }
 
-export async function getUserWork(): Promise<Work> {
-    try {
-        const response = await fetch(`${apiRoot}/user/work`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).work.map((work: any) => ({
-                ...work,
-                started: new Date(work.started),
-                finished: work.finished ? new Date(work.finished) : undefined,
-            }));
-        } else {
-            throw new Error("Failed to get user work");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getUserWork(): Promise<Work> {
+    return executeApiGet(`user/work`, ({ work }) => work.map((work: any) => ({
+        ...work,
+        started: new Date(work.started),
+        finished: work.finished ? new Date(work.finished) : undefined,
+    })), "Failed to get user work");
 }
 
-export async function getUser(uuid: string): Promise<User> {
-    try {
-        const response = await fetch(`${apiRoot}/user/${uuid}`, { headers: getAuthHeader() });
-        if (response.ok) {
-            return (await response.json()).user;
-        } else {
-            throw new Error("Failed to get user");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function getUser(uuid: string): Promise<User> {
+    return executeApiGet(`user/${uuid}`, ({ user }) => user, "Failed to get user");
 }
 
-export async function updateUser(user: { realname?: string, email?: string }) {
-    try {
-        const response = await fetch(`${apiRoot}/user/`, {
-            method: 'PUT',
-            headers: {
-                ...getAuthHeader(),
-                'Content-Type': 'application/json',
-            },
-            body: JSON.stringify(user),
-        });
-        if (!response.ok) {
-            throw new Error("Failed to update user");
-        }
-    } catch (e) {
-        throw e;
-    }
+export function updateUser(user: { realname?: string, email?: string }) {
+    return executeApiPut(`user`, user, () => {}, "Failed to update user");
 }
 
 export function getUserImageUri(uuid: string): string {
diff --git a/client/src/adapters/util.ts b/client/src/adapters/util.ts
new file mode 100644
index 0000000..08a6b61
--- /dev/null
+++ b/client/src/adapters/util.ts
@@ -0,0 +1,41 @@
+
+import { apiRoot } from 'config';
+
+import { getAuthHeader } from './auth';
+
+async function executeApiRequest<T>(path: string, method: string, body: any, onSuccess: (data: any) => T, errorMessage: string): Promise<T> {
+    try {
+        const response = await fetch(`${apiRoot}/${path}`, {
+            method: method,
+            headers: {
+                ...getAuthHeader(),
+                ...(body ? { 'Content-Type': 'application/json' } : { }),
+            },
+            body: body ? JSON.stringify(body) : undefined,
+        });
+        if (response.ok) {
+            return onSuccess(await response.json());
+        } else {
+            throw new Error(errorMessage);
+        }
+    } catch (e) {
+        throw new Error(errorMessage);
+    }
+}
+
+export function executeApiGet<T>(path: string, onSuccess: (data: any) => T, errorMessage: string): Promise<T> {
+    return executeApiRequest(path, 'GET', undefined, onSuccess, errorMessage);
+}
+
+export function executeApiDelete<T>(path: string, onSuccess: (data: any) => T, errorMessage: string): Promise<T> {
+    return executeApiRequest(path, 'DELETE', undefined, onSuccess, errorMessage);
+}
+
+export function executeApiPost<T>(path: string, body: any, onSuccess: (data: any) => T, errorMessage: string): Promise<T> {
+    return executeApiRequest(path, 'POST', body, onSuccess, errorMessage);
+}
+
+export function executeApiPut<T>(path: string, body: any, onSuccess: (data: any) => T, errorMessage: string): Promise<T> {
+    return executeApiRequest(path, 'PUT', body, onSuccess, errorMessage);
+}
+
-- 
GitLab