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

APP JavaScript
スポンサーリンク

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

1日目のテーマは
「ExchangeRate.host API を使って“シンプルな通貨レート取得アプリ”を作りながら、fetch / async‑await / エラーハンドリングの基本パターンを体で覚える」
ことです。

やることはとてもシンプルです。

ある通貨(例:JPY)から別の通貨(例:USD)のレートを
ExchangeRate.host から取得して画面に表示する。
その途中で、ローディング表示と、通信失敗時の分岐もきちんと入れる。

今日のキーワードはこの 3 つです。

fetch
Promise / async‑await
エラーハンドリング(try / catch)

これを「為替レートアプリ」という具体的な形に落とし込んでいきます。


ExchangeRate.host API をざっくり理解する

どんな API なのか

ExchangeRate.host は、為替レートを取得できる無料の API です。
「この通貨からあの通貨へのレートを教えて」と聞くことができます。

例えば、
JPY から USD へのレートを知りたいときは、こんな URL になります。

https://api.exchangerate.host/convert?from=JPY&to=USD

EUR から JPY ならこうです。

https://api.exchangerate.host/convert?from=EUR&to=JPY

返ってくるのは JSON で、イメージとしてはこんな感じです。

{
  "success": true,
  "query": {
    "from": "JPY",
    "to": "USD",
    "amount": 1
  },
  "info": {
    "rate": 0.0068
  },
  "result": 0.0068
}

ここで重要なのは、
resultinfo.rate に「レート」が入っている、ということです。

今日はまず、
「1 JPY が何 USD か」を取得して表示するところから始めます。


fetch をかみ砕いて理解する

fetch は「ブラウザに API へ行ってきて」と頼む関数

JavaScript の fetch は、
「この URL にアクセスして、結果を持ってきて」とブラウザにお願いする関数です。

例えばこう書きます。

fetch("https://api.exchangerate.host/convert?from=JPY&to=USD");
JavaScript

ただし、fetch はすぐに結果そのものを返しません。
返してくるのは Promise(未来の結果が入る箱) です。

「今はまだ結果がないけど、そのうち入るよ」という感じです。


async / await で「待つ」コードを書く

then だらけになるのを避ける

Promise は then でつなげて書くこともできますが、
ネストが深くなって読みづらくなりがちです。

そこで使うのが async / await です。

async function getRate() {
  const response = await fetch("https://api.exchangerate.host/convert?from=JPY&to=USD");
  const data = await response.json();
  console.log(data);
}
JavaScript

ここでのポイントははっきりしています。

関数に async を付けると、中で await が使える。
await fetch(...) は「fetch が終わるまで待つ」。
await response.json() は「JSON に変換されるまで待つ」。

見た目は「普通の順番のコード」なのに、
中身はちゃんと非同期処理になっている、というのが強みです。


エラーハンドリングの基本:try / catch

なぜエラーハンドリングが必要なのか

API 通信では、いろんな失敗が起こり得ます。

ネットが切れている。
サーバーが落ちている。
URL を間違えた。
サーバーがエラーを返している。
JSON の形式が想定外。

これらを放置すると、
ユーザーには「何も起きない」「真っ白」のように見えてしまいます。

そこで使うのが try / catch です。

try {
  // うまくいくかもしれない処理
} catch (error) {
  // 失敗したときにやる処理
}
JavaScript

これを async / await と組み合わせると、
「失敗したときに、ちゃんとメッセージを出す」
という優しいアプリになります。


今日作るミニアプリのイメージ

機能のイメージ

1日目は、こんな最小構成のアプリを目指します。

「基準通貨(from)」を選ぶ(例:JPY)。
「変換先通貨(to)」を選ぶ(例:USD)。
「レート取得」ボタンを押す。
ExchangeRate.host からレートを取得する。
ローディング表示を出す。
通信失敗時にメッセージを出す。

これだけで、
API 通信アプリの基本パターンが全部入っています。


HTML のイメージ(頭の中で想像できればOK)

例えば、こんな構成を想像してください。

<select id="fromSelect">
  <option value="JPY">JPY</option>
  <option value="USD">USD</option>
  <option value="EUR">EUR</option>
</select>

<select id="toSelect">
  <option value="USD">USD</option>
  <option value="JPY">JPY</option>
  <option value="EUR">EUR</option>
</select>

<button id="fetchButton">レート取得</button>

<div id="status"></div>
<div id="result"></div>

JavaScript では、これらの要素を取得して使います。

const fromSelect = document.getElementById("fromSelect");
const toSelect = document.getElementById("toSelect");
const fetchButton = document.getElementById("fetchButton");
const statusDiv = document.getElementById("status");
const resultDiv = document.getElementById("result");
JavaScript

ここまではウォーミングアップです。
ここからが本番です。


ローディング表示の基本パターン

「今なにしてるか」を伝える UI

API 通信は、数百ミリ秒〜数秒かかることがあります。
その間、ユーザーは「固まった?」と不安になります。

だから、

「取得中です…」と表示する。
ボタンを無効化して連打を防ぐ。

という UI が大事になります。

function startLoading(message) {
  statusDiv.textContent = message || "取得中です…";
  fetchButton.disabled = true;
}

function endLoading() {
  fetchButton.disabled = false;
}
JavaScript

この 2 つの関数を用意しておくと、
どの API 通信でも同じパターンで使い回せます。


ExchangeRate.host からレートを取得する関数(1日目の完成形)

ここが今日のメインです。
fetch / async / await / try / catch / ローディング / エラー分岐
が全部入った関数を書きます。

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

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

  startLoading(`${from}${to} のレートを取得中です…`);
  resultDiv.textContent = "";

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

    if (!response.ok) {
      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 = "レートの取得に成功しました。";
    renderRate(from, to, data.result);

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

  } finally {
    endLoading();
  }
}
JavaScript

ここをひとつずつ分解していきます。


重要ポイント1:入力チェックは最初に弾く

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

ここで「同じ通貨同士なら API を叩かない」という判断をしています。

これは、

無駄な通信をしない。
エラーではなく「入力の問題」として早めに伝える。

という意味で、とても大事です。


重要ポイント2:response.ok で HTTP エラーを見分ける

if (!response.ok) {
  statusDiv.textContent = `サーバーエラーが発生しました。(${response.status})`;
  return;
}
JavaScript

response.ok は、ステータスコードが 200〜299 のときに true になります。
404 や 500 のときは false です。

ここで「サーバー側の問題」を検知して、
ユーザーに伝えています。


重要ポイント3:API 独自の success フラグをチェックする

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

ExchangeRate.host は、
success というフラグを持っていることがあります。

HTTP 的には成功(200)でも、
API の内部的には失敗、というケースもあり得ます。

ここで、

HTTP レベルの成功と、
API レベルの成功を分けてチェックしているのがポイントです。


重要ポイント4:型チェックで「おかしなデータ」を弾く

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

レートは数値であるべきです。
もし文字列や null が入っていたら、それは想定外です。

ここで型チェックをしておくと、

「なんか NaN が出た」
「計算したらおかしな値になった」

といったバグを早めに検知できます。


重要ポイント5:catch では「ユーザー向け」と「開発者向け」を分ける

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

ここで、

画面には「通信に失敗しました。ネットワークを確認してください。」
コンソールには error の詳細。

というふうに、
ユーザーと開発者で出す情報を分けています。

error.message をそのままユーザーに見せると、
英語の長文や技術用語が出てきて、逆に不親切になることが多いです。


レートを画面に表示する

シンプルな表示関数

function renderRate(from, to, rate) {
  const html = `
    <h3>為替レート</h3>
    <p>1 ${from} = ${rate} ${to}</p>
  `;
  resultDiv.innerHTML = html;
}
JavaScript

ここでは、

「1 JPY = 0.0068 USD」
のような形で表示しています。

この関数は「表示にだけ責任を持つ」ようにしておくと、
あとでデザインを変えたくなったときに楽です。


ボタンにイベントをつなぐ

fetchButton.addEventListener("click", fetchRate);
JavaScript

これで、

ボタンを押す。
fetchRate が呼ばれる。
ローディング開始。
API から取得。
成功 or 失敗で分岐。
ローディング終了。

という一連の流れが完成します。


1日目のまとめ

今日あなたがやったことを、言葉で整理してみます。

ExchangeRate.host の基本的なエンドポイント(convert)を理解した。
fetch で API にアクセスする基本形を知った。
async / await で「待つ」コードを書いた。
try / catch でエラーを受け止めた。
response.ok で HTTP エラーを判定した。
API 独自の success フラグをチェックした。
result の型(number)をチェックして、想定外のデータを弾いた。
ローディング表示(startLoading / endLoading)を入れた。
通信失敗時に「ユーザー向けの日本語メッセージ」を出した。

これらは、どんな API アプリでも共通する“型”です。


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

1日目の本質は、

「API 通信は、fetch → await → JSON → 分岐 → UI という一本の流れでできている」

ということです。

Nager.Date だろうが、ExchangeRate.host だろうが、
天気 API だろうが、翻訳 API だろうが、
この流れは変わりません。

ここを一度、自分の手で書いてみたあなたは、
もう「API ってなんか怖い」から一歩抜けています。

2日目では、この為替レートアプリに

金額入力(例:1000 JPY → 何 USD?)
入力チェック
ローディング表示の改善
エラーメッセージの整理

などを足して、
「ちゃんと使える通貨変換ツール」に近づけていきます。

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