JavaScript JSON読み込みの基本 - 初心者向け完全ガイド
JavaScriptでJSONファイルを読み込む方法を初心者向けに完全解説。fetchを使った基本的な読み込みから、エラーハンドリング、実用的なサンプルコードまで詳しく説明します。
JavaScript JSON読み込みの基本 - 初心者向け完全ガイド
みなさん、Webアプリでデータを扱うとき困ったことありませんか?
「APIからデータを取得したい」 「設定ファイルを読み込みたい」 「ユーザー情報を管理したい」
こんなとき、JSONという形式でデータを扱うことが多いんです。
この記事では、JavaScriptでJSONファイルを読み込む方法を、初心者の方でも分かるように詳しく解説します。 基本的な読み込み方法から、エラーハンドリング、実用的な応用例まで、実際に使えるレベルまで理解できるよう説明していきます。
JSONって何だろう?
簡単に言うとどんなもの?
**JSON(JavaScript Object Notation)**は、データを保存・交換する軽量な形式です。
簡単に言うと、データを文字列として表現する方法の一つなんです。 JavaScriptのオブジェクト記法をベースにしていて、今ではWeb開発の標準になっています。
{ "name": "田中太郎", "age": 30, "hobbies": ["プログラミング", "読書", "映画鑑賞"], "address": { "prefecture": "東京都", "city": "渋谷区" }}
人にも読みやすくて、プログラムでも扱いやすい形式なんです。
基本的なJSON読み込み
fetchを使った簡単な読み込み
まずは一番基本的な方法から見てみましょう。
async function loadJSON(url) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`エラーが発生しました: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error('JSON読み込みエラー:', error); throw error; }}
この関数は、指定されたURLからJSONファイルを読み込みます。
fetch
でファイルを取得して、response.json()
でJSONデータに変換しています。
エラーが発生した場合は、適切にエラーハンドリングを行います。
使い方はこんな感じです。
loadJSON('data/users.json') .then(data => { console.log('読み込み成功:', data); }) .catch(error => { console.error('読み込み失敗:', error); });
Promise記法での読み込み
async/awaitが使えない場合は、Promise記法も使えます。
function loadJSONWithPromise(url) { return fetch(url) .then(response => { if (!response.ok) { throw new Error(`エラーが発生しました: ${response.status}`); } return response.json(); }) .catch(error => { console.error('JSON読み込みエラー:', error); throw error; });}
この書き方でも同じことができます。 お好みに応じて使い分けてください。
使用例です。
loadJSONWithPromise('config/settings.json') .then(settings => { console.log('設定データ:', settings); applySettings(settings); });
高機能なJSONローダーを作ってみよう
キャッシュ機能付きローダー
同じファイルを何度も読み込むのは無駄ですよね。 キャッシュ機能付きのローダーを作ってみましょう。
class JSONLoader { constructor(options = {}) { this.baseUrl = options.baseUrl || ''; this.timeout = options.timeout || 5000; this.cache = new Map(); this.retryCount = options.retryCount || 3; } async load(url, useCache = true) { const fullUrl = this.baseUrl + url; // キャッシュから取得 if (useCache && this.cache.has(fullUrl)) { console.log('キャッシュから取得:', fullUrl); return this.cache.get(fullUrl); } let attempt = 0; while (attempt < this.retryCount) { try { const data = await this.fetchWithTimeout(fullUrl); // キャッシュに保存 if (useCache) { this.cache.set(fullUrl, data); } return data; } catch (error) { attempt++; if (attempt >= this.retryCount) { throw new Error(`読み込み失敗 (${this.retryCount}回試行): ${error.message}`); } console.warn(`試行 ${attempt}/${this.retryCount} 失敗, リトライします...`); await this.delay(1000 * attempt); } } }}
このクラスには、キャッシュ機能とリトライ機能が付いています。
一度読み込んだデータはキャッシュされるので、2回目以降は高速に取得できます。 ネットワークエラーが発生した場合は、自動的にリトライを行います。
タイムアウト機能を追加
ネットワークが遅い場合に備えて、タイムアウト機能も追加しましょう。
async fetchWithTimeout(url) { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.timeout); try { const response = await fetch(url, { signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return await response.json(); } catch (error) { clearTimeout(timeoutId); if (error.name === 'AbortError') { throw new Error(`タイムアウト: ${this.timeout}ms`); } throw error; }}
この関数は、指定された時間内にレスポンスが返ってこない場合、リクエストをキャンセルします。
複数ファイルの同時読み込み
複数のJSONファイルを同時に読み込む機能も追加してみましょう。
async loadMultiple(urls, useCache = true) { const promises = urls.map(url => this.load(url, useCache)); return Promise.all(promises);}
delay(ms) { return new Promise(resolve => setTimeout(resolve, ms));}
clearCache() { this.cache.clear();}
使用例を見てみましょう。
const loader = new JSONLoader({ baseUrl: '/api/', timeout: 10000, retryCount: 2});
// 単一ファイルの読み込みloader.load('users.json') .then(users => console.log('ユーザーデータ:', users));
// 複数ファイルの同時読み込みloader.loadMultiple(['users.json', 'settings.json', 'products.json']) .then(([users, settings, products]) => { console.log('すべてのデータを読み込み完了'); });
便利でしょう?
データの検証をしてみよう
バリデーション機能付きローダー
読み込んだデータが正しい形式かチェックする機能を作ってみましょう。
class TypedJSONLoader { constructor() { this.validators = new Map(); } // バリデーター関数を登録 registerValidator(key, validator) { this.validators.set(key, validator); } async loadWithValidation(url, validatorKey) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`エラーが発生しました: ${response.status}`); } const data = await response.json(); // バリデーション実行 if (validatorKey && this.validators.has(validatorKey)) { const validator = this.validators.get(validatorKey); const validationResult = validator(data); if (!validationResult.valid) { throw new Error(`データ検証エラー: ${validationResult.error}`); } } return data; } catch (error) { console.error('型安全JSON読み込みエラー:', error); throw error; } }}
このクラスでは、データの形式をチェックできます。
バリデーター関数を作ってみよう
ユーザーデータを検証する関数の例です。
function validateUserData(data) { if (!Array.isArray(data)) { return { valid: false, error: 'データは配列である必要があります' }; } for (const user of data) { if (typeof user.name !== 'string') { return { valid: false, error: 'ユーザー名は文字列である必要があります' }; } if (typeof user.age !== 'number' || user.age < 0) { return { valid: false, error: '年齢は正の数値である必要があります' }; } if (!user.email || !user.email.includes('@')) { return { valid: false, error: '有効なメールアドレスが必要です' }; } } return { valid: true };}
この関数は、ユーザーデータが期待する形式になっているかチェックします。
使用例です。
const typedLoader = new TypedJSONLoader();typedLoader.registerValidator('users', validateUserData);
typedLoader.loadWithValidation('data/users.json', 'users') .then(users => console.log('検証済みユーザーデータ:', users)) .catch(error => console.error('エラー:', error));
これで安全にデータを扱えます。
ローカルファイルを読み込んでみよう
ファイル選択での読み込み
ユーザーがパソコンからファイルを選択して読み込む機能を作ってみましょう。
<!DOCTYPE html><html><head> <title>JSONファイル読み込み</title></head><body> <input type="file" id="jsonFileInput" accept=".json"> <div id="output"></div></body></html>
HTMLはシンプルです。 ファイル選択ボタンと結果表示エリアを用意しました。
class LocalJSONReader { constructor(inputId, outputId) { this.fileInput = document.getElementById(inputId); this.output = document.getElementById(outputId); this.init(); } init() { this.fileInput.addEventListener('change', (event) => { this.handleFileSelect(event); }); } async handleFileSelect(event) { const file = event.target.files[0]; if (!file) return; if (file.type !== 'application/json' && !file.name.endsWith('.json')) { this.showError('JSONファイルを選択してください'); return; } try { const data = await this.readJSONFile(file); this.displayData(data); } catch (error) { this.showError(`ファイル読み込みエラー: ${error.message}`); } }}
このクラスは、ユーザーが選択したファイルを読み込みます。
ファイルがJSON形式かどうかもチェックしています。 エラーが発生した場合は、分かりやすいメッセージを表示します。
ファイル読み込み機能を追加
実際にファイルを読み込む機能を追加しましょう。
readJSONFile(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (event) => { try { const jsonData = JSON.parse(event.target.result); resolve(jsonData); } catch (error) { reject(new Error('無効なJSONファイルです')); } }; reader.onerror = () => { reject(new Error('ファイル読み込みに失敗しました')); }; reader.readAsText(file); });}
displayData(data) { this.output.innerHTML = ` <h3>読み込み結果:</h3> <pre>${JSON.stringify(data, null, 2)}</pre> `;}
showError(message) { this.output.innerHTML = ` <div style="color: red;"> <h3>エラー:</h3> <p>${message}</p> </div> `;}
FileReader
を使ってファイルを読み込みます。
JSON.parse()
でテキストデータをJSONオブジェクトに変換します。
使用例です。
const reader = new LocalJSONReader('jsonFileInput', 'output');
これで、ユーザーがファイルを選択すると自動的に読み込まれます。
APIからJSON データを取得してみよう
RESTful API連携
Web APIからデータを取得する場合の実装例です。
class APIClient { constructor(baseURL, options = {}) { this.baseURL = baseURL.replace(/\/$/, ''); this.defaultHeaders = { 'Content-Type': 'application/json', ...options.headers }; this.timeout = options.timeout || 10000; } async request(endpoint, options = {}) { const url = `${this.baseURL}${endpoint}`; const config = { method: 'GET', headers: { ...this.defaultHeaders, ...options.headers }, ...options }; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.timeout); try { const response = await fetch(url, { ...config, signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`API エラー: ${response.status} ${response.statusText}`); } const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { throw new Error('レスポンスがJSON形式ではありません'); } return await response.json(); } catch (error) { clearTimeout(timeoutId); if (error.name === 'AbortError') { throw new Error('リクエストタイムアウト'); } throw error; } }}
このクラスは、Web APIとの通信を簡単にしてくれます。
タイムアウト機能や適切なエラーハンドリングも含まれています。 レスポンスがJSON形式かどうかもチェックしています。
HTTPメソッドを追加
GETだけでなく、POST、PUT、DELETEも使えるようにしましょう。
// GET requestasync get(endpoint, params = {}) { const queryString = new URLSearchParams(params).toString(); const url = queryString ? `${endpoint}?${queryString}` : endpoint; return this.request(url);}
// POST requestasync post(endpoint, data) { return this.request(endpoint, { method: 'POST', body: JSON.stringify(data) });}
// PUT requestasync put(endpoint, data) { return this.request(endpoint, { method: 'PUT', body: JSON.stringify(data) });}
// DELETE requestasync delete(endpoint) { return this.request(endpoint, { method: 'DELETE' });}
使用例を見てみましょう。
const api = new APIClient('https://api.example.com', { headers: { 'Authorization': 'Bearer your-token-here' }, timeout: 15000});
// ユーザー一覧を取得api.get('/users', { page: 1, limit: 10 }) .then(users => console.log('ユーザー一覧:', users)) .catch(error => console.error('API エラー:', error));
// 新しいユーザーを作成api.post('/users', { name: '新しいユーザー', email: 'new@example.com'}) .then(newUser => console.log('ユーザー作成成功:', newUser)) .catch(error => console.error('作成エラー:', error));
様々なAPIと簡単に連携できます。
エラーハンドリングをマスターしよう
包括的なエラー処理
しっかりとしたエラーハンドリングを実装してみましょう。
class RobustJSONLoader { constructor() { this.errorHandlers = new Map(); } registerErrorHandler(errorType, handler) { this.errorHandlers.set(errorType, handler); } async loadJSON(url) { try { const response = await fetch(url); await this.handleHTTPErrors(response); const data = await response.json(); return data; } catch (error) { return this.handleError(error, url); } } async handleHTTPErrors(response) { if (!response.ok) { switch (response.status) { case 404: throw new NetworkError('ファイルが見つかりません', 'NOT_FOUND'); case 403: throw new NetworkError('アクセスが拒否されました', 'FORBIDDEN'); case 500: throw new NetworkError('サーバーエラーが発生しました', 'SERVER_ERROR'); default: throw new NetworkError(`HTTP エラー: ${response.status}`, 'HTTP_ERROR'); } } }}
このクラスは、様々なエラーを適切に分類して処理します。
HTTPステータスコードに応じて、具体的なエラーメッセージを生成します。 エラーの種類ごとに異なる処理を実行することもできます。
カスタムエラークラス
専用のエラークラスを作ってみましょう。
class NetworkError extends Error { constructor(message, code) { super(message); this.name = 'NetworkError'; this.code = code; }}
handleError(error, url) { let errorType = 'UNKNOWN_ERROR'; let userMessage = 'データの読み込みに失敗しました'; if (error instanceof NetworkError) { errorType = error.code; userMessage = error.message; } else if (error.name === 'SyntaxError') { errorType = 'INVALID_JSON'; userMessage = 'JSONファイルの形式が正しくありません'; } else if (error.name === 'TypeError') { errorType = 'NETWORK_ERROR'; userMessage = 'ネットワークエラーが発生しました'; } // 登録されたエラーハンドラーを実行 if (this.errorHandlers.has(errorType)) { this.errorHandlers.get(errorType)(error, url); } console.error(`JSON読み込みエラー [${errorType}]:`, { url, error: error.message }); return { success: false, error: { type: errorType, message: userMessage, details: error.message } };}
使用例です。
const robustLoader = new RobustJSONLoader();
// エラーハンドラーを登録robustLoader.registerErrorHandler('NOT_FOUND', (error, url) => { console.log(`代替データを使用します: ${url}`); // 代替データの読み込み処理});
robustLoader.registerErrorHandler('NETWORK_ERROR', (error, url) => { console.log('オフラインモードに切り替えます'); // オフライン処理});
これで、エラーの種類に応じた柔軟な対応ができます。
パフォーマンスを監視してみよう
読み込み時間の測定
データの読み込み時間を測定する機能を作ってみましょう。
class PerformanceJSONLoader { constructor() { this.metrics = []; } async loadWithMetrics(url) { const startTime = performance.now(); try { const response = await fetch(url); const parseStartTime = performance.now(); const data = await response.json(); const endTime = performance.now(); // メトリクスを記録 const metrics = { url, requestTime: parseStartTime - startTime, parseTime: endTime - parseStartTime, totalTime: endTime - startTime, dataSize: JSON.stringify(data).length, timestamp: new Date().toISOString() }; this.metrics.push(metrics); this.logMetrics(metrics); return data; } catch (error) { const endTime = performance.now(); this.metrics.push({ url, error: error.message, totalTime: endTime - startTime, timestamp: new Date().toISOString() }); throw error; } } logMetrics(metrics) { console.log('📊 JSON読み込みメトリクス:', { URL: metrics.url, リクエスト時間: `${metrics.requestTime.toFixed(2)}ms`, パース時間: `${metrics.parseTime.toFixed(2)}ms`, 合計時間: `${metrics.totalTime.toFixed(2)}ms`, データサイズ: `${(metrics.dataSize / 1024).toFixed(2)}KB` }); }}
このクラスは、JSON読み込みのパフォーマンスを詳細に測定します。
リクエスト時間、パース時間、データサイズなどを記録して、ボトルネックを特定できます。
パフォーマンスレポート
測定結果をまとめて表示する機能も追加しましょう。
getPerformanceReport() { if (this.metrics.length === 0) { return '利用可能なメトリクスがありません'; } const successfulRequests = this.metrics.filter(m => !m.error); const totalRequests = this.metrics.length; const successRate = (successfulRequests.length / totalRequests) * 100; const avgRequestTime = successfulRequests.reduce((sum, m) => sum + m.requestTime, 0) / successfulRequests.length; const avgParseTime = successfulRequests.reduce((sum, m) => sum + m.parseTime, 0) / successfulRequests.length; const avgTotalTime = successfulRequests.reduce((sum, m) => sum + m.totalTime, 0) / successfulRequests.length; return { totalRequests, successRate: `${successRate.toFixed(1)}%`, averageRequestTime: `${avgRequestTime.toFixed(2)}ms`, averageParseTime: `${avgParseTime.toFixed(2)}ms`, averageTotalTime: `${avgTotalTime.toFixed(2)}ms` };}
使用例です。
const perfLoader = new PerformanceJSONLoader();
perfLoader.loadWithMetrics('data/large-dataset.json') .then(data => { console.log('データ読み込み完了'); console.log('パフォーマンスレポート:', perfLoader.getPerformanceReport()); });
パフォーマンスの問題を簡単に発見できます。
まとめ
JavaScriptでのJSON読み込みについて、基礎から実践的な応用まで詳しく解説しました。
重要なポイント
- fetchとasync/awaitで基本的な読み込み
- エラーハンドリングとリトライ機能
- キャッシュ機能でパフォーマンス向上
- バリデーションでデータ品質保証
実践のコツ
- タイムアウトとリトライでネットワーク問題に対応
- 型安全性を保つバリデーション実装
- パフォーマンス監視でボトルネック特定
- 分かりやすいエラーメッセージの提供
JSON読み込みは現代のWeb開発における基本スキルです。 適切な実装により、堅牢で高性能なWebアプリケーションを構築できるようになります。
まずは簡単な例から始めて、だんだんと高度な機能を追加してみましょう。 きっと、もっと便利で使いやすいアプリケーションが作れるようになりますよ。
ぜひ今日から、これらの技術を活用してみませんか?