HTTP通信

アプリケーションが実行できるようになったので、次はGitHubのAPIを呼び出す処理を実装していきます。 当然ですが、GitHubのAPIを呼び出すためにはHTTP通信をする必要があります。 ウェブブラウザ上でJavaScriptからHTTP通信するために、Fetch APIという機能を使います。

Fetch API

Fetch APIはHTTP通信を行いリソースを取得するためのAPIです Fetch APIを使うことで、ページ全体を再読み込みすることなく指定したURLからデータを取得できます。 Fetch APIは同じくHTTP通信を扱うXMLHttpRequestと似たAPIですが、より強力で柔軟な操作が可能です。

GitHubが提供している、ユーザー情報を取得するためのWebAPIを呼び出すコードは次のようになります。 リクエストを送信するためには、グローバルスコープのfetchメソッドを呼び出します。 fetchメソッドにURLを与えることで、HTTPリクエストが作成され、サーバーとのHTTP通信を開始します。

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

レスポンスの受け取り

GitHubのAPIに対してHTTPリクエストを送信しましたが、まだレスポンスを受け取る処理を書いていません。 次はサーバーから返却されたレスポンスのログをコンソールに出力する処理を実装します。

fetchメソッドはPromiseを返します。これはリクエストのレスポンスを表すResponseオブジェクトでresolveされます。 送信したリクエストにレスポンスが返却されると、thenコールバックが呼び出されます。 次のように、ResponseオブジェクトのstatusプロパティからはHTTPレスポンスのステータスコードが取得できます。 また、jsonメソッドもPromiseを返します。これは HTTPレスポンスをJSONとしてパースしたオブジェクトでresolveされます。

fetch(`https://api.github.com/users/${userId}`)
    .then(response => {
        console.log(response.status); // => 200
        response.json().then(userInfo => {
            // JSONパースされたオブジェクトが渡される
            console.log(userInfo); // => {...}
        });
    });

エラーハンドリング

HTTP通信にはエラーがつきものです。 そのためFetch APIを使った通信においても、エラーをハンドリングする必要があります。 サーバーとの通信に際してネットワークエラーが発生した場合は、ネットワークエラーを表すNetworkErrorオブジェクトでrejectされたPromiseが返されます。 すなわち、thenメソッドの第2引数かcatchメソッドのコールバック関数が呼び出されます。

fetch(`https://api.github.com/users/${userId}`)
    .then(response => {
        console.log(response.status);
        response.json().then(userInfo => {
            console.log(userInfo);
        });
    }).catch(error => {
        console.error("ネットワークエラー", error);
    });

一方で、リクエストが成功したかどうかはResponseオブジェクトのokプロパティで認識できます。 okプロパティは、HTTPステータスコードが200番台であればtrueを返し、400や500番台であればfalseを返します。 次のように、okプロパティがfalseであるサーバーエラーをハンドリングできます。

fetch(`https://api.github.com/users/${userId}`)
    .then(response => {
        console.log(response.status); 
        // エラーレスポンスが返されたことを検知する
        if (!response.ok) {
            console.error("サーバーエラー", response);
        } else {
            response.json().then(userInfo => {
                console.log(userInfo);
            });
        }
    }).catch(error => {
        console.error("ネットワークエラー", error);
    });

ここまでの内容をまとめ、GitHubからユーザー情報を取得する関数をgetUserInfoという名前で定義します。

function getUserInfo(userId) {
    fetch(`https://api.github.com/users/${userId}`)
        .then(response => {
            console.log(response.status);
            // エラーレスポンスが返されたことを検知する
            if (!response.ok) {
                console.error("サーバーエラー", response);
            } else {
                response.json().then(userInfo => {
                    console.log(userInfo);
                });
            }
        }).catch(error => {
            console.error("ネットワークエラー", error);
        });
}

index.jsでは関数を定義しているだけで、呼び出しは行っていません。 ページを読み込むたびにGitHubのAPIを呼び出すと、呼び出し回数の制限を超えるおそれがあります。 呼び出し回数の制限を超えると、APIからのレスポンスがステータスコード403のサーバーエラーになってしまいます。 そこでgetUserInfo関数を呼び出すため、HTMLドキュメント側にボタンを追加します。 ボタンのclickイベントでgetUserInfo関数を呼び出し、固定のユーザーIDを引数として与えています。

<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>Ajax Example</title>
  </head>
  <body>
    <h2>GitHub User Info</h2>

    <button onclick="getUserInfo('js-primer-example');">Get user info</button>
    <script src="index.js"></script>
  </body>
</html>

準備ができたら、ローカルサーバーを立ち上げてindex.htmlにアクセスしましょう。 ボタンを押すとHTTP通信が行われ、コンソールにステータスコードとレスポンスのログが出力されます。

Fetchで取得したデータの表示

また、開発者ツールのネットワーク画面を開くと、確かにGitHubのサーバーに対してHTTP通信が行われていることを確認できます。

開発者ツールでHTTP通信の記録を確認する