Skip to content

Commit 11c9381

Browse files
httpclient changes
1 parent 4c05311 commit 11c9381

File tree

1 file changed

+122
-38
lines changed

1 file changed

+122
-38
lines changed
Lines changed: 122 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,152 @@
1+
import { ApiError } from "../../types/apiError";
2+
13
export const httpClient = {
4+
fetch,
25
get,
36
post,
47
put,
58
delete: _delete,
69
download,
710
patch,
811
upload,
12+
fetchRaw,
913
};
1014

11-
async function get<T>(path: string): Promise<T> {
12-
const response = await fetch(path, { method: "GET" });
13-
return response.json();
15+
export async function fetch<T>(endpoint: RequestInfo, init: RequestInit & { notifyOnError?: boolean } = {}): Promise<T> {
16+
const { notifyOnError, ...config } = init;
17+
18+
try {
19+
// Directly use window.fetch without authFetch
20+
const response = await window.fetch(endpoint, config);
21+
22+
if (response.ok) {
23+
// First, clone the response to avoid consuming the body multiple times
24+
const clonedResponse = response.clone();
25+
try {
26+
return await clonedResponse.json();
27+
} catch (jsonError) {
28+
// If JSON parsing fails, return empty object
29+
console.warn('Failed to parse JSON response:', jsonError);
30+
return {} as T;
31+
}
32+
} else {
33+
// Clone the response before reading text to avoid consumption issues
34+
const clonedResponse = response.clone();
35+
let errorMessage = response.status.toString();
36+
37+
try {
38+
errorMessage = await clonedResponse.text() || errorMessage;
39+
} catch (textError) {
40+
console.warn('Failed to read error response text:', textError);
41+
}
42+
43+
console.error(`HTTP ${response.status}: ${errorMessage}`, response);
44+
if (notifyOnError || notifyOnError === undefined) notifyError(errorMessage);
45+
return Promise.reject(new Error(errorMessage));
46+
}
47+
} catch (e: unknown) {
48+
if (e instanceof Error) {
49+
console.error(e.message);
50+
if (notifyOnError || notifyOnError === undefined) notifyError(e.message);
51+
return Promise.reject(e);
52+
} else {
53+
console.error(e || "Unknown error");
54+
if (notifyOnError || notifyOnError === undefined) notifyError(String(e));
55+
return Promise.reject(new Error(String(e)));
56+
}
57+
}
1458
}
1559

16-
async function post<T, U>(path: string, body?: T): Promise<U> {
17-
const response = await fetch(path, {
18-
method: "POST",
19-
headers: { "Content-Type": "application/json" },
20-
body: body ? JSON.stringify(body) : undefined
21-
});
22-
return response.json();
60+
export async function fetchRaw(endpoint: RequestInfo, init: RequestInit & { notifyOnError?: boolean } = {}): Promise<Response> {
61+
const { notifyOnError, ...config } = init;
62+
63+
try {
64+
// Directly use window.fetch without authFetch
65+
return await window.fetch(endpoint, config);
66+
} catch (e: unknown) {
67+
if (e instanceof Error) {
68+
console.error(e.message);
69+
if (notifyOnError || notifyOnError === undefined) notifyError(e.message);
70+
return Promise.reject(e);
71+
} else {
72+
console.error(e || "Unknown error");
73+
if (notifyOnError || notifyOnError === undefined) notifyError(String(e));
74+
return Promise.reject(new Error(String(e)));
75+
}
76+
}
77+
}
78+
79+
// Other methods remain unchanged...
80+
async function get<T>(path: string, config?: RequestInit & { notifyOnError?: boolean }): Promise<T> {
81+
const init = { method: "GET", ...config };
82+
return fetch<T>(path, init);
83+
}
84+
85+
async function post<T, U>(path: string, body?: T, config?: RequestInit & { notifyOnError?: boolean }): Promise<U> {
86+
const defaultHeaders = {
87+
'Content-Type': 'application/json',
88+
};
89+
90+
const init = {
91+
method: "POST",
92+
body: body ? JSON.stringify(body) : undefined,
93+
headers: {
94+
...defaultHeaders,
95+
...(config?.headers || {})
96+
},
97+
...config
98+
};
99+
return fetch<U>(path, init);
23100
}
24101

25-
async function put<T, U>(path: string, body: T): Promise<U> {
26-
const response = await fetch(path, {
27-
method: "PUT",
28-
headers: { "Content-Type": "application/json" },
29-
body: JSON.stringify(body)
30-
});
31-
return response.json();
102+
async function put<T, U>(path: string, body?: T, config?: RequestInit & { notifyOnError?: boolean }): Promise<U> {
103+
const init = { method: "PUT", body: JSON.stringify(body), ...config };
104+
return fetch<U>(path, init);
32105
}
33106

34-
async function _delete<T>(path: string): Promise<T> {
35-
const response = await fetch(path, { method: "DELETE" });
36-
return response.json();
107+
async function _delete<T>(path: string, config?: RequestInit & { notifyOnError?: boolean }): Promise<T> {
108+
const init = { method: "DELETE", ...config };
109+
return fetch<T>(path, init);
37110
}
38111

39-
async function download(path: string, fileName: string): Promise<void> {
40-
const response = await fetch(path);
112+
async function download(path: string, fileName: string, config?: RequestInit & { notifyOnError?: boolean }): Promise<void> {
113+
const init = { method: "GET", ...config };
114+
const response = await fetchRaw(path, init);
41115
const blob = await response.blob();
42-
43-
const url = window.URL.createObjectURL(blob);
116+
117+
const url = window.URL.createObjectURL(new Blob([blob]));
44118
const link = document.createElement("a");
45119
link.href = url;
46120
link.setAttribute("download", fileName);
47-
121+
48122
document.body.appendChild(link);
49123
link.click();
50124
link.parentNode?.removeChild(link);
51125
}
52126

53-
async function patch<T, U>(path: string, body: T): Promise<U> {
54-
const response = await fetch(path, {
55-
method: "PATCH",
56-
headers: { "Content-Type": "application/json" },
57-
body: JSON.stringify(body)
58-
});
59-
return response.json();
127+
async function patch<T, U>(path: string, body: T, config?: RequestInit & { notifyOnError?: boolean }): Promise<U> {
128+
const init = { method: "PATCH", body: JSON.stringify(body), ...config };
129+
return fetch<U>(path, init);
130+
}
131+
132+
export async function upload<T>(path: string, formData: FormData, config?: RequestInit & { notifyOnError?: boolean }): Promise<T> {
133+
const init = { method: "POST", body: formData, ...config };
134+
return fetch<T>(path, init);
135+
}
136+
137+
function notifyError(_message: string) {
138+
// TO DO: Implement error notification logic
60139
}
61140

62-
async function upload<T>(path: string, formData: FormData): Promise<T> {
63-
const response = await fetch(path, {
64-
method: "POST",
65-
body: formData
66-
});
67-
return response.json();
141+
export function parseHttpException(ex: any, t: (key: string) => string): string[] {
142+
if (ex instanceof Error && ex.message.startsWith("{")) {
143+
const error = JSON.parse(ex.message);
144+
if ("errors" in error) {
145+
const messages = Object.entries(error.errors).map((field) => error.errors[field[0]].join(", "));
146+
return messages;
147+
}
148+
} else if (ex instanceof Error && ex.message === "403") {
149+
return [t("common.forbidden")];
150+
}
151+
return [t("common.error")];
68152
}

0 commit comments

Comments
 (0)