基礎から学ぶJavaScript入門 90日コース | 非同期処理とAPI - Day 69:APIアプリ改善

JavaScript 90日で身につけるJavaScript
スポンサーリンク
スポンサーリンク

Day 69:APIアプリ改善

Day 69では、第5フェーズ「非同期処理とAPI」の仕上げに向けて、これまで作ってきたAPIアプリを改善していきます。今回の改善内容は、UI改善、エラー処理、コード整理 の3つです。Day 64からDay 68にかけて、検索アプリやフィルター機能付き一覧表示アプリを作り、APIからデータを取得し、画面に表示し、条件に応じて表示を更新するところまで学んできました。ここまでで、アプリは「動く」状態になっています。しかし、動くことと、使いやすく、壊れにくく、読みやすいことは同じではありません。Day 69では、その差を埋めていきます。

初心者の方にとって、このDay 69はとても重要です。なぜなら、ここで初めて「機能を追加する」ことよりも、「すでにあるアプリを良くする」ことに意識を向けるからです。プログラミング学習の初期では、新しい機能を作ることに意識が向きやすいですし、それは自然なことです。しかし実際の開発では、最初の完成版を出したあとに、使いにくさを直したり、エラーへの強さを増したり、コードを整理して読みやすくしたりする作業がとても大切です。むしろ、その改善力こそが実践的な開発力に近いとも言えます。

今回のポイントは、「見た目を少し変える」だけではありません。UI改善では、ユーザーが迷わない表示や操作感を目指します。エラー処理では、失敗したときでも状態がわかるようにします。コード整理では、機能はそのままでも、読みやすく修正しやすい構造へ整えます。つまり、Day 69は「アプリを動かす回」ではなく、「アプリを育てる回」です。初心者の方は、今回の内容を通して、「良いプログラムとは何か」を少し広い視点で考えられるようになります。今回も、ステップバイステップで、例題・コード・テンプレートを交えながら、丁寧に解説していきます。

まず最初に結論をつかむ

最初に今回の内容を一言でまとめると、Day 69では「すでに動いているAPIアプリを、より使いやすく、失敗に強く、読みやすい形に整えること」を学びます。

今回の改善は大きく分けて次の3つです。

  • UI改善:見やすさと操作しやすさを高める
  • エラー処理:失敗時の案内をわかりやすくする
  • コード整理:役割ごとに分けて読みやすくする

初心者の方は、今回のテーマを「新機能追加」ではなく「完成度アップ」だと考えると理解しやすいです。

なぜアプリ改善が必要なのか

ここはDay 69の中心です。なぜアプリ改善が必要なのかというと、最初に動いたアプリは、多くの場合「最低限動く」だけであって、「使いやすい」「安全」「読みやすい」状態とは限らないからです。

たとえば、次のような問題はよくあります。

  • 検索中なのか完了したのかわかりにくい
  • 0件なのかエラーなのか区別しづらい
  • 画面の情報が散らばっていて見づらい
  • 同じような処理が何度も書かれている
  • コードが長くなり、どこを直せばよいかわかりにくい

初心者の方は、「動けば終わり」ではなく、「より良くできる部分はないか」を考えることが、次のステップにつながると理解すると大きな成長になります。

今回の改善対象を決める

Day 69では、前回のDay 68で作った「API取得+検索+フィルター+表示更新」のアプリを改善する前提で進めます。つまり、すでに次のような機能はある状態です。

  • APIからユーザー一覧を取得する
  • 名前で検索できる
  • 会社名の条件でフィルターできる
  • 結果一覧を表示できる

このアプリに対して、「見やすさ」「失敗時の対応」「コードの整理」を加えていきます。初心者の方は、何もないところから新しく作るのではなく、「今あるものを少しずつ磨く」という姿勢で読むと理解しやすいです。

UI改善とは何か

