JavaScriptでAPI:外部データを取得してみよう!( API then)

完成イメージ

APIを使って、ボタンをクリックするたびに異なる画像をランダムに表示してみましょう。

今回のテーマ

JavaScript の fetch() を使って、外部からデータを読み込み、
そのデータを画面に表示する方法

目的

  • fetch() で外部APIにアクセスしてデータを取得する
  • .then() を使った非同期処理の流れを知る
  • APIから取得したJSONデータを .innerHTML などで表示する

作成ファイル・保存場所

js-domフォルダに以下のファイルを作成してください。

ファイル名内容
js-dom07.htmlボタンクリックの動作練習用HTML/js
js-dom__07.htmlステップアップ練習用HTML/js

JavaScriptは <script> タグ内に直接記述してください(内部JS)

チェックポイント

  • APIからJSON形式でデータを取得できているか?
  • 取得したデータをHTMLとして表示できているか?
  • ネットワークが失敗したときのエラー処理ができているか?

JavaScript基礎トレーニング1

猫画像を取得して表示する

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>APIで猫画像を表示しよう</title>
</head>
<body>
  <h1>ランダムな猫の画像を表示</h1>

  <p><button id="cat-btn">猫画像を取得する</button></p>

  <div id="cat-area">
    <!-- 猫の画像がここに表示されます -->
  </div>

  <script>
    const btn = document.getElementById('cat-btn');
    const catArea = document.getElementById('cat-area');

    btn.addEventListener('click', () => {
      fetch('https://api.thecatapi.com/v1/images/search')
        .then(response => response.json())
        .then(data => {
          console.log(JSON.stringify(data, null, 2));
          const imgUrl = data[0].url;
          catArea.innerHTML = `<img src="${imgUrl}" alt="猫の画像" width="300">`;
        })
        .catch(error => {
          catArea.textContent = '猫画像の取得に失敗しました。';
          console.error('エラー:', error);
        });
    });
  </script>
</body>
</html>

fetch のコードを分解して解説!

fetch('https://api.thecatapi.com/v1/images/search')

外部サービス(The Cat API)にアクセスして、猫の画像情報をください!とリクエストします。
fetch() は「データを取りに行く命令」です。下記のようにJavaScript のアロー関数の省略構文を使って書けます。

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

取得したデータ(response)を JSON形式(データのかたまり)に変換しています。
.json() は「データを読みやすい形に直すよ」という意味です。

.then(data => {
  const imgUrl = data[0].url;
  catArea.innerHTML = `<img src="${imgUrl}" alt="猫の画像" width="300">`;
})

.then() とは?

JavaScriptの fetch() や他の非同期処理では、「データが返ってくるまで少し時間がかかる」ことがあります。そのため、「終わったあとに〇〇をやってね!」という命令を .then() を使ってつなげて書きます。

fetch('URL')
  .then(response => response.json()) // ① JSONに変換
    const imgUrl = data[0].url;
    catArea.innerHTML = `<img src="${imgUrl}" alt="猫の画像" width="300">`;
  });

.then() を使うと「順番に処理していく」ことができます(これを「Promiseチェーン」といいます)。

このあとは、読み込んだデータ(data)から、猫画像のURLを取り出して画面に表示します。

  • data[0].url は、返ってきたデータの中の「1番目の画像のURL」
  • catArea.innerHTML = ... で、HTMLに <img> タグを入れて画像を表示します。
.catch(error => {
  catArea.textContent = '猫画像の取得に失敗しました。';
  console.error('エラー:', error);
});

最後は、もし画像の取得に失敗したら(ネットに繋がらないとか)、エラーメッセージを表示します。

  • .catch() は「失敗したときの処理」
  • console.error()エラーメッセージを赤文字でコンソールに出力するメソッドです
  • console.error() で出力すると、デベロッパーツールのコンソールで赤字表示され、デバッグしやすくなります。最短で、console.error(err);とも書きます。

同期処理と非同期処理の違い

APIを使うためには、非同期処理の理解が必須です。JavaScriptでは、命令は基本的に「上から順番に実行される(同期処理)」ように動きます。しかし、外部のデータを取りに行く処理(API通信など)はすぐには終わらないことが多いため、非同期処理(ひどうきしょり)として扱われます。

同期処理とは?

  • 上から順に、1つずつ命令を実行
  • 前の処理が終わるまで次に進めない
console.log("A");

console.log("B"); // ← AのあとにすぐBが出る

