JavaScriptのきほん(15)「外部データを取得しよう(1)fetchでJSONを読み込む」

スポンサーリンク
JavaScript

これまでの記事では、ToDoリストの内容をフォームから自分で入力してきた。
今回からは、Webサーバーが公開しているデータをJavaScriptで取得し、画面に表示する方法を3回に分けて扱う。初回はfetchの基本を押さえよう。

1. fetchとは

fetch()は、指定したURLにリクエストを送り、返ってきたデータを受け取るための関数である。
通信には時間がかかるため、fetch()は結果そのものではなく「あとで結果が届く約束」を表すPromiseを返す。結果が届いたときに実行する処理は、.then()で続けて書く。

流れは次のとおりである。

  1. fetch(URL)でデータを要求する
  2. 届いた応答(response)をresponse.json()でJavaScriptのデータに変換する
  3. 変換後のデータを使って画面に表示する

2. 今回使うデータ

練習用のデータとして、JSONPlaceholder(https://jsonplaceholder.typicode.com)を使う。これは、プログラミングの学習や動作テストのために公開されている、無料のダミーデータ提供サービスである。ToDo、投稿、ユーザーなどのサンプルが用意されていて、どれも架空の内容である。個人情報や本物のデータは含まれていない。ToDoは200件あり、公式サイトでも、今回と同じ形のfetchのコードが使い方の例として紹介されている。

ネットから取得すると聞くと不安に感じられるかもしれないが、今回受け取るのは、文字で書かれたJSON形式のデータである。プログラムのファイルをダウンロードして実行するわけではない。response.json()は、受け取った文字をJavaScriptのデータとして読み取るもので、プログラムとして動かすことはない。また、こちらから個人情報などを送ることはなく、データを取得するのみである。

ただし、外部から届いた文字列を無条件に信用しないのは、情報セキュリティマネジメントとして大切である。この点は5節で触れる。
今回は、ToDoのデータを5件だけ取得する。次のURLを使う。

https://jsonplaceholder.typicode.com/todos?_limit=5

末尾の?_limit=5は、取得する件数を5件に絞る指定である。

1件のデータは、次のような形をしている。

{ "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false }

titleがタスクの内容、completedが完了済みかどうかを表す。前回のToDoリストに近い構造である。なお、titleの文はダミーである(6節で説明)。

3. index.html

まず、デスクトップにJSpracticeという名前のフォルダを作成しよう。そのフォルダの中に、次の内容でindex.htmlを作成しよう。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>外部データを取得しよう</title>
</head>
<body>
  <h1>外部のToDoデータ</h1>
  <p id="message"></p>
  <ul id="todo-list"></ul>
  <script src="script.js"></script>
</body>
</html>

保存するときは、文字コードをUTF-8にしておこう。ANSI(Shift_JIS)のまま保存すると、日本語が文字化けする。
メモ帳では、「名前を付けて保存」を選ぶとポップアップするウィンドウの下の方で、エンコードを選択できる。

エディタから文字コードに関する警告が出たら、そのまま保存せず、UTF-8を指定して保存しなおそう。この注意は、次のscript.jsでも同じである。
なお、本記事ではメモ帳で紹介しているが、学習を続ける場合には、サクラエディタなどの高機能なテキストエディタをおすすめしたい。

サクラエディタ

4. script.js

同じJSpracticeフォルダの中にscript.jsを作成し、次のコードを記述する。

const API_URL = 'https://jsonplaceholder.typicode.com/todos?_limit=5';
const list = document.getElementById('todo-list');
const message = document.getElementById('message');

message.textContent = '読み込み中...';

fetch(API_URL)
  .then((response) => response.json())
  .then((todos) => {
    console.log(todos);
    message.textContent = '';

    todos.forEach((todo) => {
      const li = document.createElement('li');
      li.textContent = (todo.completed ? '✅ ' : '⬜ ') + todo.title;
      list.appendChild(li);
    });
  });

5. コードの解説

fetch(API_URL)が通信を開始し、その結果を.then()で受け取っている。.then()が2つ続いているのは、段階が2つあるためである。

1つ目の.then()では、届いたresponseをresponse.json()でJavaScriptの配列に変換している。この変換にも時間がかかるため、response.json()もまたPromiseを返す。2つ目の.then()は、その変換が終わったあとに実行され、受け取ったtodosが5件のタスクを持つ配列になっている。

あとは、これまでのToDoリストと同じ要領である。forEachで1件ずつ取り出し、createElementでliを作り、appendChildでリストに追加している。完了状態は三項演算子で記号を切り替えた。
今回は外部から届いた文字列を表示するため、innerHTMLではなくtextContentを使っている。文字列をHTMLとして解釈させないので、より安全である。

コードの冒頭にあるmessage.textContent = '読み込み中...'は、通信が終わるまでの間の表示である。データが届いたら、message.textContent = ''で消している。

console.log(todos)は、届いたデータの中身を確かめるための一行である。ブラウザでF12キーを押し、「コンソール」タブを開くと、5件分のデータが確認できる。

6. 動作確認とまとめ

index.htmlをブラウザで開いてみよう。一瞬「読み込み中…」と表示されたあと(通信が速い場合は「読み込み中…」の表示はほとんど見えない)、5件のタスクがリストになって現れれば成功である。

なお、並んでいるdelectus aut autemのような文は、外国語に見えるが意味はない。
JSONPlaceholderが用意している「ロレム・イプサム」というラテン語風のダミー文である。

今回のポイントは次の3点である。

  • fetch()はPromiseを返し、結果は.then()で受け取る
  • response.json()でJSONをJavaScriptのデータに変換する
  • 変換後のデータは、配列としてこれまでと同じように扱える

ところで、.then()を2つ続ける書き方は、処理が増えるほど読みにくくなっていく。
次回は、async/awaitという書き方に整理しなおし、取得する件数を選べる機能も加えてみよう。通信に失敗した場合の備えは、第3回で扱う。

コメント

タイトルとURLをコピーしました