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

APP JavaScript
スポンサーリンク

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

7日目のテーマは
「Datamuse API アプリを“中級編の完成形”としてまとめる」
ことです。

ここまで 6 日間であなたは、

  • fetch の基本と応用
  • async/await による読みやすい非同期処理
  • try-catch によるエラーハンドリング
  • サジェスト(sp=)
  • 履歴・お気に入り・localStorage 保存
  • 状態管理(state)
  • Promise.all による複数モード検索

といった、API アプリ開発の本質をすべて経験してきました。

7日目は、それらを 「ひとつの完成したアプリ」 として整理し、
fetch / async-await / エラーハンドリングの“型”を自分のものにします。


アプリ全体の構造を理解する

4つのレイヤーでアプリを整理する

Datamuse アプリは、次の 4 層で構成されています。

状態管理(state)

アプリの「現在の状態」をひとまとめにする場所。

const state = {
  isLoading: false,
  history: [],
  favorites: [],
  suggestions: []
};
JavaScript

API 通信(fetch / async-await)

Datamuse API にアクセスしてデータを取得する部分。

UI 更新(render 系)

検索結果・サジェスト・履歴・お気に入りを画面に表示する部分。

イベント処理(クリック・入力)

ユーザーの操作を受け取って処理を呼び出す部分。

この構造を意識すると、
「どこで何をしているか」 が一気に理解しやすくなります。


fetch / async-await / エラーハンドリングの“完成形”を作る

共通 fetch 関数を作る理由

fetch を使う場面は多いので、
毎回 try-catch を書くとコードが散らかります。

そこで、
fetch のエラー処理をひとつにまとめた関数
を作ります。

共通の JSON リクエスト関数

async function requestJson(url) {
  try {
    const response = await fetch(url);

    if (!response.ok) {
      if (response.status === 429) {
        throw new Error("リクエストが多すぎます。少し待ってから再試行してください。");
      }
      if (response.status >= 500) {
        throw new Error("サーバー側でエラーが発生しています。時間をおいて再試行してください。");
      }
      throw new Error(`HTTPエラー(${response.status})`);
    }

    const data = await response.json();
    return data;

  } catch (error) {
    throw new Error(error.message);
  }
}
JavaScript

深掘りポイント

この関数は、

  • fetch の失敗
  • HTTP エラー
  • JSON パースエラー

をすべて Error として上に投げる 役割を持っています。

これにより、
上位の関数は「成功したか・失敗したか」だけを扱えばよくなります。


Datamuse 専用の検索関数を作る

Datamuse の仕様チェックをここに集約する

async function searchDatamuse(word, mode) {
  const url = `https://api.datamuse.com/words?${mode}=${encodeURIComponent(word)}`;

  const data = await requestJson(url);

  if (!Array.isArray(data)) {
    throw new Error("予期しない形式のデータが返されました。");
  }

  if (data.length === 0) {
    throw new Error("該当する単語が見つかりませんでした。");
  }

  const sorted = [...data].sort((a, b) => (b.score || 0) - (a.score || 0));
  return sorted;
}
JavaScript

深掘りポイント

searchDatamuse
「Datamuse API の仕様を知っている唯一の関数」
です。

UI 側は Datamuse の細かい仕様を知らなくてよくなり、
コードが読みやすくなります。


UI 側の関数を「ストーリーとして読める」形にする

fetchWords の完成形(7日目版)

async function fetchWords() {
  const word = wordInput.value.trim();
  const mode = modeSelect.value;

  if (!word) {
    statusDiv.textContent = "単語を入力してください。";
    resultDiv.textContent = "";
    return;
  }

  const modeLabel = getModeLabel(mode);

  startLoading(`${modeLabel}を取得中です…`);
  resultDiv.textContent = "";

  try {
    const words = await searchDatamuse(word, mode);

    statusDiv.textContent = `${modeLabel}の取得に成功しました。`;
    renderWords(words, modeLabel);
    addHistory(word, mode);

  } catch (error) {
    statusDiv.textContent = `検索中にエラーが発生しました:${error.message}`;
    console.error(error);

  } finally {
    endLoading();
  }
}
JavaScript

深掘りポイント

この関数は、
「検索の流れをそのまま読める」
という設計になっています。

  • 入力チェック
  • ローディング開始
  • Datamuse に検索
  • 成功時の表示
  • 履歴追加
  • 失敗時のメッセージ
  • ローディング終了

fetch の細かい処理は
searchDatamuserequestJson に隠れているため、
とても読みやすくなっています。


複数モード検索を Promise.all で同時に行う

複数モード検索の関数

async function searchMultipleModes(word) {
  const promises = [
    searchDatamuse(word, "ml"),
    searchDatamuse(word, "rel_trg")
  ];

  const [similar, related] = await Promise.all(promises);

  return { similar, related };
}
JavaScript

深掘りポイント

Promise.all を使うと、

  • 並列で API を叩ける
  • 全部終わるまで待てる
  • 結果をまとめて扱える

というメリットがあります。


ローディング表示を「アプリ全体の状態」として扱う

state と連動させる

function startLoading(message) {
  updateState({ isLoading: true });
  statusDiv.textContent = message || "処理中です…";
  searchButton.disabled = true;
  multiButton.disabled = true;
}

function endLoading() {
  updateState({ isLoading: false });
  searchButton.disabled = false;
  multiButton.disabled = false;
}
JavaScript

深掘りポイント

複数モード検索でも、
単一検索でも、
ローディング表示が一貫して動く ようになります。


エラーハンドリングを「ユーザー目線」で整理する

エラーの種類を分類する

Datamuse アプリでは、次のようなエラーが起きます。

  • ネットワークエラー
  • HTTP エラー
  • JSON パースエラー
  • API の中身が想定外
  • 入力が空
  • モードが不正

これらをすべて
「ユーザーが理解できる言葉」
に変換します。

例:429(リクエスト過多)

throw new Error("リクエストが多すぎます。少し待ってから再試行してください。");
JavaScript

深掘りポイント

エラーメッセージは、
「技術的に正しい」より「ユーザーに伝わる」
ことが大事です。


Datamuse アプリの“完成形”をまとめる

7日目で完成したアプリの特徴

  • モード切り替え(類義語 / 連想語 / 韻)
  • サジェスト(sp=)
  • 履歴(クリックで再検索)
  • お気に入り(localStorage 保存)
  • 複数モード検索(Promise.all)
  • fetch の共通化(requestJson)
  • Datamuse 専用関数(searchDatamuse)
  • ローディング表示の統一
  • エラーハンドリングの整理

これはもう、
「実用的な語彙検索アプリ」
です。


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

7日目の本質は、

「API 通信アプリは、fetch・async/await・エラーハンドリングの“型”を作れば、あとは機能を積み上げるだけ」
ということです。

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