ofetch の使い方

A better fetch API. Works on node, browser and workers.

v1.5.15.8M/週MITHTTPクライアント
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

ofetch の使い方 — Node.js・ブラウザ・Workerで動く高機能fetchラッパー

一言でいうと

ofetch は、Node.js・ブラウザ・Web Workers のすべてで動作する、ネイティブ fetch API の上位互換ラッパーです。JSONの自動パース、自動リトライ、エラーハンドリング、インターセプターなど、実務で必要な機能が最初から揃っています。

どんな時に使う?

  • Nuxt / Node.js / Edge Workers で共通のHTTPクライアントを使いたい時 — 環境差を吸収してくれるため、同じコードがどこでも動きます(Nuxt 3の内部でも採用されています)
  • axios から fetch ベースのライブラリに移行したい時 — インターセプター、自動リトライ、baseURL設定など、axiosユーザーが期待する機能を備えています
  • 素のfetchのボイラープレートを減らしたい時 — レスポンスのJSON自動パース、エラー時の自動throw、Content-Typeの自動設定など、毎回書いていた定型処理が不要になります

インストール

# npm
npm i ofetch

# yarn
yarn add ofetch

# pnpm
pnpm add ofetch

ofetch の基本的な使い方

import { ofetch } from "ofetch";

// GETリクエスト — レスポンスは自動でJSONパースされる
interface User {
  id: number;
  name: string;
  email: string;
}

const users = await ofetch<User[]>("/api/users", {
  baseURL: "https://api.example.com",
});

console.log(users[0].name); // 型補完が効く

// POSTリクエスト — bodyは自動でJSON.stringifyされ、Content-Typeも自動設定
const newUser = await ofetch<User>("/api/users", {
  baseURL: "https://api.example.com",
  method: "POST",
  body: { name: "Taro", email: "taro@example.com" },
});

これだけで、素の fetch で必要だった以下の処理がすべて自動化されます:

  • response.ok チェック → 失敗時は自動で例外をスロー
  • response.json() 呼び出し → Content-Typeに応じて自動パース
  • JSON.stringify(body) → オブジェクトを渡すだけでOK
  • headers: { "Content-Type": "application/json" } → 自動設定

よく使うAPI

1. ofetch<T>(url, options) — 基本のリクエスト

import { ofetch } from "ofetch";

// 型パラメータでレスポンスの型を指定
interface Article {
  id: number;
  title: string;
  body: string;
}

const article = await ofetch<Article>("/api/articles/1", {
  baseURL: "https://api.example.com",
});

2. query / params — クエリパラメータの付与

// /api/articles?page=2&limit=10&lang=ja として送信される
const articles = await ofetch<Article[]>("/api/articles", {
  baseURL: "https://api.example.com",
  query: {
    page: 2,
    limit: 10,
    lang: "ja",
  },
});

// URL自体にクエリがあっても安全にマージされる
// → /api/articles?lang=en&id=123
await ofetch("/api/articles?lang=en", { query: { id: 123 } });

paramsquery のエイリアスです。どちらを使っても同じ動作になります。

3. ofetch.create() — デフォルトオプション付きインスタンス生成

const apiFetch = ofetch.create({
  baseURL: "https://api.example.com/v1",
  headers: {
    Authorization: "Bearer my-token",
  },
  retry: 2,
  retryDelay: 500,
});

// 以降はbaseURLとヘッダーが自動付与される
const users = await apiFetch<User[]>("/users");
const articles = await apiFetch<Article[]>("/articles");

4. インターセプター — リクエスト/レスポンスのフック

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

  async onRequest({ options }) {
    // 毎リクエストに認証トークンを付与
    const token = await getAccessToken();
    options.headers.set("Authorization", `Bearer ${token}`);
  },

  async onRequestError({ request, error }) {
    console.error(`[Request Error] ${request}`, error);
  },

  async onResponse({ request, response }) {
    console.log(`[Response] ${request} — ${response.status}`);
  },

  async onResponseError({ request, response }) {
    // 401なら認証エラーハンドリング
    if (response.status === 401) {
      await redirectToLogin();
    }
  },
});

