Help us understand the problem. What is going on with this article?

Fetch API について

Fetch APIについて

この記事では、JavaScriptのFetch APIの簡単な使い方を紹介します。モチベーションとしては、「XMLHttpRequestだと記述が長い!」「コールバックが面倒!」です。

hac2019_2本目.png

なお、この記事ではPromiseとawaitは出てきますが、asyncは出てきません。

Fetch APIとは

Fetch APIとは、XMLHttpRequestと同じでHTTPリクエストを発行する APIですが、XMLHttpRequestよりシンプルでモダンな APIです。
Fetch APIのfetchを使えば、下記のような簡単な呼び出しで HTTPリクエストを発行して結果を見ることができます。実際、F12ツール(DevTools)上でリクエストを送ってみると、

(await fetch("https://qiita.com/api/v2/items")).json();

こんな結果が返ってきます。

(20) [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
  lastIndex: (...)
  lastItem: (...)
  0: {rendered_body: "<h2>...</h2>", body:"...", ...}
  1: {rendered_body: "<h2>...</h2>", body:"...", ...}
  <<中略>>
  19: {rendered_body: "<h2>...</h2>", body:"...", ...}
  length: 20
  __proto__: Array(0)

XMLHttpRequestを使うよりはシンプルですし、jQuery.ajaxやaxios.getのようにライブラリに依存しません。
その代わり、実行可能なブラウザには制限ができてしまいます。私は、APIからデータを取得してJavaScriptでちょっとした加工をしたいときに使っています。

基本的には、これだけ知っていれば十分です。他に知る必要があるのはヘッダやメソッドの指定の仕方くらいでしょうか。

使ってみる

なにはともあれ、使ってみましょう。
このページを見ながら、F12キーか Ctrl+Shift+Iを押して F12ツール(DevTools)を開いて、コンソールを開いてください。

リクエストを発行する

fetchを使ってリクエストを送ってみます。

fetch("https://qiita.com/api/v2/items");

するとこんな値が返ってきます。
Promiseです。中身がぜんぜん見えませんね。

Promise {<pending>}
  __proto__: Promise
  [[PromiseStatus]]: "resolved"
  [[PromiseValue]]: Response

Promiseの中身を見る

Promiseとはなにかを考える前に、とりあえず先頭にawaitをつけて実行してみましょう。

await fetch("https://qiita.com/api/v2/items");

すると、こんな感じのオブジェクトが返ってきます。
Responseです。さっきよりは中がちょっと見えます。
例えば、ステータスコードが200であることがわかります。

Response {type: "basic", url: "https://qiita.com/api/v2/items", redirected: false, status: 200, ok: true, }
  type: "basic"
  url: "https://qiita.com/api/v2/items"
  redirected: false
  status: 200
  ok: true
  statusText: ""
  headers: Headers {}
  body: (...)
  bodyUsed: false
  __proto__: Response

bodyに値が入っていそうですが、クリックして展開してみるとReadableStreamと出てきます。
読み込めそうな何かだということしかわかりません。

body: ReadableStream;
locked: false;
__proto__: ReadableStream;

body の中身を見る

ReadableStreamのことは一旦忘れて、Responseについて調べてみましょう。
Response - Web API | MDNによると、arrayBuffer, blob, formData, json, textといったメソッドがあることがわかります。
今回の APIはJSONを返すことがわかっているので、jsonメソッドを使ってみましょう。

(await fetch("https://qiita.com/api/v2/items")).json();

ついにでデータまでたどり着くことができました。

(20) [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
lastIndex: (...)
lastItem: (...)
0: {rendered_body: "<h2>...</h2>", body:"...", ...}
1: {rendered_body: "<h2>...</h2>", body:"...", ...}
<<中略>>
19: {rendered_body: "<h2>...</h2>", body:"...", ...}
length: 20
__proto__: Array(0)

もう少し使ってみる

単にGETリクエストを送るだけではつまらないので、少しだけ深堀りしてみましょう。

ヘッダ

fetchの第2引数を使えば、好きなヘッダを付けてHTTPリクエスト送ることができます。

ヘッダ付きのHTTPリクエストを送るには下記のようにします。

await fetch(url, {
  headers: {
    Authorization: "Basic " + btoa("username" + ":" + "password"),
    Accept: "application/json",
    "Content-Type": "application/json;charset=utf-8"
  }
});

Headersオブジェクトを生成して送ることもできます。

var headers = new Headers();
headers.set("Authorization", "Basic " + btoa("username" + ":" + "password"));
await fetch(url, {
  headers
});

GET以外のリクエスト

fetchの第2引数を使えば、POSTリクエストやその他のリクエストを送ることができます。

dataに入っている文字列をそのままurlにPOSTで送るには、下記のようにします。

await fetch(url, {
  method: "POST",
  body: data
});

dataがJSONオブジェクトでurlにPOSTで送るには、下記のようにします。

await fetch(url, {
  method: "POST",
  body: JSON.stringify(data)
});

fetchのその他のオプション

詳しくはGlobalFetch.fetch() - Web API | MDNを見てください。
modecredentialcacheをよく使います。

F12ツール(DevTools)の特性

F12ツール(DevTools)は、とても良くできていてPromiseでも処理が終了していれば中身を見ることができます。[[PromiseValue]]となっているところに値が入っているので、クリックして展開して中身を見ることができます。

Promise {<pending>}
  __proto__: Promise
  [[PromiseStatus]]: "resolved"
  [[PromiseValue]]: Response
    type: "basic"
    url: "https://qiita.com/api/v2/items"
    redirected: false
    status: 200
    ok: true
    statusText: ""
    headers: Headers {}
    body: (...)
    bodyUsed: false
    __proto__: Response

awaitは、この[[PromiseValue]]を、処理が終了するまで待ってから取得するための言語機能です。

Responseにmix-inされている、jsonなどのメソッドも実はPromiseを返します。Promiseから値を取り出すには下記のようにするのが正しいです。F12ツール(DevTools)で対話的に値を見るだけならawaitはなくてもOKです。

await (await fetch("https://qiita.com/api/v2/items")).json();

ReadableStream

Body - Web API | MDNによると、BodyはReponseへのmixinであり、Responseに対して arrayBuffer, blob, formData, json, textといったメソッドを提供するものです。

Body.bodyがReadableStreamですが、上記メソッドが呼ばれたときに変換する元データが入っている場所(元データを読み取り可能なストリーム)です。
ReadableStream - Web API | MDNに例があるように、ストリームを読み取りながら処理をしたり、読み取った前後になにか処理を実行したい場合に使うことができます。

Responseを扱うだけなら、Bodyのメソッドが覆い隠してくれるので、ReadableStreamを意識する必要はありません。

awaitを使わない方法

urlが文字列、optionsがオブジェクトのときawaitを使わずに同等の処理を書くなら下記のようになります。

fetch(url, options).then(response => {
  // このブロックの中ではPromiseではなくて、通常の値として扱える
  console.log(response);
  return response; // returnしてもPromiseに包まれる
});

実用性はあまりないですが、こう書いたり、

fetch(url, options).then(response => console.log(response));

こう書くこともできます。

fetch(url, options).then(console.log);

もっと使いたい方へ

もっと進んだ使い方をしたい場合は、下記の記事が参考になります。

参考

この記事を書くにあたり、下記の記事を参考にしました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした