Switch to Rezo

From Axios

If you know Axios, you already know Rezo. The API patterns are nearly identical — method signatures, interceptors, config merging, and error handling all work the same way. The difference is what ships out of the box: cookies, proxies, stealth, hooks, streaming, HTTP/2, and support for every JavaScript runtime.

Import Changes

// Axios
import axios from 'axios';

// Rezo -- same default export pattern
import rezo from 'rezo';

Instance Creation

// Axios
const client = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000,
  headers: { 'X-API-Key': 'abc123' },
});

// Rezo -- same pattern
const client = rezo.create({
  baseURL: 'https://api.example.com',
  timeout: 5000,
  headers: { 'X-API-Key': 'abc123' },
});

A simple timeout number works, but Rezo also supports staged timeouts with connect, headers, body, and total.

HTTP Methods

Every method you use in Axios works identically in Rezo:

// These are the same in both libraries
await client.get('/users');
await client.post('/users', { name: 'Ada' });
await client.put('/users/1', { name: 'Ada Lovelace' });
await client.patch('/users/1', { email: 'ada@example.com' });
await client.delete('/users/1');
await client.head('/users');
await client.options('/users');

Rezo also adds convenience methods for common content types:

// JSON with automatic Content-Type
await client.postJson('/users', { name: 'Ada' });
await client.putJson('/users/1', { name: 'Ada Lovelace' });
await client.patchJson('/users/1', { email: 'ada@example.com' });

// URL-encoded form
await client.postForm('/login', { user: 'ada', pass: 'secret' });

Interceptors

The interceptor API is identical:

// Axios
axios.interceptors.request.use(
  (config) => {
    config.headers.Authorization = `Bearer ${getToken()}`;
    return config;
  },
  (error) => Promise.reject(error)
);

axios.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      return refreshAndRetry(error.config);
    }
    return Promise.reject(error);
  }
);

// Rezo -- same API
client.interceptors.request.use(
  (config) => {
    config.headers.set('Authorization', `Bearer ${getToken()}`);
    return config;
  },
  (error) => Promise.reject(error)
);

client.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.status === 401) {
      return refreshAndRetry(error.config);
    }
    return Promise.reject(error);
  }
);

Rezo’s interceptors also support a runWhen predicate:

client.interceptors.request.use(
  (config) => { /* ... */ return config; },
  null,
  { runWhen: (config) => config.url.startsWith('/api/') }
);

Error Handling

Axios errors carry response, request, and code. Rezo carries the same information plus boolean flags and recovery suggestions.

// Axios
try {
  await axios.get('/api/data');
} catch (error) {
  if (error.response) {
    console.log(error.response.status);
    console.log(error.response.data);
  } else if (error.request) {
    console.log('No response received');
  } else {
    console.log(error.message);
  }
}

// Rezo

try {
  await rezo.get('/api/data');
} catch (error) {
  if (rezo.isRezoError(error)) {
    console.log(error.code);          // "REZ_HTTP_ERROR"
    console.log(error.status);        // 404
    console.log(error.response?.data);

    // Boolean flags -- no more manual status code checking
    console.log(error.isTimeout);        // false
    console.log(error.isNetworkError);   // false
    console.log(error.isServerError);    // false
    console.log(error.isClientError);    // true

    // Recovery suggestion
    console.log(error.suggestion);    // "Check that the URL exists..."
  }
}

Query Parameters

// Axios
await axios.get('/users', {
  params: { page: 2, limit: 25 },
  paramsSerializer: (params) => qs.stringify(params),
});

// Rezo -- same pattern, custom serializer optional
await rezo.get('/users', {
  params: { page: 2, limit: 25 },
});

Typed Responses

// Axios
const { data } = await axios.get<User[]>('/users');

// Rezo -- identical
const { data } = await rezo.get<User[]>('/users');

Cancel Requests

// Axios (modern)
const controller = new AbortController();
axios.get('/slow', { signal: controller.signal });
controller.abort();

// Rezo -- same AbortController pattern
const controller = new AbortController();
rezo.get('/slow', { signal: controller.signal });
controller.abort();

What You Gain by Switching

These are features Axios does not provide or requires third-party plugins to achieve.

Axios needs axios-cookiejar-support and tough-cookie to handle cookies. Rezo has a cookie jar built into every instance — no setup needed.

// Axios -- requires two extra packages
import axios from 'axios';
import { wrapper } from 'axios-cookiejar-support';
import { CookieJar } from 'tough-cookie';

const jar = new CookieJar();
const client = wrapper(axios.create({ jar }));

// Rezo -- cookies work automatically
const { data } = await rezo.get('https://example.com/login');
// Cookies from the response are stored and sent on subsequent requests
const { data: profile } = await rezo.get('https://example.com/profile');

If you need external control over the jar (exporting, importing, inspecting), you can pass one explicitly:

import { CookieJar } from 'rezo';

const jar = new CookieJar();
const client = rezo.create({ jar });

Proxy Manager

const client = rezo.create({
  proxyManager: {
    proxies: ['http://proxy1:8080', 'socks5://proxy2:1080'],
    rotation: { strategy: 'random' },
    autoDisableDeadProxies: true
  }
});

Stealth Mode

import { RezoStealth } from 'rezo';

const client = rezo.create({
  stealth: RezoStealth.chrome()
});

26 Lifecycle Hooks

Beyond interceptors, Rezo provides hooks for DNS resolution, TCP connect, TLS handshake, redirects, retries, cookies, and more:

const client = rezo.create({
  hooks: {
    beforeRequest: [(config) => { /* ... */ }],
    afterResponse: [(response) => { return response; }],
    beforeRetry: [(config, error, ctx) => { /* ... */ }],
    beforeRedirect: [(config, response) => { /* ... */ }],
    afterCookie: [(cookies, config) => { /* ... */ }],
  }
});

Streaming and Downloads

const download = await rezo.download(
  'https://example.com/large-file.zip',
  './downloads/file.zip'
);
download.on('progress', (p) => console.log(`${p.percentage}%`));

HTTP/2

import rezo from 'rezo/adapters/http2';

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

cURL Adapter

import rezo from 'rezo/adapters/curl';

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

Staged Timeouts

const client = rezo.create({
  timeout: {
    connect: 5_000,
    headers: 10_000,
    body: 30_000,
    total: 60_000,
  }
});

Quick Migration Checklist

  1. Replace import axios from 'axios' with import rezo from 'rezo'
  2. Replace axios.create() with rezo.create()
  3. Replace error.response.status with error.status
  4. Replace header string assignments with config.headers.set() in interceptors
  5. Remove axios-cookiejar-support — cookies are built in
  6. Remove any retry plugins — use retry: { limit: 3 } in config
  7. Enjoy everything else that comes for free