インターセプターは配列で複数指定することも可能です:

await ofetch("/api/data", {
  onRequest: [
    ({ options }) => { /* ロギング */ },
    ({ options }) => { /* トークン付与 */ },
  ],
});

5. リトライ・タイムアウト設定

const data = await ofetch("https://api.example.com/unstable-endpoint", {
  // リトライ回数(デフォルト: GETは1、POST/PUT/PATCH/DELETEは0)
  retry: 3,

  // リトライ間隔(ミリ秒、デフォルト: 0)
  retryDelay: 1000,

  // リトライ対象のステータスコードをカスタマイズ
  retryStatusCodes: [408, 429, 500, 502, 503, 504],

  // タイムアウト(ミリ秒、デフォルト: 無効)
  timeout: 5000,
});

補足: レスポンスタイプの制御

// Blobとして取得(画像・ファイルダウンロードなど)
const imageBlob = await ofetch("/api/avatar.png", {
  responseType: "blob",
});

// ReadableStreamとして取得(ストリーミング処理)
const stream = await ofetch("/api/large-data", {
  responseType: "stream",
});

// テキストとして取得(JSONパースをスキップ)
const html = await ofetch("/page", {
  responseType: "text",
});

// カスタムパーサーを使用
const data = await ofetch("/api/data", {
  parseResponse: (text) => JSON.parse(text),
});

類似パッケージとの比較

特徴ofetchaxioskynode-fetch
ブラウザ対応
Node.js対応❌(v1時点)
Web Workers / Edge
ベースfetch APIXMLHttpRequestfetch APIfetch polyfill
JSON自動パース
自動リトライ❌(別途プラグイン)
インターセプター✅(hooks)
TypeScript✅ ネイティブ△(@types必要)
バンドルサイズ~1KB (min+gzip)~13KB~3KBN/A
Nuxt 3統合✅(内蔵)

選定の目安:

  • Nuxt 3 / Nitro を使っているofetch 一択(内部で使われている)
  • ブラウザ + Node.js + Edge の全環境で統一したいofetch
  • XMLHttpRequestの機能(アップロード進捗など)が必要axios
  • ブラウザ専用で軽量なものが欲しいky

注意点・Tips

エラーハンドリングは FetchError を活用する

import { ofetch, FetchError } from "ofetch";

try {
  await ofetch("/api/protected");
} catch (error) {
  if (error instanceof FetchError) {
    // error.data にパース済みのレスポンスボディが入る
    console.error(`Status: ${error.response?.status}`);
    console.error(`Error body:`, error.data);
  }
}

POST/PUT/PATCH/DELETE はデフォルトでリトライしない

副作用のあるメソッドは安全のためリトライ回数が 0 に設定されています。明示的に retry を指定すると、冪等でないリクエストが重複実行される可能性があるため注意してください。

ofetch.create() のヘッダーは浅いマージ

create() で設定したデフォルトオプションは1階層のみクローンされます。ネストされたオブジェクト(特に headers)は参照が共有される場合があるため、動的にヘッダーを変更する場合はインターセプター(onRequest)で設定するのが安全です。

destr による安全なJSONパース

ofetch は内部で destr を使ってJSONをパースします。これは JSON.parse と異なり、プロトタイプ汚染攻撃に対する防御が組み込まれています。厳密に JSON.parse を使いたい場合は parseResponse オプションで上書きできます。

レスポンスのステータスエラーを無視したい場合

// response.ok が false でも例外をスローしない
const response = await ofetch("/api/maybe-404", {
  ignoreResponseError: true,
});

まとめ

ofetch は、Node.js・ブラウザ・Edge Workers のすべてで統一的に使えるfetchラッパーで、JSON自動パース・自動リトライ・インターセプター・型安全なレスポンスといった実務に必要な機能を極めて小さなバンドルサイズで提供します。特にNuxt 3エコシステムでは標準のHTTPクライアントとして組み込まれており、素の fetch のボイラープレートから解放されつつ、axiosのような使い勝手を得られるモダンな選択肢です。

比較記事