Adapters

XHR Adapter

The XHR adapter uses the XMLHttpRequest API (Level 2) to make HTTP requests from the browser. Its main advantage over the Fetch adapter is built-in upload and download progress events, making it the preferred choice when progress tracking is required in a browser environment.

import rezo from 'rezo/adapters/xhr';

Import and Setup

import rezo, {
  Rezo,
  RezoError,
  RezoHeaders,
  RezoFormData
} from 'rezo/adapters/xhr';

// 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
});

Upload Progress

The XHR adapter is the only browser adapter that provides real upload progress events via XMLHttpRequest.upload.onprogress:

const client = new Rezo({
  hooks: {
    onUploadProgress: [({ loaded, total, percent }) => {
      console.log(`Uploaded: ${percent.toFixed(1)}%`);
      updateProgressBar(percent);
    }]
  }
});

const form = new RezoFormData();
form.append('video', fileInput.files[0]);

await client.upload('https://api.example.com/upload', form);

This is particularly useful for large file uploads where users need visual feedback. The Fetch adapter does not support upload progress.

Download Progress

Download progress is also tracked through XHR events:

const client = new Rezo({
  hooks: {
    onDownloadProgress: [({ loaded, total, percent }) => {
      if (total) {
        console.log(`Downloaded: ${percent.toFixed(1)}%`);
      } else {
        console.log(`Downloaded: ${(loaded / 1024).toFixed(0)} KB`);
      }
    }]
  }
});

const { data } = await client.get('https://api.example.com/large-dataset');

Response Type Configuration

The adapter maps Rezo’s responseType to XMLHttpRequest.responseType:

// JSON (default) -- automatically parsed
const { data } = await rezo.get('https://api.example.com/users');

// Raw text
const { data: html } = await rezo.get('https://example.com', {
  responseType: 'text'
});

// ArrayBuffer for binary data
const { data: buffer } = await rezo.get('https://example.com/image.png', {
  responseType: 'arraybuffer'
});

// Blob for file handling in the browser
const { data: blob } = await rezo.get('https://example.com/document.pdf', {
  responseType: 'blob'
});

// Create a download link from the blob
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.pdf';
a.click();
URL.revokeObjectURL(url);

Cross-Origin Credentials

The adapter supports withCredentials for sending cookies and authorization headers with cross-origin requests:

const client = new Rezo({
  withCredentials: true
});

// Cookies and auth headers are sent with cross-origin requests
const { data } = await client.get('https://api.different-domain.com/data');

This maps directly to XMLHttpRequest.withCredentials. The server must include appropriate CORS headers (Access-Control-Allow-Credentials: true) for this to work.

Abort Signal Support

Cancel requests using an AbortController:

const controller = new AbortController();

const promise = rezo.get('https://api.example.com/slow-endpoint', {
  signal: controller.signal
});

// Cancel after 2 seconds
setTimeout(() => controller.abort(), 2000);

try {
  const { data } = await promise;
} catch (error) {
  if (error.code === 'ECONNABORTED') {
    console.log('Request cancelled');
  }
}

The adapter also supports Rezo’s built-in timeout, which creates an internal abort signal:

const { data } = await rezo.get('https://slow-api.example.com/data', {
  timeout: 5000
});

Retry Logic

Same retry mechanism as all 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]
  }
});

Rate Limit Wait

const client = new Rezo({ rateLimitWait: true });

const { data } = await client.get('https://rate-limited-api.com/data');
// Automatically waits and retries on 429 + Retry-After

Response Caching

const client = new Rezo({
  cache: {
    maxAge: 60000,
    maxEntries: 100
  }
});

const { data } = await client.get('https://api.example.com/config');

Form Data Uploads

The XHR adapter works with both Rezo’s RezoFormData and the browser’s native FormData:

// Using RezoFormData
const rezoForm = new RezoFormData();
rezoForm.append('name', 'report.xlsx');
rezoForm.append('file', fileInput.files[0]);
await rezo.post('https://api.example.com/upload', rezoForm);

// Using native FormData (also works)
const nativeForm = new FormData();
nativeForm.append('name', 'report.xlsx');
nativeForm.append('file', fileInput.files[0]);
await rezo.post('https://api.example.com/upload', nativeForm);

In browser environments, cookies are managed by the browser itself. The XHR adapter does not use a cookie jar. Instead, cookies are sent and received according to browser rules:

  • Same-origin requests include cookies automatically
  • Cross-origin requests require withCredentials: true and server CORS headers
  • httpOnly cookies are not accessible to JavaScript
// Same-origin: cookies are sent automatically
const { data } = await rezo.get('/api/profile');

// Cross-origin: requires withCredentials
const { data } = await rezo.get('https://api.other-domain.com/profile', {
  withCredentials: true
});

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: xhr
// [Rezo Debug] Response: 200 OK (112.45ms)
// [Rezo Debug] Response Headers: { ... }

Limitations

FeatureStatusReason
Proxy supportNot availableBrowser security restrictions
Response streamingNot availableXHR buffers the entire response body
HTTP/2 configurationNot availableBrowser handles protocol negotiation
DNS cachingNot availableBrowser handles DNS resolution
TLS configurationNot availableBrowser handles TLS
Cookie jarNot availableBrowser controls cookie storage
Compression controlNot availableBrowser handles Accept-Encoding

The biggest limitation compared to the Fetch adapter is the lack of response streaming. XHR buffers the entire response in memory before making it available, which can be problematic for very large responses.

Browser Compatibility

The XHR adapter requires XMLHttpRequest Level 2, which is supported by:

  • Chrome 31+
  • Firefox 20+
  • Safari 7+
  • Edge 12+
  • IE 11 (partial — no responseType: 'json')
  • Opera 18+

For IE11, the adapter automatically falls back to manual JSON parsing when responseType: 'json' is not supported.

When to Use This Adapter

The XHR adapter is the right choice when:

  • You need upload progress events in the browser (Fetch does not support this)
  • You need to support IE11 or older browsers
  • You need responseType: 'blob' for in-browser file handling
  • You want withCredentials support for CORS requests with cookies

For modern browsers where upload progress is not needed, the Fetch adapter is lighter. For server-side Node.js, use the HTTP adapter.