JavaScript | 1 日 120 分 × 7 日アプリ学習:API通信アプリ(ExchangeRate.host)

APP JavaScript
スポンサーリンク

3日目のゴールと今日やること

3日目のテーマは
「通貨変換アプリを“使っていて気持ちいいツール”に進化させる」 ことです。

1日目でレート取得、2日目で金額変換までできるようになりました。
3日目では、アプリとしての完成度を一気に上げるために、次の機能を追加します。

  • 通貨の「逆変換」ボタン(USD→JPY を JPY→USD に一瞬で切り替える)
  • よく使う通貨ペアのプリセット(例:JPY→USD、USD→EUR)
  • 入力補助(from と to が同じなら自動で変えるなど)
  • fetch / async‑await / エラーハンドリングを“設計として整理”する

今日の内容は、初心者がつまずきやすい
「UI と API の連動」 を丁寧に解説していきます。


通貨変換アプリの現状を整理する

あなたのアプリはすでに、

  • 金額入力
  • from / to 通貨選択
  • ExchangeRate.host の /convert を fetch
  • async/await で待つ
  • try/catch でエラーを受け止める
  • ローディング表示
  • 通信失敗時の分岐
  • レートと変換結果の表示

という、API アプリの基本をすべて備えています。

3日目では、ここに「操作性の向上」を加えていきます。


通貨の「逆変換」ボタンを作る

なぜ必要なのか

ユーザーはよくこう思います。

「USD→JPY を見たあと、JPY→USD も見たい」

そのたびにプルダウンを両方変えるのは面倒です。
そこで 逆変換ボタン を作ります。

ボタンのイメージ

<button id="swapButton">⇄ 逆変換</button>

JavaScript 側で取得します。

const swapButton = document.getElementById("swapButton");
JavaScript

逆変換のロジックを作る

from と to を入れ替えるだけ

function swapCurrencies() {
  const from = fromSelect.value;
  const to = toSelect.value;

  fromSelect.value = to;
  toSelect.value = from;

  statusDiv.textContent = `${to}${from} に切り替えました。`;
}
JavaScript

イベント登録:

swapButton.addEventListener("click", swapCurrencies);
JavaScript

深掘りポイント

ここで大事なのは、

  • 「UI の状態を変えるだけ」
  • 「API は呼ばない」

という分離です。

ユーザーが「逆変換したあとに変換ボタンを押す」
という自然な流れを壊さないようにします。


よく使う通貨ペアのプリセットを作る

なぜプリセットが便利なのか

ユーザーは毎回同じ通貨ペアを使うことが多いです。

  • JPY → USD
  • USD → EUR
  • EUR → JPY

これをワンクリックでセットできると、
アプリの使い勝手が一気に上がります。

プリセットボタンのイメージ

<button class="preset" data-from="JPY" data-to="USD">JPY → USD</button>
<button class="preset" data-from="USD" data-to="EUR">USD → EUR</button>
<button class="preset" data-from="EUR" data-to="JPY">EUR → JPY</button>

JavaScript 側で取得します。

const presetButtons = document.querySelectorAll(".preset");
JavaScript

プリセットのロジック

data 属性を使って from / to をセットする

presetButtons.forEach((btn) => {
  btn.addEventListener("click", () => {
    const from = btn.dataset.from;
    const to = btn.dataset.to;

    fromSelect.value = from;
    toSelect.value = to;

    statusDiv.textContent = `${from}${to} を選択しました。`;
  });
});
JavaScript

深掘りポイント

data 属性を使うことで、

  • HTML 側でペアを定義
  • JS 側は「セットするだけ」

という責任分離ができます。

これは UI 設計の基本です。


入力補助:from と to が同じなら自動で変える

ユーザーがよくやるミス

  • from を JPY にした
  • to も JPY にした
  • 「あれ、変換できない…」

これを防ぐために、
同じ通貨が選ばれたら自動で変える
という補助を入れます。

ロジック

function autoFixSameCurrency() {
  if (fromSelect.value === toSelect.value) {
    // とりあえず USD に変えるなど
    toSelect.value = "USD";
    statusDiv.textContent = "同じ通貨が選ばれたため、変換先を USD に変更しました。";
  }
}
JavaScript

