完成イメージ
郵便番号を入力し、住所検索ボタンをクリックしたら都道府県・市区・町域が自動で取得できるAPIを作成してみよう


APIで犬の画像をランダムに取得し、ボタンをクリックしたら再度、新しい画像を読み込む

作成ファイル・保存場所
js-domフォルダに以下のファイルを作成してください。
| ファイル名 | 内容 |
|---|---|
| js-dom08.html | ボタンクリックの動作練習用HTML/js |
| js-dom__08.html | ステップアップ練習用HTML/js |
JavaScriptは <script> タグ内に直接記述してください(内部JS)
今回のテーマ
async / await を使って、APIから外部データを取得し、順番通りに処理・表示する方法を学びます。
複数の非同期処理を整理して書けるようになり、実務でもよく使われるスタイルを体験します。
目的
async functionとawaitの書き方を理解する- 複数の非同期処理を「順番に実行する」しくみを体感する
try { ... } catch { ... }でエラー処理をまとめて書けるようにする- API(2つのエンドポイント)を使ってデータを連携する
チェックポイント
await fetch()を使ってAPIからデータを取得できているか?async functionの中で処理を順番に書けているか?try / catchを使ってエラーを1箇所で処理できているか?- 2つのAPIを組み合わせて表示(例:画像+日本語名)ができているか?
JavaScript基礎トレーニング
1.郵便番号から住所を取得
郵便番号APIを使って、郵便番号から都道府県・市町村区を表示させます。
エンドポイント:https://zipcloud.ibsnet.co.jp/api/search?zipcode=郵便番号
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>郵便番号で住所を取得</title>
<style>
input[type=text] {
width: 400px;
padding: 10px 5px;
}
#search-btn {
padding: 8.5px 30px;
}
</style>
</head>
<body>
<h1>郵便番号から住所を取得</h1>
<input type="text" id="zipcode" placeholder="郵便番号を入力(例: 1000001)">
<button id="search-btn">検索</button>
<p id="result">住所がここに表示されます</p>
<script>
const btn = document.getElementById('search-btn');
const result = document.getElementById('result');
btn.addEventListener('click', async () => {
const zipcode = document.getElementById('zipcode').value;
try {
const res = await fetch(`https://zipcloud.ibsnet.co.jp/api/search?zipcode=${zipcode}`);
const data = await res.json();
console.log(JSON.stringify(data, null, 2));
if (data.results) {
const address = data.results[0];
result.textContent = `${address.address1}${address.address2}${address.address3}`;
} else {
result.textContent = '該当する住所が見つかりませんでした。';
}
} catch (error) {
result.textContent = 'エラーが発生しました。';
console.error('エラー:', error);
}
});
</script>
</body>
</html>
解答例
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>郵便番号で住所を取得</title>
<style>
input[type=text] {
width: 150px;
padding: 10px 5px;
margin-bottom: 10px;
}
#search-btn {
padding: 8.5px 30px;
}
label {
display: inline-block;
width: 80px;
}
</style>
</head>
<body>
<h1>郵便番号から住所を取得</h1>
<label for="zipcode">郵便番号</label>
<input type="text" id="zipcode" placeholder="例: 8000000">
<button id="search-btn">住所検索</button>
<!-- 住所表示欄(3分割) -->
<div id="result">
<p>
<label for="pref">都道府県</label>
<input type="text" id="pref">
</p>
<p>
<label for="city">市区</label>
<input type="text" id="city">
</p>
<p>
<label for="town">町域</label>
<input type="text" id="town">
</p>
</div>
<script>
const btn = document.getElementById('search-btn');
btn.addEventListener('click', async () => {
const zipcode = document.getElementById('zipcode').value;
try {
const res = await fetch(`https://zipcloud.ibsnet.co.jp/api/search?zipcode=${zipcode}`);
const data = await res.json();
console.log(JSON.stringify(data, null, 2));
if (data.results) {
const address = data.results[0];
document.getElementById('pref').value = address.address1; // 都道府県
document.getElementById('city').value = address.address2; // 市区
document.getElementById('town').value = address.address3; // 町域
} else {
alert('該当する住所が見つかりませんでした。');
}
} catch (error) {
alert('エラーが発生しました。');
console.error('エラー:', error);
}
});
</script>
</body>
</html>
2.犬のランダム画像
ページが読み込まれたら、20枚読み込む
エンドポイント:https://dog.ceo/api/breeds/image/random
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>APIで犬画像を表示しよう</title>
<style>
#area {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.dog-image {
width: 100%;
max-width: 100%;
aspect-ratio: 1 / 1;
object-fit: cover;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
}
</style>
</head>
<body>
<h1>Window Load表示 + ボタン再読み込み</h1>
<button id="btn">もう一度読み込む</button>
<p id="area">表示するエリア</p>
<script>
const btn = document.getElementById('btn');
const area = document.getElementById('area');
//非同期で動く関数を作る宣言
async function showDogs() {
area.innerHTML = ''; // 表示をクリア
try {
for (let i = 0; i < 20; i++) {
const res = await fetch('https://dog.ceo/api/breeds/image/random');
const data = await res.json();
const img = document.createElement('img');
img.src = data.message;
img.alt = '犬の画像';
img.classList.add('dog-image');
area.appendChild(img);
}
} catch (error) {
console.error('エラー:', error);
area.textContent = '画像の取得に失敗しました。';
}
}
// 画面読み込み時に実行
window.addEventListener('load', showDogs);
// ボタンクリック時に再読み込み
btn.addEventListener('click', showDogs);
</script>
</body>
</html>
async / await / try-catch とは?
JavaScriptでは、APIからデータを取ってくる処理(fetch)は「非同期(ひどうき)」になります。
非同期とは「すぐには結果が返ってこない」ということです。
async / await の役割
async function 関数名() {
const res = await fetch('URL');
}
async functionと書くと、関数の中でawaitが使えるようになりますawait fetch(...)は「この結果が返ってくるまで待つよ」という意味- 順番通りに処理が進むため、コードが読みやすくなります。
async とは?
async は 「この関数は非同期処理を含みますよ」 という宣言です。
これを付けることで、関数の中で await が使えるようになります。
async function fetchData() {
// ここで await が使えるようになる
}
async を付けると、その関数は 非同期関数になります自動的に Promiseを返す関数として扱われます通常の関数と区別して、「非同期の処理があるよ」と見てわかるメリットもあります
await とは?
await は 「この処理が終わるまで、次に進まないで待って!」 という命令です。
const res = await fetch('https://api.example.com/data');
await は Promise(非同期処理の結果)を待つために使いますfetch() のように時間がかかる処理の完了を「待つ」ことができますこれにより、処理の順番が保たれ、コードの見通しが良くなります
try / catch のセットで使うと安心!
async function fetchData() {
try {
const res = await fetch('URL');
const data = await res.json();
console.log(data);
} catch (error) {
console.error('エラー:', error);
}
}
- tryの中でエラーが起きたら
catchに飛んでくれる - ページ全体が止まらない
- ユーザーに「エラーメッセージ」を出すことができる
JavaScript応用トレーニング
ボタンをクリックしてランダム表示
2種類のAPIを使ってポケモンを表示させよう(ポケモン+日本語化)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>APIを使ってみよう!</title>
</head>
<body>
<h2>ランダムポケモンを表示</h2>
<button id="btn">ポケモンを表示</button>
<p id="result">ここに表示されます</p>
<script>
const btn = document.getElementById('btn');
const result = document.getElementById('result');
btn.addEventListener('click', async () => {
try {
const randomId = Math.floor(Math.random() * 898) + 1; // 1〜898番まで対応
const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${randomId}`);
const data = await res.json();
console.log(JSON.stringify(data, null, 2));//data確認
const image = data.sprites.other['official-artwork'].front_default;
// "sprites": {
// "other": {
// "official-artwork": {
// "front_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/25.png"
// }
// }
// }
//なぜここだけブラケット記法['official-artwork']
//ここはハイフンを含むのでドット記法が使えません
// 日本語名の取得(2回目のfetch)
const speciesRes = await fetch(data.species.url);
const speciesData = await speciesRes.json();
const jpName = speciesData.names.find(n => n.language.name === 'ja').name;
result.innerHTML = `
<p><strong>${jpName}</strong>(No.${randomId})</p>
<img src="${image}" width="400" alt="${jpName}">
`;
} catch (error) {
result.textContent = 'エラーが発生しました';
console.error(error);
}
});
</script>
</body>
</html>
ポケモンAPIの画像は「学習や個人利用」以外には使ってはいけません。
ポケモンを名前で検索できるようにしてみよう!
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ポケモンを検索しよう!</title>
<style>
input[type=text] {
padding: 7px 10px;
width: 250px;
}
button {
padding: 4px 20px;
}
</style>
</head>
<body>
<h2>ポケモンを名前で検索</h2>
<input type="text" id="nameInput" placeholder="ポケモンの名前(例:ピカチュウ)">
<button id="btn">検索</button>
<p id="result">ここに表示されます</p>
<script>
const btn = document.getElementById('btn');
const result = document.getElementById('result');
const nameInput = document.getElementById('nameInput');
btn.addEventListener('click', async () => {
const keyword = nameInput.value.trim();
if (!keyword) {
result.textContent = '名前を入力してください。';
return;
}
try {
// 全ポケモンの種別一覧から日本語対応名を探す
const res = await fetch(`https://pokeapi.co/api/v2/pokemon-species/?limit=10000`);
const data = await res.json();
// 各種別データをfetchして、該当する日本語名を探す
let foundUrl = null;
for (const entry of data.results) {
const speciesRes = await fetch(entry.url);
const speciesData = await speciesRes.json();
const jpNameEntry = speciesData.names.find(n => n.language.name === 'ja');
if (jpNameEntry && jpNameEntry.name === keyword) {
foundUrl = speciesData.varieties[0].pokemon.url;
break;
}
}
if (!foundUrl) {
result.textContent = '該当するポケモンが見つかりませんでした。';
return;
}
const pokeRes = await fetch(foundUrl);
const pokeData = await pokeRes.json();
const image = pokeData.sprites.other['official-artwork'].front_default;
result.innerHTML = `
<p><strong>${keyword}</strong>(No.${pokeData.id})</p>
<img src="${image}" width="400" alt="${keyword}">
`;
} catch (error) {
result.textContent = 'エラーが発生しました。';
console.error(error);
}
});
</script>
</body>
</html>
ポケモン図鑑と無限スクロールのサンプル
ページを読み込んだ時点で、ポケモンを自動的に表示します。最初は20体ずつ2回分(計40体)を一括で読み込み、ある程度スクロールできる状態を作ります。その後は、ユーザーがページの下までスクロールするたびに、次の20体を追加表示していくことで、無限にスクロールが続いていくような体験にします。この仕組みは「無限スクロール(infinite scroll)」と呼ばれ、SNSや商品一覧ページなどでもよく使われます。(こちらは学習用サイトです。

課題:天気予報のAPIを利用して作成してみよう!
解答例
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>現在の天気を取得しよう</title>
</head>
<body>
<h2>現在の天気を取得しよう!(Open-Meteo API)</h2>
<p><button id="weather-btn">天気を取得</button></p>
<div id="weather-area">ここに結果が表示されます</div>
<script>
// weathercode を日本語の天気に変換
function translateWeatherCode(code) {
const map = {
0: '快晴',
1: '晴れ',
2: '一部曇り',
3: '曇り',
45: '霧',
48: '霧(霧氷)',
51: '弱い霧雨',
53: '中程度の霧雨',
55: '強い霧雨',
61: '弱い雨',
63: '中程度の雨',
65: '強い雨',
71: '弱い雪',
73: '中程度の雪',
75: '強い雪',
80: '弱いにわか雨',
81: 'にわか雨',
82: '強いにわか雨',
95: '雷雨',
96: '雷雨(弱い雹)',
99: '雷雨(強い雹)'
};
return map[code] || '不明';
}
// 天気取得ボタンの処理
document.getElementById('weather-btn').addEventListener('click', async () => {
const area = document.getElementById('weather-area');
area.textContent = 'データ取得中...';
try {
const lat = 33.59;
const lon = 130.40;
const res = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}¤t_weather=true`);
const data = await res.json();
console.log(JSON.stringify(data, null, 2)); // デバッグ用
const temp = data.current_weather.temperature;
const wind = data.current_weather.windspeed;
const code = data.current_weather.weathercode;
const weather = translateWeatherCode(code);
area.innerHTML = `
<p><strong>現在の気温:</strong>${temp}℃</p>
<p><strong>風速:</strong>${wind} m/s</p>
<p><strong>天気:</strong>${weather}</p>
`;
} catch (error) {
area.textContent = '天気情報の取得に失敗しました。';
console.error('エラー:', error);
}
});
</script>
</body>
</html>
