Fetch Adapter
The Fetch adapter provides cross-platform HTTP support using the standard Fetch API. It works in browsers, Deno, Bun, Node.js 18+, Cloudflare Workers, Vercel Edge, and any runtime that implements globalThis.fetch. It is the recommended adapter for client-side applications and edge runtimes.
import rezo from 'rezo/adapters/fetch'; Import and Setup
import rezo, {
Rezo,
RezoError,
RezoHeaders,
RezoFormData
} from 'rezo/adapters/fetch';
// Default instance
const { data } = await rezo.get('https://api.example.com/users');
// Custom instance
const client = new Rezo({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: { 'Authorization': 'Bearer my-token' }
}); Environment Detection
The Fetch adapter automatically detects its runtime environment to adjust behavior:
| Environment | Detection | Cookie Jar |
|---|---|---|
| Node.js | process.versions.node | Yes (manual headers) |
| Bun | globalThis.Bun | Yes (manual headers) |
| Deno | globalThis.Deno | Yes (manual headers) |
| Browser | window + document | No (browser-controlled) |
| Web Worker | WorkerGlobalScope | No (browser-controlled) |
| Cloudflare Workers | navigator.userAgent === 'Cloudflare-Workers' | Yes (manual headers) |
| Vercel Edge | globalThis.EdgeRuntime | Yes (manual headers) |
In server-side environments (Node.js, Bun, Deno, Cloudflare Workers), the adapter can set the Cookie header manually for jar integration. In browser environments, document.cookie and the Cookie header are controlled by the browser, so the cookie jar is not available.
Redirect Handling
The Fetch adapter uses redirect: 'manual' internally to intercept redirects and handle them itself. This allows Rezo to:
- Track redirect chains and the final URL
- Apply cookie jar updates at each redirect step
- Detect redirect cycles
- Enforce
maxRedirectslimits
const response = await rezo.get('https://example.com/short-link', {
maxRedirects: 5,
followRedirects: true
});
// Access the final URL after redirects
console.log(response.config.url); // https://example.com/actual-page Timeout with AbortController
Timeouts are implemented using AbortController, which is the standard mechanism for canceling Fetch requests:
const { data } = await rezo.get('https://slow-api.example.com/data', {
timeout: 5000 // 5 second timeout
}); You can also provide your own AbortSignal for manual cancellation:
const controller = new AbortController();
// Cancel the request after 3 seconds
setTimeout(() => controller.abort(), 3000);
try {
const { data } = await rezo.get('https://example.com/data', {
signal: controller.signal
});
} catch (error) {
if (error.code === 'ECONNABORTED') {
console.log('Request was cancelled');
}
} Response Streaming
The Fetch adapter supports response streaming via response.body.getReader():
const response = await rezo.stream('https://example.com/events');
// response.data is a ReadableStream
const reader = response.data.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
console.log(decoder.decode(value, { stream: true }));
} Server-Sent Events
Streaming works well for consuming Server-Sent Events (SSE):
const response = await rezo.stream('https://api.example.com/events', {
headers: { 'Accept': 'text/event-stream' }
});
const reader = response.data.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('
');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.startsWith('data: ')) {
const event = JSON.parse(line.slice(6));
handleEvent(event);
}
}
} Download Progress
The adapter tracks download progress using the reader API:
const client = new Rezo({
hooks: {
onDownloadProgress: [({ loaded, total, percent }) => {
if (total) {
console.log(`Downloaded ${percent.toFixed(1)}%`);
} else {
console.log(`Downloaded ${loaded} bytes`);
}
}]
}
});
const { data } = await client.get('https://example.com/large-response'); Note that total is only available when the server sends a Content-Length header.
Retry Logic
The Fetch adapter includes the same retry mechanism as other adapters:
const { data } = await rezo.get('https://flaky-api.example.com/data', {
retry: {
limit: 3,
delay: 1000,
backoff: 'exponential',
statusCodes: [429, 500, 502, 503, 504]
}
}); Rate Limit Wait
Automatic Retry-After header handling for 429 responses:
const client = new Rezo({ rateLimitWait: true });
// Automatically waits if the server returns 429 with Retry-After
const { data } = await client.get('https://rate-limited-api.com/data'); Response Caching
const client = new Rezo({
cache: {
maxAge: 30000, // 30 seconds
maxEntries: 200
}
});
const { data: first } = await client.get('https://api.example.com/config');
const { data: second } = await client.get('https://api.example.com/config');
// second is served from cache Content Type Detection
The adapter automatically detects and parses response content types:
// JSON responses are parsed automatically
const { data } = await rezo.get('https://api.example.com/users');
// data is already a parsed JavaScript object
// Text responses
const { data: html } = await rezo.get('https://example.com', {
responseType: 'text'
});
// Binary data
const { data: buffer } = await rezo.get('https://example.com/image.png', {
responseType: 'arraybuffer'
}); Debug Mode
const { data } = await rezo.get('https://api.example.com/users', {
debug: true
});
// [Rezo Debug] GET https://api.example.com/users
// [Rezo Debug] Adapter: fetch
// [Rezo Debug] Response: 200 OK (95.42ms) Limitations
The Fetch adapter has several limitations compared to the HTTP and HTTP/2 adapters, mostly due to browser security restrictions:
| Feature | Status | Reason |
|---|---|---|
| Proxy support | Not available | Browsers do not expose proxy configuration to JavaScript |
| Streaming requests | Not available | Fetch does not support streaming request bodies in all runtimes |
| HTTP/2 configuration | Not available | The browser/runtime negotiates protocols transparently |
| DNS caching | Not available | Handled by the runtime’s resolver |
| TLS configuration | Not available | Managed by the runtime’s TLS stack |
| Cookie jar (browser) | Not available | Cookie header is controlled by the browser |
| Upload progress | Not available | Fetch does not provide upload progress events |
Cookie Jar in Server Runtimes
While browser environments cannot use the cookie jar, server-side runtimes (Node.js, Bun, Deno, Cloudflare Workers) can:
// This works in Node.js, Bun, Deno, CF Workers
import rezo, { RezoCookieJar } from 'rezo/adapters/fetch';
const jar = new RezoCookieJar();
const client = new Rezo({ jar });
await client.post('https://api.example.com/login', { user: 'admin' });
const { data } = await client.get('https://api.example.com/profile');
// Cookies are sent via manual Cookie header When to Use This Adapter
The Fetch adapter is the right choice when:
- You are building a browser application and want the smallest bundle size
- You are targeting edge runtimes (Cloudflare Workers, Vercel Edge)
- You are running on Deno
- You do not need proxy, TLS configuration, or cookie jar support (in browsers)
- You want maximum runtime compatibility across environments
For server-side Node.js applications that need full features, use the HTTP adapter. For HTTP/2 multiplexing, use the HTTP/2 adapter. For upload progress in browsers, use the XHR adapter.