Use createClient to create a reusable HTTP client instance.
import { createClient } from '@dfsync/client';
const client = createClient({
baseURL: 'https://api.example.com',
});const client = createClient({
baseUrl: 'https://api.example.com',
timeout: 5000,
});const client = createClient({
baseUrl: 'https://api.example.com',
headers: {
'x-service-name': 'billing-worker',
},
});const client = createClient({
baseUrl: 'https://api.example.com',
fetch: globalThis.fetch,
});type ClientConfig = {
baseUrl: string;
timeout?: number;
headers?: Record<string, string>;
fetch?: typeof globalThis.fetch;
auth?: {
// see Auth section
};
hooks?: {
// see Hooks section
};
};The client provides a predictable set of methods:
client.get(path, options?)
client.delete(path, options?)
client.post(path, body?, options?)
client.put(path, body?, options?)
client.patch(path, body?, options?)
client.request(config)
getanddeletedo not accept bodypost,put, andpatchaccept request body as the second argumentoptionsis used for headers, query, timeout, retry, and other settings
type User = {
id: string;
name: string;
};
const user = await client.get<User>('/users/1');const users = await client.get('/users', {
query: {
page: 1,
active: true,
},
});const created = await client.post('/users', {
name: 'Tom',
email: 'tom@example.com',
});const updated = await client.put('/users/1', {
name: 'Tom Updated',
});const updatedUser = await client.patch('/users/1', {
name: 'Jane',
});const result = await client.delete('/users/1');type RequestOptions = {
query?: Record<string, string | number | boolean | null | undefined>;
headers?: Record<string, string>;
timeout?: number;
retry?: RetryConfig;
signal?: AbortSignal;
};const result = await client.request({
method: 'POST',
path: '/events',
body: {
type: 'user.created',
},
headers: {
'x-request-id': 'req-123',
},
timeout: 3000,
});type RequestConfig = {
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
path: string;
query?: Record<string, string | number | boolean | null | undefined>;
body?: unknown;
headers?: Record<string, string>;
timeout?: number;
retry?: RetryConfig;
signal?: AbortSignal;
};Headers are merged in this order:
- default headers
- client headers
- request headers
- auth modifications
- beforeRequest hook modifications
That means request-level headers override client-level headers, and auth can still overwrite auth-related header values.
Timeout is resolved in this order:
- request-level timeout
- client-level timeout
- default timeout:
5000
Responses are parsed automatically:
application/json→ parsed JSON- other content types → text
204 No Content→undefined
If request body is an object, the client:
- serializes it with
JSON.stringify(...) - sets
content-type: application/jsononly if you did not set it yourself
If request body is a string, the client:
- sends it as-is
- does not force a
content-type