まずUI改善です。UIとは、User Interface の略で、ユーザーが見る画面や触れる部品のことです。入力欄、ボタン、メッセージ、一覧表示、余白、色の違いなどもすべてUIに含まれます。

初心者の方は、UI改善というと見た目の装飾だけを想像しがちですが、本質は「使いやすさの改善」です。たとえば、検索欄が狭すぎて入力しにくい、結果が詰まりすぎて読みにくい、エラーメッセージが普通の文章と区別しづらい、といったものを直していくのがUI改善です。

UI改善で最初に見るべきポイント

UI改善では、次の観点で見ると整理しやすいです。

  • 入力しやすいか
  • 現在の状態がわかるか
  • 結果が読みやすいか
  • エラーや0件が区別しやすいか
  • 画面全体に余白やまとまりがあるか

初心者の方は、「きれいかどうか」よりも、「迷わず使えるかどうか」に注目すると、改善の方向が見えやすくなります。

例1:入力欄と結果表示を見やすくする

たとえば、入力欄やセレクトボックスに余白を入れたり、結果一覧をカード風にしたりするだけでも、かなり見やすくなります。

<input type="text" id="keywordInput" placeholder="名前で検索">
<select id="companyFilter">
  <option value="">すべての会社</option>
  <option value="C">Cで始まる会社</option>
  <option value="R">Rで始まる会社</option>
</select>
input, select {
  padding: 8px;
  margin-right: 8px;
  margin-bottom: 12px;
}

.user-item {
  padding: 10px;
  margin-bottom: 8px;
  border: 1px solid #ccc;
  border-radius: 6px;
}

初心者の方は、「少しの余白と区切りだけでも、見やすさが大きく変わる」と体験できるとよいです。

例2:状態ごとのメッセージを見分けやすくする

検索中、エラー、通常メッセージがすべて同じ見た目だと、何が起きているかわかりにくいです。そこで、状態に応じて色やクラスを変える方法が役立ちます。

.error {
  color: red;
}

.success {
  color: green;
}

.loading {
  color: blue;
}

このようにクラスを切り替えると、ユーザーにとって状態が伝わりやすくなります。初心者の方は、「文字の内容だけでなく見た目でも状態を伝える」と理解すると、UI設計の感覚が育ちます。

エラー処理改善とは何か

次にエラー処理改善です。Day 63でもエラー処理を学びましたが、Day 69ではさらに「使う人にとってわかりやすいか」「コードとして扱いやすいか」という視点で見直します。

初心者の方は、エラー処理というと try...catch を書くだけで終わりだと思いがちです。しかし実際には、次のようなことも大切です。

  • エラー時に前回の結果を残すのか消すのか
  • ユーザーへどんな文章で伝えるか
  • ローディング表示を確実に戻すか
  • エラー状態を見た目でも区別できるか

つまり、エラー処理は「失敗を受け止める」だけでなく、「失敗後の画面を整える」ことまで含みます。

エラー時に特に注意したいこと

ここはかなり重要です。エラーが起きたときに、前回の成功結果がそのまま残っていると、ユーザーは「今の結果なのか前の結果なのか」がわからなくなることがあります。そのため、失敗時には結果一覧を空にするのも1つの考え方です。

resultList.innerHTML = "";
message.textContent = "データの取得に失敗しました。時間をおいて再試行してください。";
message.className = "error";
JavaScript

初心者の方は、「エラーメッセージを出すだけ」で終わらず、「画面全体として今の状態が正しく見えるか」を考えると一段上の設計になります。

コード整理とは何か

次にコード整理です。これは、動作を変えずに、コードを読みやすく、直しやすく、再利用しやすくすることです。初心者の方は、コード整理というと難しく感じるかもしれませんが、本質は「役割ごとに分けること」です。

たとえば、次のように整理できます。

  • データ取得担当の関数
  • 表示担当の関数
  • 検索・フィルター担当の関数
  • メッセージ表示担当の関数

