diff options
| author | 2024-08-19 17:05:24 +0100 | |
|---|---|---|
| committer | 2024-08-19 17:05:24 +0100 | |
| commit | df35284987d7b9e04e76bad44bc529f45febf38f (patch) | |
| tree | c8e1cd836f1e721ac97070f0fc98f6f5d605d6ad /thallium-frontend/src | |
| parent | Build in API base URL (diff) | |
Add API client
Diffstat (limited to 'thallium-frontend/src')
| -rw-r--r-- | thallium-frontend/src/api/client.ts | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/thallium-frontend/src/api/client.ts b/thallium-frontend/src/api/client.ts new file mode 100644 index 0000000..9e64af5 --- /dev/null +++ b/thallium-frontend/src/api/client.ts @@ -0,0 +1,53 @@ +/* +TODO: Someday these methods should try pick out authentication from the Redux stores. +*/ + +const BASE_URL = THALLIUM_BASE_URL; + +interface APIErrorResponse { + detail?: string; +} + +export type APIRequestBody = Record<string, unknown>; + +type APIResponseBody = Record<string, unknown>; + +export class APIError extends Error { + constructor(message: string, public status: number, public data: APIErrorResponse | null) { + super(message); + } +} + +const request = async (url: string, options: RequestInit = {}): Promise<APIResponseBody> => { + const response = await fetch(`${BASE_URL}${url}`, options); + if (!response.ok) { + let maybeData: APIErrorResponse | null; + + try { + maybeData = await response.json() as APIErrorResponse; + } catch (e) { + maybeData = null; + } + + throw new APIError(response.statusText, response.status, maybeData); + } + return response.json() as Promise<APIResponseBody>; +}; + +export const get = async (url: string, options: RequestInit = {}): Promise<APIResponseBody> => { + return request(url, { + ...options, + method: "GET", + }); +}; + +export const post = async (url: string, data: APIRequestBody, options: RequestInit = {}): Promise<APIResponseBody> => { + return request(url, { + ...options, + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }); +}; |