DEV Community

Alex Spinov
Alex Spinov

Posted on

ofetch Has a Free Universal HTTP Client — Here's How to Use It

fetch() is everywhere now — but it's still verbose. No auto-retry, no JSON parsing, no error throwing, no interceptors. ofetch adds all of that in 1KB.

What Is ofetch?

ofetch is a better fetch API from the UnJS ecosystem. It works in Node.js, browsers, service workers, and edge runtimes — with auto-JSON, retries, and interceptors built in.

Quick Start

npm install ofetch
Enter fullscreen mode Exit fullscreen mode
import { ofetch } from 'ofetch';

// Auto-parses JSON, throws on errors, retries on failure
const data = await ofetch('/api/users');
// No need for: const res = await fetch(); if (!res.ok) throw; const data = await res.json();
Enter fullscreen mode Exit fullscreen mode

Why ofetch Over fetch()

// Native fetch — 6 lines for a simple GET
const res = await fetch('https://api.example.com/users');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();

// ofetch — 1 line, same result
const data = await ofetch('https://api.example.com/users');
Enter fullscreen mode Exit fullscreen mode

Key Features

Auto JSON

// Response automatically parsed as JSON
const users = await ofetch('/api/users');

// Request body automatically serialized
await ofetch('/api/users', {
  method: 'POST',
  body: { name: 'John', email: 'john@example.com' },
  // Content-Type: application/json set automatically
});
Enter fullscreen mode Exit fullscreen mode

Auto Retry

// Retries 1 time by default on network errors
const data = await ofetch('/api/flaky-endpoint');

// Custom retry count
const data = await ofetch('/api/endpoint', { retry: 3 });

// Custom retry delay
const data = await ofetch('/api/endpoint', {
  retry: 3,
  retryDelay: 1000, // 1 second between retries
});
Enter fullscreen mode Exit fullscreen mode

Error Handling

try {
  const data = await ofetch('/api/users/999');
} catch (error) {
  // error.status — HTTP status code
  // error.data — parsed response body
  // error.message — "404 Not Found"
  console.log(error.status); // 404
  console.log(error.data);   // { message: "User not found" }
}
Enter fullscreen mode Exit fullscreen mode

Interceptors

const api = ofetch.create({
  baseURL: 'https://api.example.com',

  onRequest({ options }) {
    options.headers.set('Authorization', `Bearer ${getToken()}`);
  },

  onResponse({ response }) {
    console.log(`${response.status} ${response.url}`);
  },

  onResponseError({ response }) {
    if (response.status === 401) {
      refreshToken();
    }
  },
});

const users = await api('/users');
Enter fullscreen mode Exit fullscreen mode

Query Parameters

const users = await ofetch('/api/users', {
  query: {
    page: 1,
    limit: 10,
    sort: 'name',
    filter: ['active', 'verified'],
  },
});
// GET /api/users?page=1&limit=10&sort=name&filter=active&filter=verified
Enter fullscreen mode Exit fullscreen mode

Comparison

Feature ofetch fetch axios
Auto JSON Yes No Yes
Auto retry Yes No Plugin
Error throwing Yes No Yes
Interceptors Yes No Yes
Bundle size 1KB 0 13KB
Node.js Yes 18+ Yes
Edge/Workers Yes Yes No
TypeScript First-class Basic Good

Get Started


Fetching data from APIs? My Apify scrapers handle the heavy lifting. Custom solutions: spinov001@gmail.com

Top comments (0)