こうしておくと、「表示だけ変えたい」「検索条件だけ変えたい」といったときに、修正場所がすぐわかるようになります。

悪い例と改善の考え方

たとえば、1つの関数の中に、取得・検索・フィルター・表示・メッセージ変更・エラー処理が全部詰め込まれていると、かなり読みにくくなります。

悪い方向のイメージは、次のようなものです。

  • 1つの関数が長すぎる
  • 同じ処理を何度も書いている
  • 変数名があいまいで役割がわかりにくい
  • どこで画面更新しているのか見えにくい

初心者の方は、コード整理を「頭の中の整理をコードに反映すること」と考えるとわかりやすいです。

ステップ1:メッセージ表示を関数化する

まずは小さな整理から始めます。メッセージ表示を何度も直接書くのではなく、関数にまとめます。

function setMessage(text, className = "") {
  message.textContent = text;
  message.className = className;
}
JavaScript

こうしておくと、次のように書けます。

setMessage("データを読み込み中です...", "loading");
setMessage("3件のユーザーが見つかりました。", "success");
setMessage("データの取得に失敗しました。", "error");
JavaScript

初心者の方は、「同じ形の処理を見つけたら関数化できる」と気づけると、コード整理がしやすくなります。

ステップ2:結果表示を関数化する

結果一覧を表示する処理も関数にまとめます。

function renderUsers(users) {
  resultList.innerHTML = "";

  users.forEach(function (user) {
    const li = document.createElement("li");
    li.classList.add("user-item");
    li.textContent = `${user.name} / ${user.email} / ${user.company.name}`;
    resultList.appendChild(li);
  });
}
JavaScript

こうすると、表示の見た目を変えたいときも renderUsers() だけ見ればよくなります。初心者の方は、「画面に出す処理を1か所に集める」と考えるとわかりやすいです。

ステップ3:絞り込み処理を関数化する

検索とフィルターも、表示更新関数の中に全部書くのではなく、分けられます。

function getFilteredUsers() {
  const keyword = keywordInput.value.trim().toLowerCase();
  const companyLetter = companyFilter.value;

  let filteredUsers = allUsers.filter(function (user) {
    return user.name.toLowerCase().includes(keyword);
  });

  if (companyLetter !== "") {
    filteredUsers = filteredUsers.filter(function (user) {
      return user.company.name.startsWith(companyLetter);
    });
  }

  return filteredUsers;
}
JavaScript

初心者の方は、「絞り込み結果を返す関数」にすると、表示更新の流れが読みやすくなることを感じられるはずです。

ステップ4:表示更新の役割を明確にする

こうして部品を分けたら、表示更新関数はかなりシンプルになります。

function updateDisplay() {
  const filteredUsers = getFilteredUsers();

  if (filteredUsers.length === 0) {
    resultList.innerHTML = "";
    setMessage("条件に合うユーザーが見つかりませんでした。");
    return;
  }

  renderUsers(filteredUsers);
  setMessage(`${filteredUsers.length}件のユーザーが見つかりました。`, "success");
}
JavaScript

初心者の方は、この形を見ると「表示更新関数は全体の流れを見る役割」だと理解しやすくなります。

そのまま使える改善版テンプレート

ここでは、Day 68のアプリをDay 69向けに改善した完成テンプレートを紹介します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Day 69 APIアプリ改善</title>
  <style>
    body {
      font-family: sans-serif;
      max-width: 800px;
      margin: 24px auto;
      padding: 16px;
    }

    input, select {
      padding: 8px;
      margin-right: 8px;
      margin-bottom: 12px;
    }

    #message {
      margin: 12px 0;
      font-weight: bold;
    }

    .loading {
      color: blue;
    }

    .success {
      color: green;
    }

    .error {
      color: red;
    }

    .user-item {
      padding: 10px;
      margin-bottom: 8px;
      border: 1px solid #ccc;
      border-radius: 6px;
      background-color: #f9f9f9;
      list-style: none;
    }

    ul {
      padding-left: 0;
    }
  </style>
