「Request / Response」は fetch がやり取りする“手紙の入れ物”
まず大きなイメージからいきます。
fetch は「サーバーと会話する窓口」でしたよね。
その会話の中で実際に行き来しているのが、
送る側の情報をまとめた Request オブジェクト
返ってきた情報をまとめた Response オブジェクト
です。
つまり、
あなた → サーバー に送る「手紙」が Request
サーバー → あなた に返ってくる「返事」が Response
と考えると分かりやすいです。
ふだんは fetch(url, options) と書くだけで、裏側で勝手に Request が作られ、返ってきた Response を受け取っています。
でも、この二つをちゃんと意識できるようになると、通信の理解が一段深くなります。
Response オブジェクトをちゃんと理解する
Response は「サーバーからの返事のまとまり」
fetch の戻り値(Promise が解決したときの中身)は、Response オブジェクトです。
const response = await fetch("https://example.com/api/user");
JavaScriptこの response の中には、サーバーからの返事に関する情報がまとまっています。
ステータスコード(200, 404, 500 など)
ヘッダー(Content-Type など)
ボディ(中身)をどう読むかのメソッド
などが入っています。
「HTTP レスポンスを JavaScript から扱いやすくしたもの」が Response だと思ってください。
ステータスコードと ok プロパティ
まずよく使うのが status と ok です。
console.log(response.status); // 200, 404, 500 など
console.log(response.ok); // 200〜299 のとき true、それ以外は false
JavaScriptここがとても重要です。
fetch 自体は、サーバーが 404 や 500 を返しても「エラーにはしない」
「通信は成功したけど、サーバー側の結果はエラーだった」という状態を自分で判定する必要がある
そのために response.ok を見るのが定番パターンです。
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
JavaScriptボディを読むメソッド(json / text など)
Response の中身(ボディ)は、そのままでは使えません。
「どういう形式で読みたいか」をメソッドで指定します。
JSON として読みたいときは json()。
const data = await response.json();
JavaScriptテキストとして読みたいときは text()。
const text = await response.text();
JavaScriptこの二つはどちらも非同期で、Promise を返します。
つまり、
await fetch(...) でレスポンスヘッダーまで取得await response.json() でボディをパース
という「二段階で読む」イメージが大事です。
Response は一度しか“読めない”という性質
Response のボディは「ストリーム」なので、基本的に一度しか読めません。
const data1 = await response.json();
const data2 = await response.json(); // ここはエラーになる
JavaScript一回 json() や text() で読んだら、それでおしまいです。
同じ Response から何度もボディを取り出すことはできません。
もしどうしても複数の場所で使いたいなら、
一度変数に入れて、それを渡していく設計にします。
const data = await response.json();
useA(data);
useB(data);
JavaScriptRequest オブジェクトは「送る内容をまとめたもの」
fetch は内部で Request を勝手に作っている
ふだんはこう書いていますよね。
fetch("https://example.com/api/user", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "taro" }),
});
JavaScriptこのとき裏側では、
URL
HTTP メソッド(GET / POST など)
ヘッダー
ボディ
といった情報をまとめた Request オブジェクト が作られています。
つまり、fetch は
Request を作る
その Request をサーバーに送る
返ってきた Response を Promise で返す
ということをやっているわけです。
Request を自分で作ることもできる
必要であれば、自分で new Request(...) してから fetch に渡すこともできます。
const req = new Request("https://example.com/api/user", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "taro" }),
});
const response = await fetch(req);
JavaScriptこうすると、
同じ Request を何度か使い回したい
Request を別の関数に渡したい
といったときに便利です。
ただ、初心者のうちは「fetch(url, options) で十分」と思っていて大丈夫です。
「裏側では Request が作られている」というイメージだけ持っておけば OK です。
Request からもヘッダーやメソッドを参照できる
Request オブジェクトも、いろいろな情報を持っています。
console.log(req.method); // "POST"
console.log(req.url); // "https://example.com/api/user"
console.log(req.headers.get("Content-Type")); // "application/json"
JavaScriptService Worker や高度な処理を書くときには、
Request を受け取って中身を見て処理を分岐する、ということもよくあります。
Request / Response をセットでイメージする
一連の流れをコードで眺めてみる
シンプルな GET の例を、Request / Response の視点で見直してみます。
async function loadUser() {
const url = "https://example.com/api/user";
// ここで内部的に Request が作られる
const response = await fetch(url);
// ここから Response を扱う
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const user = await response.json();
console.log(user);
}
JavaScript流れとしては、
URL から Request が組み立てられる
Request がサーバーに送られる
サーバーが Response を返す
Response のステータスやボディを見て処理を決める
という感じです。
POST の例だと、Request の中身が少しリッチになります。
async function createUser(user) {
const response = await fetch("https://example.com/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(user),
});
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const created = await response.json();
console.log(created);
}
JavaScriptここでは、
Request のメソッドが POST
ヘッダーに Content-Type が付く
ボディに JSON 文字列が入る
という形で、「送る側の情報」が Request にまとまっています。
ヘッダーを通して Request / Response が“会話”している
Request ヘッダーで「こういう形で送るよ」と伝える
例えば JSON を送るとき、こんなヘッダーを付けます。
headers: {
"Content-Type": "application/json",
}
JavaScriptこれは、
「このリクエストのボディは JSON ですよ」
とサーバーに伝えるための情報です。
サーバー側はそれを見て、
「じゃあ JSON としてパースしよう」と判断します。
Response ヘッダーで「こういう形で返すよ」と伝える
逆に、サーバーからの返事にもヘッダーがあります。
console.log(response.headers.get("Content-Type")); // "application/json" など
JavaScriptここで Content-Type: application/json なら、
「このレスポンスのボディは JSON ですよ」という意味です。
だからこそ、クライアント側では response.json() を呼ぶわけです。
Request と Response は、
ヘッダーを通して「データの形式」や「追加情報」をやり取りしています。
このやり取りを意識できるようになると、
「なぜここでこのヘッダーを付けるのか」が理解しやすくなります。
初心者として本当に押さえておきたいポイント
最後に、あなたの頭の中に残しておいてほしいことを整理します。
fetch の結果は Response オブジェクト
Response にはステータス(status / ok)、ヘッダー、ボディ読み取りメソッド(json() / text())がある
ボディは一度しか読めないので、json() や text() は一回だけ呼ぶ
Request は「送る内容をまとめたオブジェクト」で、fetch(url, options) で裏側で作られている
POST などでは、Request のメソッド・ヘッダー・ボディを意識して設計する
Request / Response は、ヘッダーを通して「どういうデータを送る・返すか」を会話している
おすすめの練習は、
今まで書いた fetch のコードを見直して、
「ここで作られている Request はどんな中身になっているか」
「返ってきた Response から何を見て、どう判断しているか」
を言葉にして説明してみることです。
それがスラスラ言えるようになったとき、
あなたはもう「なんとなく fetch を使っている人」ではなく、
「Request / Response の会話を設計できる人」 に近づいています。