イベント登録:

fromSelect.addEventListener("change", autoFixSameCurrency);
toSelect.addEventListener("change", autoFixSameCurrency);
JavaScript

深掘りポイント

ユーザーが「間違えた」と感じる前に
アプリが先回りして修正してくれると、
使い心地が一気に良くなります。


fetch / async‑await / エラーハンドリングを“設計として整理”する

2日目までの convertCurrency を振り返る

2日目の convertCurrency は、
すでにかなり良い形になっています。

今日は、そこに「UI の改善」を加えます。


3日目版 convertCurrency(完成形)

async function convertCurrency() {
  const rawAmount = amountInput.value.trim();
  const from = fromSelect.value;
  const to = toSelect.value;

  if (from === to) {
    statusDiv.textContent = "異なる通貨を選択してください。";
    resultDiv.textContent = "";
    return;
  }

  const parsed = parseAmount(rawAmount);
  if (!parsed.ok) {
    statusDiv.textContent = parsed.message;
    resultDiv.textContent = "";
    return;
  }

  const amount = parsed.value;

  startLoading(`${amount} ${from}${to} に変換中です…`);
  resultDiv.textContent = "";

  try {
    const url =
      `https://api.exchangerate.host/convert` +
      `?from=${encodeURIComponent(from)}` +
      `&to=${encodeURIComponent(to)}` +
      `&amount=${encodeURIComponent(amount)}`;

    const response = await fetch(url);

    if (!response.ok) {
      if (response.status >= 500) {
        statusDiv.textContent = "サーバー側でエラーが発生しています。時間をおいて再試行してください。";
      } else {
        statusDiv.textContent = `サーバーエラーが発生しました。(${response.status})`;
      }
      return;
    }

    const data = await response.json();

    if (!data || data.success === false) {
      statusDiv.textContent = "レートの取得に失敗しました。";
      console.error("API error response:", data);
      return;
    }

    if (typeof data.result !== "number") {
      statusDiv.textContent = "予期しない形式のデータが返されました。";
      console.error("Unexpected data:", data);
      return;
    }

    statusDiv.textContent = "通貨変換に成功しました。";
    renderConversion(from, to, amount, data.result, data.info?.rate);

  } catch (error) {
    statusDiv.textContent = "通信に失敗しました。ネットワークを確認してください。";
    console.error(error);

  } finally {
    endLoading();
  }
}
JavaScript

重要ポイント1:try の中は「成功したときのストーリー」にする

try ブロックの中は、
できるだけ「うまくいったときの流れ」だけを書くようにします。

  • URL を組み立てる
  • fetch でレスポンスを取る
  • HTTP ステータスをチェック
  • JSON に変換
  • API の success をチェック
  • result の型をチェック
  • 表示する

失敗したときのことは、
HTTP エラーの if と catch に任せます。


重要ポイント2:エラーの“責任の場所”を意識する

エラーは種類ごとに責任を分けると、
コードが読みやすくなります。

入力エラー → parseAmount
HTTP エラー → response.ok
API レベルの失敗 → data.success
データ形式エラー → typeof data.result
ネットワークエラー → catch

この分担ができていると、
あとから読むときにとても楽です。


3日目のまとめ

今日あなたがやったことを整理すると、こうなります。

  • 通貨の逆変換ボタンを作った
  • よく使う通貨ペアのプリセットを作った
  • from と to が同じなら自動で修正する入力補助を入れた
  • fetch / async‑await / エラーハンドリングを「設計として整理」した
  • convertCurrency をストーリーとして読める形にした

どれも新しい文法ではなく、
「アプリとしての使いやすさを上げるための設計」 です。


今日いちばん深く理解してほしいこと

3日目の本質は、

「API アプリは、fetch のコードを増やすより、UI と入力の設計を整える方が大事」

ということです。

通貨変換アプリは、
fetch → await → JSON → 分岐 → UI
という“型”の上に成り立っています。

4日目では、このアプリに
状態管理(state)・お気に入り通貨ペア・localStorage 保存
などを加えて、さらに“毎日使えるツール”に育てていきます。

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