</head>
<body>
  <h2>ユーザー検索&フィルター 改善版</h2>

  <input type="text" id="keywordInput" placeholder="名前で検索">
  <select id="companyFilter">
    <option value="">すべての会社</option>
    <option value="C">Cで始まる会社</option>
    <option value="R">Rで始まる会社</option>
  </select>

  <p id="message">データを読み込みます。</p>
  <ul id="resultList"></ul>

  <script>
    // APIから取得した元データを保存する
    let allUsers = [];

    // 必要な要素を取得する
    const keywordInput = document.getElementById("keywordInput");
    const companyFilter = document.getElementById("companyFilter");
    const message = document.getElementById("message");
    const resultList = document.getElementById("resultList");

    // メッセージ表示を担当する関数
    function setMessage(text, className = "") {
      message.textContent = text;
      message.className = className;
    }

    // ユーザー一覧を描画する関数
    function renderUsers(users) {
      // 前回の表示を空にする
      resultList.innerHTML = "";

      // 1件ずつ表示する
      users.forEach(function (user) {
        const li = document.createElement("li");
        li.classList.add("user-item");
        li.textContent = `${user.name} / ${user.email} / ${user.company.name}`;
        resultList.appendChild(li);
      });
    }

    // 検索とフィルターを適用した配列を返す関数
    function getFilteredUsers() {
      const keyword = keywordInput.value.trim().toLowerCase();
      const companyLetter = companyFilter.value;

      // まず名前で検索する
      let filteredUsers = allUsers.filter(function (user) {
        return user.name.toLowerCase().includes(keyword);
      });

      // 次に会社名でフィルターする
      if (companyLetter !== "") {
        filteredUsers = filteredUsers.filter(function (user) {
          return user.company.name.startsWith(companyLetter);
        });
      }

      return filteredUsers;
    }

    // 条件に応じて画面表示を更新する関数
    function updateDisplay() {
      const filteredUsers = getFilteredUsers();

      // 0件なら一覧を消してメッセージを表示する
      if (filteredUsers.length === 0) {
        resultList.innerHTML = "";
        setMessage("条件に合うユーザーが見つかりませんでした。");
        return;
      }

      // 一覧を表示して件数を知らせる
      renderUsers(filteredUsers);
      setMessage(`${filteredUsers.length}件のユーザーが見つかりました。`, "success");
    }

    // APIからデータを取得する関数
    async function loadUsers() {
      try {
        // 読み込み中メッセージ
        setMessage("データを読み込み中です...", "loading");

        // APIへリクエストを送る
        const response = await fetch("https://jsonplaceholder.typicode.com/users");

        // HTTPエラーを確認する
        if (!response.ok) {
          throw new Error("ユーザーデータの取得に失敗しました。");
        }

        // データを保存する
        allUsers = await response.json();

        // 初期表示を行う
        updateDisplay();
      } catch (error) {
        // エラー時は一覧を空にする
        resultList.innerHTML = "";

        // ユーザー向けメッセージ
        setMessage("データの取得に失敗しました。時間をおいて再試行してください。", "error");

        // 開発者向け詳細
        console.log("エラー詳細:", error);
      }
    }

    // 入力内容が変わったら表示を更新する
    keywordInput.addEventListener("input", function () {
      updateDisplay();
    });

    // フィルター条件が変わったら表示を更新する
    companyFilter.addEventListener("change", function () {
      updateDisplay();
    });

    // 最初にデータを取得する
    loadUsers();
  </script>
</body>
</html>

この改善版テンプレートの重要な見どころ

初心者の方は、このコードの中で特に次の点に注目すると理解しやすいです。

  • `setMessage()` でメッセージ処理をまとめていること
  • `renderUsers()` で表示処理を分けていること
  • `getFilteredUsers()` で検索とフィルターを分けていること
  • `updateDisplay()` が全体の流れを見る役割になっていること
  • エラー時に一覧表示を空にして状態を明確にしていること

特に重要なのは、「1つの関数が1つの役割を持つように整理されている」という点です。これによって、コードがかなり読みやすくなります。

特に深掘りしたい重要ポイント

今回最も大切なのは、「動くコードを、そのまま成長できる形へ整える」という考え方です。初心者の方は、最初に書いたコードに愛着があって、なかなか分割や整理をしたくないこともあります。しかし、アプリは大きくなるほど、整理されていないコードでは修正や追加が難しくなります。そのため、今のうちから「役割分担」「関数化」「状態の見せ方」を意識することが非常に大切です。

また、UI改善・エラー処理・コード整理は別々の話に見えて、実はつながっています。コードが整理されているとUI改善もしやすくなりますし、エラー時の表示改善もやりやすくなります。つまり、読みやすいコードは、改善しやすいコードでもあります。

情報セキュリティの観点での注意

アプリ改善では、見た目や使いやすさに意識が向きやすいですが、外部データを扱う基本姿勢は変わりません。引き続き、外部APIから取得したデータは textContent など安全な方法で表示し、内部エラーの詳細はユーザー画面へそのまま出しすぎないことが大切です。また、コード整理の際にも、どの処理が外部入力に関わるかを意識しておくと、あとで安全性を確認しやすくなります。初心者の方は、「整理しやすいコードは安全確認もしやすい」と考えるとよいです。

初心者が特に注意したいポイント

Day 69では、次の点を特に意識すると理解が深まりやすいです。

  • UI改善は見た目だけでなく使いやすさの改善です。
  • エラー処理は失敗後の画面まで含めて考えることが大切です。
  • コード整理は役割ごとに関数を分けることから始められます。
  • 同じ処理が何度も出てきたら関数化を考えるとよいです。
  • 読みやすいコードは修正しやすく、改善しやすいです。

特に重要なのは、「改善」とは飾り付けではなく、使う人にも作る人にもやさしい形へ整えることだという点です。

Day 69のゴールを整理する

Day 69では、次のことができるようになっていれば十分です。

  • 既存のAPIアプリのUIを見やすく改善できる
  • エラー時の表示をよりわかりやすくできる
  • メッセージ表示や描画処理を関数化できる
  • 検索・フィルター・表示更新の役割を分けて整理できる
  • 動くだけでなく改善しやすいコードを書こうと意識できる

ここまでできれば、Day 69としてはとても順調です。APIを使ったアプリを、実用的で育てやすい形へ近づける力がついています。

まとめ

Day 69では、第5フェーズ「非同期処理とAPI」の仕上げとして、APIアプリの改善に取り組みました。今回の改善内容は、UI改善、エラー処理、コード整理の3つでした。UI改善では、入力欄や結果表示に余白やまとまりを持たせ、状態ごとに見た目を分けることで、使いやすさを高めました。エラー処理では、失敗時のメッセージをわかりやすくし、前回の結果が誤解を生まないように一覧を空にするなど、画面全体として状態が伝わるようにしました。コード整理では、メッセージ表示、描画、絞り込み、表示更新といった役割ごとに関数を分けることで、読みやすく修正しやすい構造へ整えました。

特に大切なのは、「動くコードを、そのまま終わりにしない」ことです。実際の開発では、最初に完成したものを何度も見直し、使いやすく、壊れにくく、読みやすく育てていくことが重要です。その感覚をDay 69で身につけられると、この先のJavaScript学習でも非常に大きな強みになります。

次に進む前に、今回の改善版テンプレートを実際に動かし、メッセージの文言を変えたり、結果表示に会社名だけでなく電話番号も足したり、0件時の見た目を変えたりしてみるのがおすすめです。そして、「どの改善がユーザー向けの改善で、どの改善が開発者向けの改善なのか」を自分の言葉で説明できるようになると、Day 69の理解がかなり深まっています。

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