cURL から fetch / axios への移行で詰まる 7 つのポイント
執筆: デジタル道具屋 編集部 / API 連携担当
BtoB SaaS の API 連携プロジェクトで、サードパーティ API への接続実装を多数担当する編集チームです。
本記事の執筆方針と編集ポリシーについてはAbout ページをご覧ください。
導入:「ドキュメントの cURL は動くのに、JS から呼ぶと 401」


落とし穴 1:-d は「自動的に POST + form 形式」
cURL の -d オプションは 2つの暗黙の振る舞いがあります。
- HTTP メソッドを 自動的に POST に変える
Content-Type: application/x-www-form-urlencodedを 自動付与する
fetch ではこれを明示する必要があります:
# cURL
curl -d 'name=alice&age=20' https://api.example.com/users
// 等価な fetch
fetch('https://api.example.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ name: 'alice', age: '20' }),
})
Content-Type: application/json と JSON.stringify(...) をセットで指定するのを忘れずに。」落とし穴 2:Cookie の自動送信
cURL は同一セッション内では Cookie を自動で扱います。fetch は明示的に credentials: 'include' を指定しないと Cookie を送りません。 認証 Cookie を使う API では、これを忘れると 401 / 403 になります。
fetch('https://api.example.com/me', {
credentials: 'include', // または 'same-origin'
})さらにブラウザ環境では、サーバー側で Access-Control-Allow-Credentials: true と Access-Control-Allow-Origin に具体的なオリジン(* ではダメ)を返さないと、Cookie 送信が拒否されます。
落とし穴 3:CORS は cURL では起きない


対策は基本的にサーバー側で適切な Access-Control-* ヘッダーを返すこと。 自分が API を握っていない場合は、Next.js の API ルートやプロキシを挟んで自サーバー経由で呼ぶ手もあります。
落とし穴 4:リダイレクトの扱い
cURL で -L を付けないとリダイレクトを追わないのに対し、fetch はデフォルトで redirect: 'follow'(自動追従)です。 逆に「最初のリクエストだけ送ってリダイレクトの Location ヘッダーを取りたい」場合は、fetch 側で redirect: 'manual' を指定します。
落とし穴 5:HTTPメソッドと body の組み合わせ
GET リクエストに body を付けると、fetch は TypeError になります。 cURL は -X GET -d '...' でも黙って受け付けてしまうため、API ドキュメントが間違って GET + body で書かれているケースがあります。 その場合はクエリパラメータに変更するか、サーバー実装を確認しましょう。
落とし穴 6:レスポンスの読み方
fetch のレスポンスは 1度しか読めません。response.json() を呼んだ後に response.text() を呼ぶとエラーです。 生のテキストとパース後の両方が欲しい場合は、const text = await response.text(); const data = JSON.parse(text); と段階を分けます。
// 失敗するパターン
const data = await response.json();
const text = await response.text(); // → エラー
// 正しいパターン
const text = await response.text();
const data = JSON.parse(text);落とし穴 7:ステータスコードはエラーにならない
cURL は終了コードで成功/失敗を判別しますが、fetch は HTTP レベルで通信できれば 4xx / 5xx でも resolve します。try/catch だけではサーバーエラーを捕捉できないので、response.ok を必ずチェックしましょう。
const res = await fetch(url);
if (!res.ok) {
// 4xx / 5xx の処理
throw new Error(`API error: ${res.status}`);
}
const data = await res.json();
変換作業を機械化する
オプションが多い cURL コマンドを手作業で fetch / axios に書き換えるのは事故のもとです。 当サイトのcURL → Fetch 変換ツールでは、 cURL コマンドを貼り付けるだけで JavaScript の fetch / axios コードに変換できます。 生成されたコードに、本記事で解説した credentials・response.ok チェック・エラーハンドリングを足して仕上げてください。
関連: HTTP ステータス検索、JSON 整形(API レスポンスのデバッグに)、URL エンコード/デコード。
🚨 現場の失敗あるある
AbortController を渡し忘れて、画面遷移後もバックグラウンドで fetch が走り続け、 アンマウント済みコンポーネントへの setState 警告 → メモリリーク、というパターンが React 系で頻発します。 React Query や SWR を使えばこの辺は自動で面倒を見てくれるので、複数の fetch を扱うなら検討する価値があります。
参考にした一次情報
本記事の内容は、以下の公式仕様や一次情報を参照して執筆しています。
- Fetch Standard
WHATWG
https://fetch.spec.whatwg.org/
- curl - command line tool and library
curl project
https://curl.se/docs/manpage.html
- CORS - Cross-Origin Resource Sharing | MDN
MDN Web Docs
https://developer.mozilla.org/ja/docs/Web/HTTP/CORS