Back

Node.jsでAPIからデータを取得する方法

Node.jsでAPIからデータを取得する方法

フロントエンド開発者としてNode.jsコードを書いている場合、習慣的にAxiosを使用したり、node-fetchがまだ必要かどうか疑問に思ったりしたことがあるでしょう。今日の答えは思っているよりもシンプルです。モダンなNode.jsには安定した組み込みのfetch APIがあり、ほとんどのユースケースではこれだけで十分です。

クリーンで信頼性の高いサーバーサイドHTTPリクエストを実現するために知っておくべきことを紹介します。

重要なポイント

  • モダンなNode.jsには、undiciを基盤としたグローバルなfetch APIが標準搭載されています。パッケージのインストールは不要です。
  • fetchは404や500などのHTTPエラーで例外をスローしません。ボディを読み取る前に必ずresponse.okをチェックしてください。
  • リクエストタイムアウトには、手動でAbortControllerを設定する代わりにAbortSignal.timeout()を使用してください。
  • 同一オリジンへの繰り返しリクエストが多い高スループットシナリオでは、接続の再利用のためにundiciのPoolを使用してください。
  • Node.js専用プロジェクトでは、依存関係リストを軽量に保つため、Axiosよりもネイティブfetchを優先してください。

Node.jsのFetch APIは安定版で組み込まれています

Node.js 18以降、fetchはインポート不要でグローバルに利用可能です。v18では実験的機能としてマークされ、v21で安定版となりました。内部ではundiciを基盤としています。undiciはNode.jsのfetch実装を支えるHTTPクライアントであり、すでに知っているブラウザのFetch APIと同じ仕様です。

インストール不要。require('node-fetch')も不要。ただfetch()を使うだけです。

const response = await fetch("https://api.github.com/users/nodejs/repos", {
  headers: { "User-Agent": "my-app" },
})

if (!response.ok) {
  throw new Error(`HTTP error: ${response.status}`)
}

const repos = await response.json()
console.log(repos.map((r) => r.name))

重要な点を理解しておいてください。fetchは404や500などのHTTPエラーで例外をスローしません。ネットワーク障害の場合のみスローします。ボディを読み取る前に必ずresponse.okまたはresponse.statusをチェックしてください。

Node.jsのFetch APIでPOSTリクエストを行う

データの送信は簡単です。methodを設定し、Content-Typeヘッダーを追加して、ペイロードをシリアライズします。

const response = await fetch("https://api.example.com/posts", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ title: "Hello", body: "World" }),
})

if (!response.ok) {
  throw new Error(`HTTP error: ${response.status}`)
}

const data = await response.json()

FormDataのアップロードの場合は、Content-Typeヘッダーを完全に省略してください。fetchが正しいmultipart boundaryとともに自動的に設定します。

AbortSignalでタイムアウトを処理する

fetch呼び出し自体には組み込みのタイムアウトオプションはありませんが、AbortSignal.timeout()を使えばクリーンに実装できます。

const response = await fetch("https://api.example.com/data", {
  signal: AbortSignal.timeout(5000), // 5秒
})

リクエストが制限時間を超えると、リクエストは中止されます。シンプルなケースでは手動のAbortController設定は不要です。

より複雑なシナリオ、例えばユーザーアクションに基づいてリクエストをキャンセル、タイムアウトも強制したい場合は、AbortControllerAbortSignal.any()を組み合わせることができます。

const controller = new AbortController()

const response = await fetch("https://api.example.com/data", {
  signal: AbortSignal.any([
    controller.signal,
    AbortSignal.timeout(5000),
  ]),
})

// 手動でキャンセルする場合は、他の場所でcontroller.abort()を呼び出す

undiciを直接使用すべき場合

ほとんどのNode.js APIリクエストでは、グローバルなfetchが適切なツールです。しかし、同一オリジンに対して多数のリクエストを行う場合、例えば内部サービスに繰り返しアクセスする場合は、undiciのPoolを使用することで接続の再利用とより細かい制御が可能になります。

import { Pool } from "undici"

const pool = new Pool("https://internal-api.example.com", {
  connections: 10,
})

const { statusCode, body } = await pool.request({
  path: "/data",
  method: "GET",
})

const data = await body.json()

pool.request()が返すbodyResponseオブジェクトではなく、読み取り可能なストリームであることに注意してください。例えばbody.json()body.text()などで明示的に消費する必要があります。

高度なプーリング、大きなレスポンスの効率的なストリーミング、またはパフォーマンス重視のコードでの最大スループットが必要な場合は、undiciを直接使用してください。

Node.jsのFetch vs Axios:どちらを使うべきか?

ネイティブFetchAxios
インストールが必要いいえはい
ブラウザ互換性ありあり
自動JSON解析いいえ(.json()を呼び出す)はい
インターセプター手動組み込み
HTTPエラーで例外をスローいいえはい
タイムアウトオプションAbortSignal組み込み

Axiosは、インターセプター、自動JSON解析、またはブラウザとNode.jsで同じコードベースでの一貫した動作が必要な場合、依然として堅実な選択肢です。しかし、Node.js専用のコードを書いていて、これらの追加機能が不要な場合、ネイティブfetchは依存関係リストをクリーンに保ちます。

新規プロジェクトではnode-fetchを避けてください。Node 18以前は正しい解決策でしたが、現在サポートされているすべてのNode.jsバージョンでは冗長です。

まとめ

モダンなNode.jsでのサーバーサイドHTTPリクエストには、組み込みのfetchから始めましょう。安定していて、使い慣れており、追加のものは何も必要ありません。タイムアウトにはAbortSignal.timeout()を追加し、エラーにはresponse.okをチェックし、パフォーマンスが要求される場合のみundiciのPoolを使用してください。本当に高レベルな機能が必要な場合はAxiosをツールキットに残しておいてください。ただし、デフォルトでインストールしないでください。

よくある質問

はい。グローバルfetch APIはNode.js 18で実験的機能として導入され、Node.js 21で安定版になりました。undiciを基盤としており、追加のパッケージは不要です。現在サポートされているすべてのNode.jsバージョンには標準で含まれています。

設計上、fetchはDNS解決エラーや接続切断などのネットワークレベルの障害でのみPromiseをrejectします。404や500などのHTTPエラーステータスコードは有効なレスポンスと見なされます。ボディを処理する前に、response.okまたはresponse.statusを自分でチェックする必要があります。

はい、競合はありません。一部のチームは、シンプルなリクエストにはネイティブfetchを使用し、インターセプターや自動エラースローが必要な場合にAxiosを使用しています。ただし、HTTPクライアントを混在させると複雑さが増すため、1つをデフォルトとして選択し、特定の機能が必要な場合のみもう1つを使用してください。

接続プーリング、HTTP接続のきめ細かい制御、または同一オリジンへの繰り返しリクエストでの最大スループットが必要な場合は、undiciを直接使用してください。シンプルさが生のパフォーマンスよりも重要な典型的なAPI呼び出しでは、グローバルfetchで十分です。

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay