diff --git a/app/src/lib/ai/butlerClient.ts b/app/src/lib/ai/butlerClient.ts index befcb9ccb..7fd0f3f5e 100644 --- a/app/src/lib/ai/butlerClient.ts +++ b/app/src/lib/ai/butlerClient.ts @@ -11,8 +11,7 @@ export class ButlerAIClient implements AIClient { async evaluate(prompt: string) { const messages: PromptMessage[] = [{ role: MessageRole.User, content: prompt }]; - const response = await this.cloud.post<{ message: string }>({ - path: 'evaluate_prompt/predict.json', + const response = await this.cloud.post<{ message: string }>('evaluate_prompt/predict.json', { body: { messages, max_tokens: 400, diff --git a/app/src/lib/backend/httpClient.ts b/app/src/lib/backend/httpClient.ts index 0484a9bbb..3d45f833e 100644 --- a/app/src/lib/backend/httpClient.ts +++ b/app/src/lib/backend/httpClient.ts @@ -7,32 +7,23 @@ export const DEFAULT_HEADERS = { export type RequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; -function getApiUrl(path: string) { - return new URL(path, API_URL); -} +type RequestOptions = { + headers?: Record; + body?: FormData | object; + token?: string; +}; export class HttpClient { constructor(public fetch = window.fetch) {} - private formatBody(body?: FormData | object) { - if (body instanceof FormData) { - return body; - } else if (body) { - return JSON.stringify(body); - } - } - - async request(params: { - path: string; - method: RequestMethod; - token?: string; - body?: FormData | object; - headers?: Record; - }): Promise { + private async request( + path: string, + opts: RequestOptions & { method: RequestMethod } + ): Promise { const butlerHeaders = new Headers(DEFAULT_HEADERS); - if (params.headers) { - Object.entries(params.headers).forEach(([key, value]) => { + if (opts.headers) { + Object.entries(opts.headers).forEach(([key, value]) => { if (value) { butlerHeaders.set(key, value); } else { @@ -41,58 +32,42 @@ export class HttpClient { }); } - if (params.token) butlerHeaders.set('X-Auth-Token', params.token); + if (opts.token) butlerHeaders.set('X-Auth-Token', opts.token); - const response = await this.fetch(getApiUrl(params.path), { - method: params.method || 'GET', + const response = await this.fetch(getApiUrl(path), { + method: opts.method, headers: butlerHeaders, - body: this.formatBody(params.body) + body: formatBody(opts.body) }); return parseResponseJSON(response); } - get(params: { path: string; token?: string; headers?: Record }) { - return this.request({ ...params, method: 'GET' }); + async get(path: string, opts?: Omit) { + return await this.request(path, { ...opts, method: 'GET' }); } - post(params: { - path: string; - token?: string; - body?: FormData | object; - headers?: Record; - }) { - return this.request({ ...params, method: 'POST' }); + async post(path: string, opts?: RequestOptions) { + return await this.request(path, { ...opts, method: 'POST' }); } - put(params: { - path: string; - token?: string; - body?: FormData | object; - headers?: Record; - }) { - return this.request({ ...params, method: 'PUT' }); + async put(path: string, opts?: RequestOptions) { + return this.request(path, { ...opts, method: 'PUT' }); } - patch(params: { - path: string; - token?: string; - body?: FormData | object; - headers?: Record; - }) { - return this.request({ ...params, method: 'PATCH' }); + async patch(path: string, opts?: RequestOptions) { + return this.request(path, { ...opts, method: 'PATCH' }); } - delete(params: { - path: string; - token?: string; - body?: FormData | object; - headers?: Record; - }) { - return this.request({ ...params, method: 'DELETE' }); + async delete(path: string, opts?: RequestOptions) { + return await this.request(path, { ...opts, method: 'DELETE' }); } } +function getApiUrl(path: string) { + return new URL(path, API_URL); +} + async function parseResponseJSON(response: Response) { if (response.status === 204 || response.status === 205) { return null; @@ -102,3 +77,8 @@ async function parseResponseJSON(response: Response) { return await response.json(); } } + +function formatBody(body?: FormData | object) { + if (!body) return; + return body instanceof FormData ? body : JSON.stringify(body); +} diff --git a/app/src/lib/backend/projects.ts b/app/src/lib/backend/projects.ts index 5424d94db..576f3a401 100644 --- a/app/src/lib/backend/projects.ts +++ b/app/src/lib/backend/projects.ts @@ -134,8 +134,7 @@ export class ProjectService { uid?: string; } ): Promise { - return this.httpClient.post({ - path: 'projects.json', + return this.httpClient.post('projects.json', { body: params, token }); @@ -149,16 +148,14 @@ export class ProjectService { description?: string; } ): Promise { - return this.httpClient.put({ - path: `projects/${repositoryId}.json`, + return this.httpClient.put(`projects/${repositoryId}.json`, { body: params, token }); } getCloudProject(token: string, repositoryId: string): Promise { - return this.httpClient.get({ - path: `projects/${repositoryId}.json`, + return this.httpClient.get(`projects/${repositoryId}.json`, { token }); } diff --git a/app/src/lib/components/ShareIssueModal.svelte b/app/src/lib/components/ShareIssueModal.svelte index 787a52d66..fbef0cc4f 100644 --- a/app/src/lib/components/ShareIssueModal.svelte +++ b/app/src/lib/components/ShareIssueModal.svelte @@ -125,8 +125,7 @@ if (params.data) formData.append('data', params.data); // Content Type must be unset for the right form-data border to be set automatically - return httpClient.put({ - path: 'feedback', + return httpClient.put('feedback', { body: formData, headers: { 'Content-Type': undefined }, token diff --git a/app/src/lib/stores/user.ts b/app/src/lib/stores/user.ts index 792296942..8bb49d474 100644 --- a/app/src/lib/stores/user.ts +++ b/app/src/lib/stores/user.ts @@ -81,7 +81,7 @@ export class UserService { } async createLoginToken(): Promise { - const token = await this.httpClient.post({ path: 'login/token.json' }); + const token = await this.httpClient.post('login/token.json'); const url = new URL(token.url); url.host = API_URL.host; return { @@ -104,11 +104,11 @@ export class UserService { // TODO: Remove token from URL, we don't want that leaking into logs. getLoginUser(token: string): Promise { - return this.httpClient.get({ path: `login/user/${token}.json` }); + return this.httpClient.get(`login/user/${token}.json`); } getUser(token: string): Promise { - return this.httpClient.get({ path: 'user.json', token }); + return this.httpClient.get('user.json', { token }); } updateUser(token: string, params: { name?: string; picture?: File }): Promise { @@ -117,8 +117,7 @@ export class UserService { if (params.picture) formData.append('avatar', params.picture); // Content Type must be unset for the right form-data border to be set automatically - return this.httpClient.put({ - path: 'user.json', + return this.httpClient.put('user.json', { body: formData, headers: { 'Content-Type': undefined }, token