非同期処理とは?

  • 時間がかかる処理(API通信など)を「あとで」実行
  • JavaScriptは他の処理を止めずに先へ進める
  • 結果が返ってきたら、あらためてその処理を行う

なぜ非同期が必要なの?

  • APIからデータを取るのは1〜2秒かかることもある
  • その間に画面が止まると、ユーザーにとって不便
  • JavaScriptは「他のことをやりながら待つ」しくみを持っている

非同期を扱うための書き方

JavaScriptでは、非同期処理を扱うために以下のような書き方があります:

  • .then() を使った方法(Promiseチェーン)・・・軽量なAPI
  • async / await を使った方法(読みやすく実務向け)・・・時間がかかりそうなもの

非同期にする理由は「ユーザー体験を止めないため」順番を守るために .then()await を使います

種類処理の流れ特徴
同期処理完全に終わってから次へ進む安定だけど遅いと画面が止まる
非同期処理結果を待たずに次に進む画面が止まらないが順番は保証されない
非同期+制御.then()await で順番を指定順番が必要なときに便利

APIとは?

Application Programming Interface(アプリケーション プログラミング インターフェース)
の略です。簡単にいうと、他のサービスにお願いして、情報やデータをもらうためのしくみです。

  • API = 自動販売機(欲しいデータをリクエスト → データが返ってくる)
  • fetch() = ボタンを押す動作(商品を選ぶ)
  • JSON = 出てきた缶ジュース(形式化されたデータ)

の3つを使います。

JSONとは?

JSON(ジェイソン)とは、JavaScript Object Notation(ジャバスクリプト オブジェクト表記)の略で、データをやり取りするときの「決まった形(ルール)」です。

  • 文字列(テキスト)として受け取られる
  • JavaScriptの .json() で中身をオブジェクトとして使える形に変換できる
  • 配列(リスト)と組み合わせることで、たくさんのデータもやり取り可能

The Cat API(無料・認証不要でも使える)のエンドポイント

「猫の画像を表示したい!」と思ったとき、自分で画像を用意しなくても、
猫画像を配っているサイト(=API)にお願いすれば、代わりに送ってくれます。

https://api.thecatapi.com/v1/images/search

このURLにアクセスすると、ランダムな猫の画像が1枚返されます。
レスポンスはこんな感じのJSON

[
  {
    "id": "abc",
    "url": "https://cdn2.thecatapi.com/images/abc.jpg",
    "width": 800,
    "height": 600
  }
]

上記のJsonファイルの中の "url" を取り出して画像を表示することができたりします。

const imgUrl = data[0].url;

無料で使えるトランプ画像APIのエンドポイント

ランダムなトランプ1枚の画像URLを返してくれるAPI

https://deckofcardsapi.com/api/deck/new/draw/?count=1

レスポンスはこんな感じのJSONです

{
  "cards": [
    {
      "value": "7",
      "suit": "HEARTS",
      "image": "https://deckofcardsapi.com/static/img/7H.png"
    }
  ],
  ...
}

JavaScriptステップアップトレーニング

APIで取得したトランプのカードを表示させます。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>トランプカードを表示しよう</title>
</head>

<body>
    <h1>ランダムなトランプカード</h1>

    <p><button id="draw-btn">カードを引く</button></p>

    <div id="card-area">
        <!-- カード画像と情報が表示されます -->
    </div>

    <script>
        const btn = document.getElementById('draw-btn');
        const cardArea = document.getElementById('card-area');

        btn.addEventListener('click', () => {
            fetch('https://deckofcardsapi.com/api/deck/new/draw/?count=1')
                .then(res => res.json())
                .then(data => {
                    console.log(JSON.stringify(data, null, 2));
                    const card = data.cards[0];
                    const image = card.image;
                    const value = card.value;
                    const suit = card.suit;

                    cardArea.innerHTML = `
            <p>${suit}の${value} </p>
            <img src="${image}" alt="カード画像" width="200">
          `;
                })
                .catch(err => {
                    cardArea.textContent = 'カードの取得に失敗しました。';
                    console.error(err);
                });
        });
    </script>
</body>

</html>

ここまでで .then() を使ったAPI通信の基本が理解できました!

次は、非同期処理をより見やすく書ける async / await の書き方を学びましょう。

トランプカードをさらに応用!ハイアンドローゲームの作成

APIで取得したカードを使ってハイアンドローを作成してみましょう。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>ハイアンドローゲーム</title>
    <style>
        .area {
            display: flex;
            gap: 30px;
        }
    </style>
</head>

