ky の使い方

Tiny and elegant HTTP client based on the Fetch API

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

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

ky の使い方 — Fetch APIベースの軽量HTTPクライアント

一言でいうと

kyは、ブラウザのFetch APIをラップした軽量かつエレガントなHTTPクライアントです。axiosのような便利なAPIを、わずか数KBのバンドルサイズで提供します。

どんな時に使う?

  • フロントエンドアプリでREST APIを呼び出したい時fetchの冗長な記述(response.okチェック、JSON.parseなど)を省略し、簡潔にHTTPリクエストを書きたい場合
  • リトライ処理を手軽に実装したい時 — ネットワークエラーや5xxエラー時の自動リトライが組み込みで必要な場合
  • axiosからの軽量化移行 — バンドルサイズを削減しつつ、同等の開発体験を維持したい場合

インストール

# npm
npm install ky

# yarn
yarn add ky

# pnpm
pnpm add ky

対応環境: ky v1.x はモダンブラウザ、Node.js 18.x以降、Deno、Bun で動作します。Fetch APIがネイティブで利用可能な環境が前提です。

基本的な使い方

import ky from 'ky';

// GETリクエスト — JSONを自動パース
const user = await ky.get('https://api.example.com/users/1').json<User>();
console.log(user.name);

// POSTリクエスト — bodyを自動的にJSON.stringifyしてくれる
const newUser = await ky
  .post('https://api.example.com/users', {
    json: { name: 'Taro', email: 'taro@example.com' },
  })
  .json<User>();

console.log(newUser.id);
// 型定義の例
interface User {
  id: number;
  name: string;
  email: string;
}

fetchとの比較で見ると、kyの簡潔さが際立ちます:

// 素のfetchで書いた場合
const response = await fetch('https://api.example.com/users/1');
if (!response.ok) {
  throw new Error(`HTTP error! status: ${response.status}`);
}
const user: User = await response.json();

// kyで書いた場合
const user = await ky.get('https://api.example.com/users/1').json<User>();

よく使うAPI

1. HTTPメソッドショートカット

import ky from 'ky';

// GET
const data = await ky.get('https://api.example.com/posts').json();

// POST
const created = await ky.post('https://api.example.com/posts', {
  json: { title: 'Hello', body: 'World' },
}).json();

// PUT
await ky.put('https://api.example.com/posts/1', {
  json: { title: 'Updated' },
});

// PATCH
await ky.patch('https://api.example.com/posts/1', {
  json: { title: 'Patched' },
});

// DELETE
await ky.delete('https://api.example.com/posts/1');

2. searchParams — クエリパラメータの指定

// URLSearchParamsを手動で組み立てる必要がない
const results = await ky
  .get('https://api.example.com/search', {
    searchParams: {
      q: 'typescript',
      page: 2,
      limit: 20,
    },
  })
  .json<SearchResult>();
// => GET https://api.example.com/search?q=typescript&page=2&limit=20

3. retry — 自動リトライ

// デフォルトで2回リトライ(408, 413, 429, 500, 502, 503, 504 に対して)
const data = await ky
  .get('https://api.example.com/unstable-endpoint', {
    retry: {
      limit: 3,          // 最大3回リトライ
      methods: ['get'],   // GETのみリトライ
      statusCodes: [503], // 503のみリトライ対象
      backoffLimit: 3000, // バックオフの上限(ms)
    },
  })
  .json();

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

const api = ky.create({
  prefixUrl: 'https://api.example.com',
  hooks: {
    beforeRequest: [
      (request) => {
        const token = localStorage.getItem('accessToken');
        if (token) {
          request.headers.set('Authorization', `Bearer ${token}`);
        }
      },
    ],
    beforeRetry: [
      async ({ request, error, retryCount }) => {
        console.log(`Retry #${retryCount} for ${request.url}`);
      },
    ],
    afterResponse: [
      async (request, options, response) => {
        if (response.status === 401) {
          // トークンリフレッシュ処理
          const newToken = await refreshToken();
          request.headers.set('Authorization', `Bearer ${newToken}`);
          return ky(request);
        }
      },
    ],
  },
});

