JavaScript Fetch APIで非同期通信をしてみる

JavaScript Fetch APIで非同期通信をしてみる

JavaScriptでの非同期処理、すごく便利ですよね。
非同期通信を使うメリットの例として
指定したURLからデータを取得し、ページ全体を再読み込みすることなくHTMLを更新出来るのはユーザビリティの向上に繋がることだけでなくサーバー負荷の軽減にもなります。
そしてなによりAjax(Asynchronous JavaScript + XML)という呼び方がかっこいいです(笑)

そんな非同期処理をFetch APIを用いてやってみましょう。
Fetch APIという機能を使うことで、ブラウザ上でJavaScriptからHTTP通信をする事が可能になります。

※Fetch APIを使用しなくてもXMLHttpRequestやjQuery.ajax()で非同期通信を実現出来ますがこの記事では扱わないので気になった方は調べてみてください。

Fetch API

Webブラウザ上でJavaSciptからHTTP通信するためにFetch APIを使用します。
Fetch APIを用いればページ全体を再読み込みすることなく指定したURLからデータを取得することができます。(非同期通信)
以前はFetch APIではなくXMLHttpRequestを使うのが主流でした。

Fetch APIの使い方

fetchメソッドの引数にURLを与えることでHTTPリクエストが作成されます。

const URL = 'http://xxx.com';
fetch(URL)


https://api.github.com/users/任意のUserID でGitHubのユーザ情報に関するAPIを呼び出す事が出来ます。

※Node.jsでプロジェクトでfetchを使用する時はnode-fetchをnpmでインストール必要があります。

下にある画像は、
fetch( ‘https://api.github.com/users/xxxx’)
の返り値です。

見て分かる通り、fetchはPromiseのインスタンスを返しています。

Promiseインスタンスを解決してAPIからのレスポンスを取得する方法を説明していきます。

Responseを受け取る

リクエストを送ったのでレスポンスを受け取る処理を書いていきます。
fetchメソッドはPromiseを返し、このPromiseインスタンスはResponseオブジェクト解決(resolve)されます。
Responseオブジェクトはいくつかのメソッドを持っていて、欲しい型を指定する事が出来ます。

Responseオブジェクトのメソッド一覧

  • json()
  • text()
  • formData
  • arrayBuffer()
  • blob()


ResponseオブジェクトのjsonメソッドはPromiseを返し、これはHTTPレスポンスのボディをJSONとしてパース(JSONをオブジェクト形式に変換する。パースをしないと’userInfo.name’のような扱い方が出来ない)したオブジェクトでresolveされます。

HTTPレスポンスはレスポンスステータス、レスポンスヘッダー、レスポンスボディの構成になっていて欲しいデータはボディ(本文)に入っているのでjson()でパースします。
※ステータスはエラー処理の際に用います。

const userId = "xxxx";

fetch(`https://api.github.com/users/${userId}`)

  .then(response => response.json())

  .then(data => {

    console.log(data)

    console.log(`userName: ${data.name}`)

  })

  .catch((error) => console.log(error))

.then((response) => response.json())

ここでjsonメソッドを用いてresponseオブジェクトからJSON形式で返すように指定しています。
次のthenで繋いだdataには指定したJSON形式のUserに関する値が入っています。

以上が基本的なFetch APIの使い方です。

エラー処理

HTTP通信ではエラーが出る事があります。そんな時の為にエラーハンドリングをしっかりとする必要があります。
サーバーとの通信でネットワークのエラーが発生した場合にはrejectされたPromiseが返されます。
つまり、catchメソッドでネットワークエラーが拾えます。

const userId = "xxx";

fetch(`https://api.github.com/users/${userId}`)

  .then(response => {

    console.log(response.status)

    return response.json()

  })

  .then(data => {

    console.log(jsonData)

  })

  .catch(error => {

    console.log(`ネットワークエラー: ${error}`)

  })

fetchが成功したか

リクエストが成功したかを確認するにはResponseオブジェクトのもつOKプロパティを利用します。
上にあるFetch APIの使い方で張っている画像を見ればOKプロパティを持つ事が確認できます。
HTTPステータスコードが200番台であればtrueを返し、400や500番台であればfalseを返します。

const userId = "xxx";

fetch(`https://api.github.com/users/${userId}`)

  .then((response) => {

    console.log(response.status)

    if (!response.ok) {

      // リクエストが成功せずサーバーエラーを検知する

      console.log(`サーバーエラー: ${response}`)

    } else {

      return response.json()

    }
  })
  
  .then((jsonData) => {

    console.log(jsonData)

  })
  .catch((error) => {

    console.log(`ネットワークエラー: ${error}`)
  
  })

FetchでなくXMLHttpRequestを使う

冒頭で述べたとおり、Fetch APIが標準化される前はXMLHttpRequestが一般的に使用されていました。
詳しい使い方は割愛しますがFetch APIとの違いを確認するのに参考にしてみてください。
古いブラウザではFetch APIに対応していないケースがあるのでそういった時にXHRを使う場面があるかもしれません。

XHRの詳細について

https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
const userId = "xxx";
const request = new XMLHttpRequest();
request.open("GET", `https://api.github.com/users/${userId}`)
request.addEventListener('load', () => {
  // if分岐でリクエストが成功したかを判定する
  if (request.status >= 200 &amp;&amp; request.status < 300) {
    console.log(request.responseText)
    // fetchの場合はjson()だったがXHRではparseする 
    const data = JSON.parse(request.responseText);
    console.log(data)
  } else {
    console.log("サーバーエラー")
  }
});
request.addEventListener('error', () => {
  console.log("ネットワークエラー")
});
//リクエストを送信する
request.send()