Node v16.15.0 および v17.5.0 から、Fetch API と FormData が利用できるようになりました。 それ以前はブラウザに近いAPIを利用するために node-fetch と form-data パッケージを利用している人もいるかと思います。 3rd-partyパッケージのimport文を消すだけで移行できる場合もありますが、ファイルアクセスなどNode.jsの機能を利用している場合は、気をつけるポイントがあります。 この記事ではnode-fetch/form-dataパッケージからNode.jsネイティブAPIへの移行方法を紹介します。
忙しい人向けdiff
import fs from 'node:fs';
-import FormData from 'form-data';
-import fetch from 'node-fetch';
-const file = fs.createReadStream('secret.txt');
+const file = await fs.openAsBlob('secret.txt', { type: 'text/plain' });
const form = new FormData();
-form.append('file', file);
+form.append('file', file, 'secret.txt');
const response = await fetch('https://example.com/upload', {
method: 'POST',
body: form,
});
解説
型の非互換性
form-dataパッケージとNode.jsのFormDataは互換性がなく、Fetch APIにそのまま渡せません。
もしネイティブのFetch APIにform-dataを渡すと、[object FormData]
という文字列がリクエストボディとなってしまいます。
import FormData from 'form-data';
const form = new FormData();
await fetch('https://example.com/upload', {
method: 'POST',
body: form,
});
// [object FormData]
またform-dataパッケージは、Node.jsの fs.ReadStream
を受け取りました。
ネイティブAPIはブラウザ互換のBlobを受け取ります。
Node.js v19.8.0から追加された fs.openAsBlob()
を使うと、ファイルからBlobを作れます。
もしネイティブAPIのFormDataに fs.ReadStream
を渡すと、[object Object]
という文字列が値となります。
import fs from 'node:fs';
const file = fs.createReadStream('secret.txt');
const form = new FormData();
form.append('file', file);
// Content-Disposition: form-data; name="file"
//
// [object Object]
内部挙動の非互換性
form-dataパッケージは fs.ReadStream
からファイル名を取得して filename
フィールドに渡します(内部実装)。
またファイル名からファイルタイプを取得してContent-Typeヘッダーを指定します(内部実装)。
Blobはファイル名を持たないため、FormData
で指定する必要があります。
ネイティブ APIの FormData
は、Content-Typeを指定しない場合 application/octet-stream
がデフォルトとなります。
Content-Typeを明示的に指定するには、fs.openAsBlob()
の引数に渡します。
const file = await fs.openAsBlob('secret.txt');
const form = new FormData();
form.append('file', file);
// Content-Disposition: form-data; name="file"; filename="blob"
// Content-Type: application/octet-stream
const file = await fs.openAsBlob('secret.txt', { type: 'text/plain' });
const form = new FormData();
form.append('file', file, 'secret.txt');
// Content-Disposition: form-data; name="file"; filename="secret.txt"
// Content-Type: text/plain
まとめ
Fetch API/FormDataはNode.js v21.0.0からStability: 2 (Stable)になりました。
fs.openAsBlob()
は最新版のNode.js v22でもStability: 1(Experimental)です(2024年7月27日時点の最新版はv22.5.1)。
古い環境での実行や、将来のAPI変更には注意しましょう。