HTTP通信
ローカルサーバーでアプリケーションが実行できるようになったので、次はGitHubのAPIを呼び出す処理を実装していきます。 GitHubのAPIを呼び出すためにはHTTP通信をする必要があります。 ウェブブラウザ上でJavaScriptからHTTP通信するために、Fetch APIという機能を使います。
Fetch API
Fetch APIはHTTP通信を行ってリソースを取得するためのAPIです。 Fetch APIを使うことで、ページ全体を再読み込みすることなく指定したURLからデータを取得できます。 Fetch APIは同じくHTTP通信を扱うXMLHttpRequestと似たAPIですが、より強力で柔軟な操作が可能です。
リクエストを送信するためには、fetch
メソッドを利用します。
fetch
メソッドは引数で指定したURLに対して、HTTPリクエストを行えます。
GitHubにはユーザー情報を取得するAPIとして、https://api.github.com/users/GitHubユーザーID
というURLが用意されています。
GitHubのユーザーIDには、英数字と-
(ハイフン)以外は利用できないため、ユーザーIDはencodeURIComponent
関数を使ってエスケープしたものを結合します。encodeURIComponent
は/
や%
などURLとして特殊な意味を持つ文字列をただの文字列として扱えるようにエスケープする関数です。
次のコードでは、指定したGitHubユーザーIDの情報を取得するURLに対してfetch
メソッドで、GETのHTTPリクエストを行っています。
const userId = "任意のGitHubユーザーID";
fetch(`https://api.github.com/users/${encodeURIComponent(userId)}`);
レスポンスの受け取り
GitHubのAPIに対してHTTPリクエストを送信しましたが、まだレスポンスを受け取る処理を書いていません。 次はサーバーから返却されたレスポンスのログをコンソールに出力する処理を実装します。
fetch
メソッドはPromise
を返します。このPromise
インスタンスはリクエストのレスポンスを表すResponse
オブジェクトでresolveされます。
送信したリクエストにレスポンスが返却されると、then
コールバックが呼び出されます。
次のように、Response
オブジェクトのstatus
プロパティからは、HTTPレスポンスのステータスコードが取得できます。
また、Response
オブジェクトのjson
メソッドもPromise
を返します。これは、HTTPレスポンスボディをJSONとしてパースしたオブジェクトでresolveされます。
ここでは、書籍用に用意したjs-primer-example
というGitHubアカウントのユーザー情報を取得しています。
const userId = "js-primer-example";
fetch(`https://api.github.com/users/${encodeURIComponent(userId)}`)
.then(response => {
console.log(response.status); // => 200
return response.json().then(userInfo => {
// JSONパースされたオブジェクトが渡される
console.log(userInfo); // => {...}
});
});
エラーハンドリング
HTTP通信にはエラーがつきものです。
そのためFetch APIを使った通信においても、エラーをハンドリングする必要があります。
たとえば、サーバーとの通信に際してネットワークエラーが発生した場合は、ネットワークエラーを表すNetworkError
オブジェクトでrejectされたPromise
が返されます。
すなわち、then
メソッドの第二引数かcatch
メソッドのコールバック関数が呼び出されます。
const userId = "js-primer-example";
fetch(`https://api.github.com/users/${encodeURIComponent(userId)}`)
.then(response => {
console.log(response.status);
return response.json().then(userInfo => {
console.log(userInfo);
});
}).catch(error => {
console.error(error);
});
一方で、リクエストが成功したかどうかはResponse
オブジェクトのok
プロパティで認識できます。
ok
プロパティは、HTTPステータスコードが200番台であればtrue
を返し、それ以外の400や500番台などならfalse
を返します。
次のように、ok
プロパティがfalse
となるエラーレスポンスをハンドリングできます。
const userId = "js-primer-example";
fetch(`https://api.github.com/users/${encodeURIComponent(userId)}`)
.then(response => {
console.log(response.status);
// エラーレスポンスが返されたことを検知する
if (!response.ok) {
console.error("エラーレスポンス", response);
} else {
return response.json().then(userInfo => {
console.log(userInfo);
});
}
}).catch(error => {
console.error(error);
});
ここまでの内容をまとめ、GitHubからユーザー情報を取得する関数をfetchUserInfo
という名前で定義します。
function fetchUserInfo(userId) {
fetch(`https://api.github.com/users/${encodeURIComponent(userId)}`)
.then(response => {
console.log(response.status);
// エラーレスポンスが返されたことを検知する
if (!response.ok) {
console.error("エラーレスポンス", response);
} else {
return response.json().then(userInfo => {
console.log(userInfo);
});
}
}).catch(error => {
console.error(error);
});
}
index.jsでは関数を定義しているだけで、呼び出しは行っていません。
ページを読み込むたびにGitHubのAPIを呼び出すと、呼び出し回数の制限を超えるおそれがあります。 呼び出し回数の制限を超えると、APIからのレスポンスがステータスコード403のエラーになってしまいます。
そのため、HTMLドキュメント側に手動でfetchUserInfo
関数を呼び出すためのボタンを追加します。
ボタンのclickイベントでfetchUserInfo
関数を呼び出し、取得したいユーザーIDを引数として与えています。
例としてjs-primer-example
という書籍用に用意したGitHubアカウントを指定しています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>Ajax Example</title>
</head>
<body>
<h2>GitHub User Info</h2>
<button onclick="fetchUserInfo('js-primer-example');">Get user info</button>
<script src="index.js"></script>
</body>
</html>
準備ができたら、ローカルサーバーを立ち上げてindex.htmlにアクセスしましょう。 ボタンを押すとHTTP通信が行われ、コンソールにステータスコードとレスポンスのログが出力されます。
また、開発者ツールのネットワークパネルを開くと、GitHubのサーバーに対してHTTP通信が行われていることを確認できます。
[コラム] XMLHttpRequest
XMLHttpRequest(XHR)はFetch APIと同じくHTTP通信を行うためのAPIです。
Fetch APIが標準化される以前は、ブラウザとサーバーの間で通信するにはXHRを使うのが一般的でした。
このセクションで扱ったFetch APIによるfetchUserInfo
関数は、XHRを使うと次のように書けます。
function fetchUserInfo(userId) {
// リクエストを作成する
const request = new XMLHttpRequest();
request.open("GET", `https://api.github.com/users/${encodeURIComponent(userId)}`);
request.addEventListener("load", () => {
// リクエストが成功したかを判定する
// Fetch APIのresponse.okと同等の意味
if (request.status >= 200 && request.status < 300) {
// レスポンス文字列をJSONオブジェクトにパースする
const userInfo = JSON.parse(request.responseText);
console.log(userInfo);
} else {
console.error("エラーレスポンス", request.statusText);
}
});
request.addEventListener("error", () => {
console.error("ネットワークエラー");
});
// リクエストを送信する
request.send();
}
Fetch APIはXHRを置き換えるために作られたもので、ほとんどのユースケースではXHRを使う必要はなくなりました。 また、古いブラウザではFetch APIが実装されていなかったため、ブラウザの互換性を保つためにXHRが使われている場面もありました。 XHRの詳しい使い方については、XHRの利用についてのドキュメントを参照してください。
このセクションのチェックリスト
- Fetch APIを使ってHTTPリクエストを送った
- GitHubのAPIから取得したユーザー情報のJSONオブジェクトをコンソールに出力した
- Fetch APIの呼び出しに対するエラーハンドリングを行った
fetchUserInfo
関数を宣言し、ボタンのクリックイベントで呼び出した
ここまでのアプリは次のURLで確認できます。