5日目のゴールと今日やること
5日目のテーマは
「Nager.Date API アプリを“中級者の設計”に進化させる」 ことです。
ここまでであなたは、
- 年と国を指定して祝日を取得
- ローディング表示
- エラーハンドリング
- 前年・翌年・今年ボタン
- お気に入り機能
- localStorage 保存
といった、祝日アプリの基礎と応用をしっかり作ってきました。
5日目では、これらをさらに一段レベルアップさせて、
- fetch を共通化して「どこでも同じ型で使える」ようにする
- Promise / async‑await を使って「複数国の祝日を同時に取得」する
- エラーハンドリングを「原因別」に整理する
- ローディング表示を「複数リクエスト」に対応させる
という、まさに中級者らしい設計に踏み込みます。
fetch を「共通関数」にまとめるという発想
なぜ共通化が必要なのか
祝日アプリでは、いろいろな場面で fetch を使います。
- 通常の祝日取得
- お気に入りからの再取得
- 複数国の祝日比較
- 年を変えて再取得
これらすべてで fetch を直書きすると、
- エラーハンドリングがバラバラ
- 修正したいときに全部直す必要がある
- コードが読みづらくなる
という問題が出てきます。
そこで、
「JSON を返す API を叩くための共通関数」 を作ります。
共通の requestJson 関数を作る
まずは素直な形で書く
async function requestJson(url) {
try {
const response = await fetch(url);
if (!response.ok) {
if (response.status === 404) {
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 エラー(404, 500 など)
- JSON パースエラー
をすべて Error として上に投げる 役割を持っています。
これにより、
上位の関数は「成功したか・失敗したか」だけを扱えばよくなります。
Nager.Date 専用の検索関数を作る
API の仕様チェックをここに集約する
async function fetchPublicHolidays(year, countryCode) {
const url = `https://date.nager.at/api/v3/PublicHolidays/${year}/${countryCode}`;
const data = await requestJson(url);
if (!Array.isArray(data)) {
throw new Error("予期しない形式のデータが返されました。");
}
if (data.length === 0) {
throw new Error("祝日が見つかりませんでした。");
}
return data;
}
JavaScript深掘りポイント
fetchPublicHolidays は
「Nager.Date API の仕様を知っている唯一の関数」
です。
UI 側は API の細かい仕様を知らなくてよくなり、
コードが読みやすくなります。
UI 側の fetchHolidays を“ストーリーとして読める”形にする
5日目版 fetchHolidays
async function fetchHolidays() {
const rawYear = yearInput.value.trim();
const countryCode = countrySelect.value;
const parsed = parseYear(rawYear);
if (!parsed.ok) {
statusDiv.textContent = parsed.message;
resultDiv.textContent = "";
return;
}
const year = parsed.value;
setLoading(true, `${year}年の祝日を取得中です…`);
resultDiv.textContent = "";
try {
const holidays = await fetchPublicHolidays(year, countryCode);
statusDiv.textContent = "祝日の取得に成功しました。";
renderHolidays(holidays);
} catch (error) {
statusDiv.textContent = `取得中にエラーが発生しました:${error.message}`;
console.error(error);
} finally {
setLoading(false);
}
}
JavaScript深掘りポイント
この関数は、
「祝日取得の流れをそのまま読める」
という設計になっています。
- 入力チェック
- ローディング開始
- fetchPublicHolidays で祝日取得
- 成功時の表示
- 失敗時のメッセージ
- ローディング終了
fetch の細かい処理はfetchPublicHolidays と requestJson に隠れているため、
とても読みやすくなっています。
Promise.all を使って「複数国の祝日を同時に取得」する
複数国比較のニーズ
祝日アプリでは、
「日本とアメリカの祝日を比較したい」
「日本とドイツの祝日を同時に見たい」
というニーズがよくあります。
これを実現するのが Promise.all です。
複数国の祝日を同時に取得する関数
async function fetchMultipleCountries(year, countries) {
const promises = countries.map((code) =>
fetchPublicHolidays(year, code)
);
const results = await Promise.all(promises);
return results;
}
JavaScript深掘りポイント
Promise.all のメリットは、
- 並列で API を叩ける
- 全部終わるまで待てる
- 結果をまとめて扱える
という点です。
複数国比較の UI を作る
例:日本・アメリカ・ドイツを比較するボタン
async function compareCountries() {
const rawYear = yearInput.value.trim();
const parsed = parseYear(rawYear);
if (!parsed.ok) {
statusDiv.textContent = parsed.message;
return;
}
const year = parsed.value;
const countries = ["JP", "US", "DE"];
setLoading(true, `${year}年の複数国の祝日を取得中です…`);
resultDiv.textContent = "";
try {
const results = await fetchMultipleCountries(year, countries);
renderComparison(results, countries, year);
statusDiv.textContent = "複数国の祝日取得に成功しました。";
} catch (error) {
statusDiv.textContent = `比較中にエラーが発生しました:${error.message}`;
console.error(error);
} finally {
setLoading(false);
}
}
JavaScript複数国の祝日を比較表示する
シンプルな比較表示
function renderComparison(results, countries, year) {
let html = `<h3>${year}年 複数国の祝日比較</h3>`;
results.forEach((holidays, index) => {
const code = countries[index];
html += `<h4>${code} の祝日</h4>`;
holidays.forEach((item) => {
html += `<p>${item.date}:${item.localName}(${item.name})</p>`;
});
});
resultDiv.innerHTML = html;
}
JavaScript深掘りポイント
ここで重要なのは、
- Promise.all の結果は「国ごとの配列の配列」
- index を使って国コードと対応させる
- UI 側は「祝日をどう見せるか」だけに集中できる
という構造です。
ローディング表示を「複数リクエスト」に対応させる
state と連動させる
function setLoading(isLoading, message) {
updateState({ isLoading });
if (isLoading) {
statusDiv.textContent = message || "処理中です…";
}
fetchButton.disabled = isLoading;
compareButton.disabled = isLoading;
thisYearButton.disabled = isLoading;
prevYearButton.disabled = isLoading;
nextYearButton.disabled = isLoading;
}
JavaScript複数国比較でも、
単一国の取得でも、
ローディング表示が一貫して動く ようになります。
エラーハンドリングを「原因別」に整理する
requestJson の中で原因別に分岐
- 404 → データがない
- 500 番台 → サーバー側の問題
- その他 → 一般的な HTTP エラー
ユーザーにとっては、
「自分が悪いのか、サーバーが悪いのか」
がわかるだけでストレスが減ります。
5日目のまとめ
今日あなたがやったことを整理すると、こうなります。
- fetch を requestJson に共通化
- Nager.Date 専用の fetchPublicHolidays を作成
- UI 側の fetchHolidays を「読みやすい流れ」に整理
- Promise.all で複数国の祝日を同時に取得
- 複数国比較の UI を実装
- ローディング表示を state と連動
- エラーハンドリングを原因別に整理
どれも新しい文法ではなく、
「fetch / async‑await / エラーハンドリングを“設計として扱う”」
という話です。
今日いちばん深く理解してほしいこと
5日目の本質は、
「API 通信は、型を作ればどんどん応用できる」
ということです。
単一国の祝日取得
お気に入り
複数国比較
localStorage 保存
これらは全部、
同じ fetch / async-await / try-catch の型の上に乗っています。
6日目では、この祝日アプリを
さらに整理し、拡張しやすい構造に仕上げる 回に入ります。
あなたのアプリが「本当に使えるツール」になる瞬間が近づいています。