<body>
    <h1>ハイアンドローに挑戦!</h1>

    <div id="game-area">
        <div class="area">
            <div>
                <p>あなたのカード</p>
                <div id="player-card"></div>
            </div>
            <div>
                <p>相手のカード:</p>
                <div id="opponent-card"></div>
            </div>
        </div>
        <p>
            <button id="high-btn" disabled>HIGH(高い)</button>
            <button id="low-btn" disabled>LOW(低い)</button>
        </p>

        <p id="result"></p>

        <p><button id="start-btn">ゲームスタート</button></p>
    </div>

    <script>
        const startBtn = document.getElementById('start-btn');
        const highBtn = document.getElementById('high-btn');
        const lowBtn = document.getElementById('low-btn');
        const playerCardDiv = document.getElementById('player-card');
        const opponentCardDiv = document.getElementById('opponent-card');
        const resultP = document.getElementById('result');

        let playerValue = 0; // プレイヤーのカードの数値

        // カードのvalueを数値に変換
        function getCardValue(value) {
            if (value === 'ACE') return 1;
            if (value === 'JACK') return 11;
            if (value === 'QUEEN') return 12;
            if (value === 'KING') return 13;
            return Number(value);
        }

        // 最初のカードを引く(あなたのカード)
        function drawPlayerCard() {
            fetch('https://deckofcardsapi.com/api/deck/new/draw/?count=1')
                .then(res => res.json())
                .then(data => {
                    const card = data.cards[0];
                    playerValue = getCardValue(card.value);
                    playerCardDiv.innerHTML = `<img src="${card.image}" alt="${card.value} of ${card.suit}" width="100">`;
                    resultP.textContent = '';
                    opponentCardDiv.innerHTML = '';
                    highBtn.disabled = false;
                    lowBtn.disabled = false;
                });
        }

        // 次のカードを引いて結果判定
        function drawOpponentCard(guess) {
            fetch('https://deckofcardsapi.com/api/deck/new/draw/?count=1')
                .then(res => res.json())
                .then(data => {
                    const card = data.cards[0];
                    const opponentValue = getCardValue(card.value);
                    opponentCardDiv.innerHTML = `<img src="${card.image}" alt="${card.value} of ${card.suit}" width="100">`;

                    // 判定
                    if (
                        (guess === 'high' && opponentValue > playerValue) ||
                        (guess === 'low' && opponentValue < playerValue)
                    ) {
                        resultP.textContent = 'あなたの勝ち!';
                    } else if (opponentValue === playerValue) {
                        resultP.textContent = '引き分け(ノーカウント)';
                    } else {
                        resultP.textContent = 'あなたの負け';
                    }

                    highBtn.disabled = true;
                    lowBtn.disabled = true;
                });
        }

        // イベント設定
        startBtn.addEventListener('click', drawPlayerCard);
        highBtn.addEventListener('click', () => drawOpponentCard('high'));
        lowBtn.addEventListener('click', () => drawOpponentCard('low'));
    </script>
</body>

</html>

その他のAPI

スクロールできます
種類API名内容・できること利用形態備考
絵文字Emoji API(emoji-api.com など)Unicode絵文字の一覧、カテゴリ、コードなどを取得無料教材にも遊びにも使える
国情報REST Countries API各国の国名・首都・通貨・国旗・人口など無料表・検索・一覧表示の教材に向く
GitHubGitHub REST APIユーザー・リポジトリ・スター数などの情報無料(要APIキー)ポートフォリオと組み合わせるのも可
NASANASA Open API宇宙画像、火星探査データ、天体写真など無料(APIキー必要)天体系教材・英語APIの練習にも
音楽情報iTunes Search API曲名・アーティスト・アルバム画像など無料音楽再生ではなく情報取得専用
天気(別)WeatherAPI / OpenWeatherMap詳細な天気、週間予報、天気アイコンなど無料〜有料学習利用は無料枠で十分
地図検索Mapbox API地図の表示・経路探索・ピン立て有料(無料枠あり)Google Mapsの代替として人気

商品検索・EC系API 一覧

種類API名内容・できること利用形態備考
商品検索Amazon PA-API商品の画像・価格・説明・レビューなど無料(制限あり)Amazonアソシエイト登録が必須。紹介実績が必要。
商品検索Rakuten Ichiba API楽天市場の商品一覧・価格・画像など無料APIキー取得のみで利用可能。学習にも使いやすい。
商品検索Yahoo! Shopping API商品検索・ランキング・画像・価格など無料(要申請)Yahooデベロッパー登録が必要