Refactor parameters in httpClient.ts

- it's convention for first param to be url
This commit is contained in:
Mattias Granlund 2024-04-11 16:04:01 +02:00
parent 7aa30724e7
commit 92b12ebad7
5 changed files with 43 additions and 69 deletions

View File

@ -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,

View File

@ -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<string, string | undefined>;
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<T>(params: {
path: string;
method: RequestMethod;
token?: string;
body?: FormData | object;
headers?: Record<string, string | undefined>;
}): Promise<T> {
private async request<T>(
path: string,
opts: RequestOptions & { method: RequestMethod }
): Promise<T> {
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<T>(params: { path: string; token?: string; headers?: Record<string, string | undefined> }) {
return this.request<T>({ ...params, method: 'GET' });
async get<T>(path: string, opts?: Omit<RequestOptions, 'body'>) {
return await this.request<T>(path, { ...opts, method: 'GET' });
}
post<T>(params: {
path: string;
token?: string;
body?: FormData | object;
headers?: Record<string, string | undefined>;
}) {
return this.request<T>({ ...params, method: 'POST' });
async post<T>(path: string, opts?: RequestOptions) {
return await this.request<T>(path, { ...opts, method: 'POST' });
}
put<T>(params: {
path: string;
token?: string;
body?: FormData | object;
headers?: Record<string, string | undefined>;
}) {
return this.request<T>({ ...params, method: 'PUT' });
async put<T>(path: string, opts?: RequestOptions) {
return this.request<T>(path, { ...opts, method: 'PUT' });
}
patch<T>(params: {
path: string;
token?: string;
body?: FormData | object;
headers?: Record<string, string | undefined>;
}) {
return this.request<T>({ ...params, method: 'PATCH' });
async patch<T>(path: string, opts?: RequestOptions) {
return this.request<T>(path, { ...opts, method: 'PATCH' });
}
delete<T>(params: {
path: string;
token?: string;
body?: FormData | object;
headers?: Record<string, string | undefined>;
}) {
return this.request<T>({ ...params, method: 'DELETE' });
async delete<T>(path: string, opts?: RequestOptions) {
return await this.request<T>(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);
}

View File

@ -134,8 +134,7 @@ export class ProjectService {
uid?: string;
}
): Promise<CloudProject> {
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<CloudProject> {
return this.httpClient.put({
path: `projects/${repositoryId}.json`,
return this.httpClient.put(`projects/${repositoryId}.json`, {
body: params,
token
});
}
getCloudProject(token: string, repositoryId: string): Promise<CloudProject> {
return this.httpClient.get({
path: `projects/${repositoryId}.json`,
return this.httpClient.get(`projects/${repositoryId}.json`, {
token
});
}

View File

@ -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

View File

@ -81,7 +81,7 @@ export class UserService {
}
async createLoginToken(): Promise<LoginToken> {
const token = await this.httpClient.post<LoginToken>({ path: 'login/token.json' });
const token = await this.httpClient.post<LoginToken>('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<User> {
return this.httpClient.get({ path: `login/user/${token}.json` });
return this.httpClient.get(`login/user/${token}.json`);
}
getUser(token: string): Promise<User> {
return this.httpClient.get({ path: 'user.json', token });
return this.httpClient.get('user.json', { token });
}
updateUser(token: string, params: { name?: string; picture?: File }): Promise<any> {
@ -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