sp3-verify-1770325794/packages/api-client/src/client.ts
jordan 286d313d81
All checks were successful
ci/woodpecker/manual/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
Initialize project from skeleton template
2026-02-05 21:09:55 +00:00

96 lines
2.4 KiB
TypeScript

/**
* API Client Configuration
*/
export interface ClientConfig {
baseUrl: string;
apiKey?: string;
bearerToken?: string;
headers?: Record<string, string>;
onError?: (error: Error) => void;
}
/**
* Create a typed API client
*
* @example
* const client = createClient({
* baseUrl: 'https://api.example.com',
* apiKey: 'your-api-key',
* });
*
* const users = await client.get('/users');
* const newUser = await client.post('/users', { name: 'John' });
*/
export function createClient(config: ClientConfig) {
const { baseUrl, apiKey, bearerToken, headers = {}, onError } = config;
async function request<T>(
method: string,
path: string,
options: {
body?: unknown;
params?: Record<string, string | number | boolean | undefined>;
headers?: Record<string, string>;
} = {}
): Promise<T> {
const url = new URL(path, baseUrl);
// Add query params
if (options.params) {
for (const [key, value] of Object.entries(options.params)) {
if (value !== undefined) {
url.searchParams.set(key, String(value));
}
}
}
// Build headers
const requestHeaders: Record<string, string> = {
'Content-Type': 'application/json',
...headers,
...options.headers,
};
if (apiKey) {
requestHeaders['X-API-Key'] = apiKey;
}
if (bearerToken) {
requestHeaders['Authorization'] = `Bearer ${bearerToken}`;
}
const response = await fetch(url.toString(), {
method,
headers: requestHeaders,
body: options.body ? JSON.stringify(options.body) : undefined,
});
if (!response.ok) {
const error = new Error(`API error: ${response.status}`);
if (onError) {
onError(error);
}
throw error;
}
// Handle no-content responses
if (response.status === 204) {
return undefined as T;
}
return response.json();
}
return {
get: <T>(path: string, params?: Record<string, string | number | boolean | undefined>) =>
request<T>('GET', path, { params }),
post: <T>(path: string, body?: unknown) =>
request<T>('POST', path, { body }),
put: <T>(path: string, body?: unknown) =>
request<T>('PUT', path, { body }),
patch: <T>(path: string, body?: unknown) =>
request<T>('PATCH', path, { body }),
delete: <T>(path: string) =>
request<T>('DELETE', path),
};
}