const user = await api.get('users/me').json<User>();

5. timeout と ky.create — インスタンスの共通設定

// プロジェクト全体で使う共通インスタンスを作成
const api = ky.create({
  prefixUrl: 'https://api.example.com/v2',
  timeout: 30_000, // 30秒(デフォルトは10秒)
  headers: {
    'X-Custom-Header': 'my-app',
  },
  retry: 2,
});

// 以降はprefixUrlからの相対パスで呼べる
const posts = await api.get('posts').json<Post[]>();
// => GET https://api.example.com/v2/posts

// インスタンスの設定を一部上書きして拡張
const adminApi = api.extend({
  headers: {
    'X-Admin': 'true',
  },
});

類似パッケージとの比較

特徴kyaxiosgotnode-fetch
バンドルサイズ~3 KB~13 KBNode専用Node専用
ベースFetch APIXMLHttpRequestNode httpFetch API polyfill
ブラウザ対応
Node.js対応✅ (18+)
自動リトライ✅ 組み込み❌ 別途必要✅ 組み込み
フック/インターセプター
JSON自動パース.json()デフォルト.json().json()
TypeScript✅ ネイティブ要@types
ストリーミング✅ (ReadableStream)一部対応

選定の目安:

  • ブラウザ中心で軽量にしたい → ky
  • ブラウザ+Node.jsで実績重視 → axios
  • Node.js専用で高機能 → got

注意点・Tips

HTTPErrorのハンドリング

kyはステータスコードが2xx以外の場合、自動的にHTTPErrorをスローします。エラーレスポンスのbodyを取得するには非同期処理が必要です。

import ky, { HTTPError } from 'ky';

try {
  await ky.get('https://api.example.com/not-found').json();
} catch (error) {
  if (error instanceof HTTPError) {
    const statusCode = error.response.status;
    const errorBody = await error.response.json<{ message: string }>();
    console.error(`${statusCode}: ${errorBody.message}`);
  }
}

prefixUrl の末尾スラッシュに注意

// ✅ 正しい — prefixUrlの末尾スラッシュは自動処理される
const api = ky.create({ prefixUrl: 'https://api.example.com/v1' });
await api.get('users'); // => https://api.example.com/v1/users

// ❌ 注意 — パス側を先頭スラッシュで始めるとprefixUrlが無視される
await api.get('/users'); // => これはエラーになる

FormDataの送信

const formData = new FormData();
formData.append('file', fileBlob, 'photo.png');
formData.append('description', 'プロフィール画像');

// Content-Typeは自動設定される(multipart/form-data)
await ky.post('https://api.example.com/upload', {
  body: formData,
});

AbortControllerによるキャンセル

const controller = new AbortController();

// 5秒後にキャンセル
setTimeout(() => controller.abort(), 5000);

try {
  const data = await ky
    .get('https://api.example.com/large-data', {
      signal: controller.signal,
    })
    .json();
} catch (error) {
  if (error instanceof DOMException && error.name === 'AbortError') {
    console.log('リクエストがキャンセルされました');
  }
}

デフォルトのtimeoutは10秒

kyのデフォルトタイムアウトは10秒(10,000ms)です。fetchのデフォルト(タイムアウトなし)とは異なるため、長時間かかるAPIを呼ぶ場合は明示的にtimeoutを設定してください。falseを指定するとタイムアウトを無効化できます。

// タイムアウトを無効化
await ky.get('https://api.example.com/heavy', { timeout: false });

まとめ

kyは、Fetch APIの薄いラッパーとして「fetchに足りないもの」を的確に補うライブラリです。自動リトライ、フック、JSONの簡易ハンドリング、エラーの自動スローといった実用的な機能を、わずか数KBで提供します。特にフロントエンド開発において、axiosからの移行先として、あるいは素のfetchの改善策として、有力な選択肢となるでしょう。

比較記事