3日目のゴールと今日やること
3日目のテーマは
「1日分の天気 → 複数日(予報)に広げても、同じ fetch・async/await・エラーハンドリングで考えられるようになること」
です。
1日目・2日目で、あなたはすでに
fetch で API を叩く
async/await で読みやすく書く
try-catch と response.ok、data.error でエラーを分岐する
ローディング表示とボタン制御を入れる
という「API 通信の基本フォーム」を身につけました。
3日目はこれをそのまま使いながら、
現在の天気 API(current)ではなく
予報 API(forecast)を叩いて
「複数日の天気」を表示する
という、少しだけ“スケールアップしたアプリ”にしていきます。
今日の完成イメージを先に描く
どんなアプリにするか
今日のミニアプリは、こんな動きをします。
都市名を入力する
「検索」ボタンを押す
WeatherAPI.com の forecast API を叩く
今日を含む 3 日分の天気を取得する
ローディング中は「取得中…」と表示
成功したら「日付・最高/最低気温・天気」を一覧表示
失敗したら「エラー内容」をわかりやすく表示
つまり、
「1件のデータを表示」から
「配列(複数件)をループして表示」
にステップアップします。
ここで大事なのは、
ロジックの“骨格”は 1 日目・2 日目とまったく同じ、
という感覚を持つことです。
forecast API に変えるだけで「複数日」が取れる
current API と forecast API の違い
1日目・2日目で使っていたのは、
だいたいこんな URL でした。
https://api.weatherapi.com/v1/current.json?key=API_KEY&q=Tokyo&lang=ja
3日目で使うのは、
forecast.json です。
https://api.weatherapi.com/v1/forecast.json?key=API_KEY&q=Tokyo&days=3&lang=ja
違いは 2 つだけです。
パスが current.json → forecast.json
クエリに days=3 が増えた(何日分ほしいか)
JavaScript で書くとこうなります。
const API_KEY = "YOUR_API_KEY";
const baseUrl = "https://api.weatherapi.com/v1/forecast.json";
function buildUrl(city, days = 3) {
const params = new URLSearchParams({
key: API_KEY,
q: city,
days: String(days),
lang: "ja"
});
return `${baseUrl}?${params.toString()}`;
}
JavaScriptここまでで、
「複数日を取る準備」は完了です。
fetch と async/await は「昨日と同じフォーム」で使う
骨格は変えない
2日目の fetchWeather を、
ほぼそのまま forecast 用に書き換えます。
async function fetchForecast(city) {
const error = validateCity(city);
if (error) {
statusDiv.textContent = error;
resultDiv.textContent = "";
return;
}
startLoading();
try {
const url = buildUrl(city, 3);
const response = await fetch(url);
if (!response.ok) {
statusDiv.textContent = `サーバーエラーが発生しました。(${response.status})`;
return;
}
const data = await response.json();
if (data.error) {
statusDiv.textContent = `エラー:${data.error.message}`;
return;
}
statusDiv.textContent = "3日分の天気を取得しました。";
renderForecast(data);
} catch (error) {
statusDiv.textContent = "通信に失敗しました。ネットワークを確認してください。";
console.error(error);
} finally {
endLoading();
}
}
JavaScriptここで意識してほしいのは、
fetch
await
response.ok チェック
data.error チェック
try-catch-finally
という“型”は、
昨日とまったく同じだということです。
中級に上がるって、
「新しいことを覚える」より
「同じ型をいろんな場面に当てはめられる」
ことなんですよね。
forecast のレスポンス構造を読み解く
どんな JSON が返ってくるか
forecast.json は、ざっくりこんな構造です。
{
"location": {
"name": "Tokyo",
"country": "Japan"
},
"current": {
"temp_c": 26.5,
"condition": { "text": "晴れ" }
},
"forecast": {
"forecastday": [
{
"date": "2026-01-27",
"day": {
"maxtemp_c": 28.0,
"mintemp_c": 20.0,
"condition": { "text": "晴れ" }
}
},
{
"date": "2026-01-28",
"day": {
"maxtemp_c": 27.0,
"mintemp_c": 19.0,
"condition": { "text": "にわか雨" }
}
}
]
}
}
複数日分は
forecast.forecastday という配列に入っています。
つまり、
location.name / country → 都市情報
forecast.forecastday → 日ごとの天気一覧
というイメージで見れば OK です。
複数日分をループして表示する
renderForecast の役割
renderForecast は、
「1 日分」ではなく
「配列を全部表示する」 関数になります。
function renderForecast(data) {
const name = data.location.name;
const country = data.location.country;
const days = data.forecast.forecastday;
let html = "";
html += `<p>${name} (${country}) の 3 日間の天気</p>`;
days.forEach((day) => {
const date = day.date;
const max = day.day.maxtemp_c;
const min = day.day.mintemp_c;
const text = day.day.condition.text;
html += `
<div class="day">
<p>日付:${date}</p>
<p>最高:${max} ℃ / 最低:${min} ℃</p>
<p>天気:${text}</p>
</div>
`;
});
resultDiv.innerHTML = html;
}
JavaScriptここでのポイントは、
配列 days を forEach で回して
1 日分ずつ HTML を足していく
というシンプルな構造です。
深掘り:API 通信 × 配列処理ができると一気に世界が広がる
今やっていることは、
API から配列を受け取る
配列をループして UI を作る
という、
「ほぼすべての Web アプリで使うパターン」です。
天気だけじゃなくて、
商品一覧
ユーザー一覧
チャット履歴
ニュース記事
など、
「一覧表示するもの」は全部この形になります。
エラーハンドリングを「複数日でも同じように」考える
失敗パターンは昨日と変わらない
複数日を取ろうが、
1 日だけ取ろうが、
失敗パターンは同じです。
ネットワークエラー(catch)
HTTP エラー(!response.ok)
API 独自のエラー(data.error)
大事なのは、
「どの段階で失敗したか」を意識してメッセージを変える
ことです。
例えば、
response.ok が false → サーバー側の問題の可能性
data.error がある → 入力や API キーの問題の可能性
なので、メッセージも変えられます。
if (!response.ok) {
statusDiv.textContent = `サーバーエラーが発生しました。(${response.status})`;
return;
}
const data = await response.json();
if (data.error) {
statusDiv.textContent = `エラー:${data.error.message}`;
return;
}
JavaScriptここまで分けてあげると、
ユーザーも「自分のせいか、サーバーのせいか」が
なんとなくわかります。
ローディング表示は「複数日でもまったく同じ」
startLoading / endLoading をそのまま使う
2日目で作ったローディング関数は、
そのまま再利用できます。
function startLoading() {
statusDiv.textContent = "天気情報を取得中です…";
resultDiv.textContent = "";
searchButton.disabled = true;
}
function endLoading() {
searchButton.disabled = false;
}
JavaScriptfetchForecast の中で
try の前に startLoading
finally の中で endLoading
という“型”を守るだけです。
深掘り:ローディングは「処理の始まりと終わりを挟む」
ローディング表示は、
「非同期処理の前後を挟む」
というイメージで考えると、
どんな API 通信にも応用できます。
3日目の全体コード(重要部分をまとめて)
const API_KEY = "YOUR_API_KEY";
const baseUrl = "https://api.weatherapi.com/v1/forecast.json";
const cityInput = document.getElementById("cityInput");
const searchButton = document.getElementById("searchButton");
const statusDiv = document.getElementById("status");
const resultDiv = document.getElementById("result");
function buildUrl(city, days = 3) {
const params = new URLSearchParams({
key: API_KEY,
q: city,
days: String(days),
lang: "ja"
});
return `${baseUrl}?${params.toString()}`;
}
function validateCity(city) {
if (!city.trim()) return "都市名を入力してください。";
if (city.length > 50) return "都市名が長すぎます。50文字以内で入力してください。";
return null;
}
function startLoading() {
statusDiv.textContent = "天気情報を取得中です…";
resultDiv.textContent = "";
searchButton.disabled = true;
}
function endLoading() {
searchButton.disabled = false;
}
function renderForecast(data) {
const name = data.location.name;
const country = data.location.country;
const days = data.forecast.forecastday;
let html = "";
html += `<p>${name} (${country}) の 3 日間の天気</p>`;
days.forEach((day) => {
const date = day.date;
const max = day.day.maxtemp_c;
const min = day.day.mintemp_c;
const text = day.day.condition.text;
html += `
<div class="day">
<p>日付:${date}</p>
<p>最高:${max} ℃ / 最低:${min} ℃</p>
<p>天気:${text}</p>
</div>
`;
});
resultDiv.innerHTML = html;
}
async function fetchForecast(city) {
const error = validateCity(city);
if (error) {
statusDiv.textContent = error;
resultDiv.textContent = "";
return;
}
startLoading();
try {
const url = buildUrl(city, 3);
const response = await fetch(url);
if (!response.ok) {
statusDiv.textContent = `サーバーエラーが発生しました。(${response.status})`;
return;
}
const data = await response.json();
if (data.error) {
statusDiv.textContent = `エラー:${data.error.message}`;
return;
}
statusDiv.textContent = "3日分の天気を取得しました。";
renderForecast(data);
} catch (error) {
statusDiv.textContent = "通信に失敗しました。ネットワークを確認してください。";
console.error(error);
} finally {
endLoading();
}
}
searchButton.addEventListener("click", () => {
fetchForecast(cityInput.value);
});
JavaScript今日いちばん深く理解してほしいこと
3日目で本当に持ち帰ってほしいのは、
API が「1件」でも「複数件」でも
fetch・async/await・エラーハンドリングの“型”は変わらない
という感覚です。
違うのは、
レスポンスの中身(current か forecast か)
配列をループするかどうか
だけです。
つまり、あなたはもう
「API の仕様書を読んで、
それに合わせて URL を組み立てて、
返ってきた JSON を自分で解釈して UI に落とし込める人」
になりつつあります。
次の 4 日目では、
この forecast アプリに
天気アイコンの表示
摂氏 / 華氏の切り替え
エラー時の UI 改善
などを足して、
さらに“プロダクト寄り”の仕上がりにしていきます。

