
JavaScriptでの外部API連携
2025-07-28はじめに
現代のWeb開発において、外部APIとの連携はほぼ必須のスキルです。この章では、JavaScriptを使って外部APIと通信する方法を、初心者の方にもわかりやすく詳細に解説します。API連携の基本概念から、実際のコード例、エラー処理、ベストプラクティスまで、実践的な知識を身につけましょう。
APIとは何か?
基本的な定義
API(Application Programming Interface)は、ソフトウェア同士が通信するためのインターフェースです。Web APIはHTTPプロトコルを使用してデータをやり取りします。
APIの種類
- RESTful API: HTTPメソッド(GET, POSTなど)を使用
- GraphQL API: クエリ言語を使用して必要なデータのみ取得
- SOAP API: XMLベースのプロトコル(現在はあまり使われない)
- WebSocket: 双方向リアルタイム通信
API連携の基本要素
1. エンドポイント(URL)
APIが提供する特定の機能へのアクセスポイントです。
例: https://api.example.com/users
2. HTTPメソッド
- GET: データの取得
- POST: データの作成
- PUT/PATCH: データの更新
- DELETE: データの削除
3. リクエストヘッダー
追加情報を提供します。よく使われるヘッダー:
Content-Type
: データ形式(application/jsonなど)Authorization
: 認証トークンAccept
: 受け入れ可能なレスポンス形式
4. リクエストボディ
POSTやPUTリクエストでサーバーに送信するデータ
5. クエリパラメータ
URLの末尾に追加するパラメータ
例: ?page=1&limit=10
6. ステータスコード
レスポンスの状態を示す3桁の数字:
- 200番台: 成功
- 400番台: クライアントエラー
- 500番台: サーバーエラー
fetch APIを使った基本的なAPI連携
現代のJavaScriptでは、fetch
APIが標準的なHTTPリクエストの方法です。
GETリクエストの例
async function fetchUsers() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const users = await response.json();
console.log('取得したユーザー:', users);
return users;
} catch (error) {
console.error('ユーザー取得に失敗:', error);
throw error;
}
}
fetchUsers().then(users => console.log('処理完了'));
POSTリクエストの例
async function createUser(userData) {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const newUser = await response.json();
console.log('作成されたユーザー:', newUser);
return newUser;
} catch (error) {
console.error('ユーザー作成に失敗:', error);
throw error;
}
}
const newUser = {
name: 'John Doe',
email: 'john@example.com'
};
createUser(newUser);
認証が必要なAPIの扱い方
多くのAPIは認証が必要です。主な認証方法:
1. APIキー
const apiKey = 'your_api_key_here';
async function fetchWeather(city) {
const response = await fetch(
`https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${city}`
);
// ...
}
2. Bearerトークン(JWTなど)
const token = 'your_token_here';
async function fetchProtectedData() {
const response = await fetch('https://api.example.com/protected', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// ...
}
3. OAuth
より複雑ですが、多くの公開APIで使用されています。
実際のAPI連携のステップバイステップ
1. APIドキュメントを読む
- 利用可能なエンドポイント
- 必要なパラメータ
- 認証方法
- レートリミット
- レスポンスの形式
2. ベースURLを設定
const API_BASE_URL = 'https://api.example.com/v1';
3. リクエスト関数を作成
async function makeApiRequest(endpoint, method = 'GET', body = null) {
const url = `${API_BASE_URL}${endpoint}`;
const options = {
method,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`
},
};
if (body) {
options.body = JSON.stringify(body);
}
try {
const response = await fetch(url, options);
if (response.status === 401) {
// 認証エラー処理
handleUnauthorized();
throw new Error('認証が必要です');
}
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'リクエストに失敗しました');
}
return await response.json();
} catch (error) {
console.error(`APIリクエストエラー (${method} ${endpoint}):`, error);
throw error;
}
}
4. 具体的なAPI関数を実装
// ユーザー一覧取得
async function getUsers() {
return makeApiRequest('/users');
}
// 特定ユーザー取得
async function getUser(id) {
return makeApiRequest(`/users/${id}`);
}
// ユーザー作成
async function createUser(userData) {
return makeApiRequest('/users', 'POST', userData);
}
よくある問題と解決策
1. CORSエラー
ブラウザのセキュリティ制約によるエラーです。
解決策:
- サーバー側でCORS設定を修正(Access-Control-Allow-Originなど)
- 開発時はプロキシサーバーを使用
- 必要に応じてモードを設定(非推奨)
fetch(url, {
mode: 'cors' // または 'no-cors'(制限あり)
});
2. レートリミット
APIの利用制限に達した場合のエラー。
解決策:
- リクエスト間隔を空ける
- エラー時のリトライ処理を実装
- レスポンスヘッダーを確認(X-RateLimit-*など)
async function fetchWithRetry(url, retries = 3) {
try {
const response = await fetch(url);
return response;
} catch (error) {
if (retries <= 0) throw error;
await new Promise(resolve => setTimeout(resolve, 1000));
return fetchWithRetry(url, retries - 1);
}
}
3. ネットワークエラー
解決策:
- タイムアウト設定
- エラーハンドリングの強化
async function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
signal: controller.signal
});
clearTimeout(timeoutId);
return response;
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
}
ベストプラクティス
- エラーハンドリングを徹底: ネットワークエラー、APIエラー、データパースエラーなど
- リクエストを抽象化: 共通関数を作成して重複を減らす
- セキュリティを考慮: APIキーをフロントエンドにハードコードしない
- パフォーマンス最適化: キャッシュ、並列リクエスト、不要なリクエストの削減
- テストを書く: API連携部分のテストを実装
- ログを残す: デバッグ用に適切なログを記録
- 型定義を使用: TypeScriptでAPIレスポンスの型を定義
実際のプロジェクトでのAPI連携例
天気情報アプリ
class WeatherApi {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.openweathermap.org/data/2.5';
}
async getCurrentWeather(city) {
const response = await fetch(
`${this.baseUrl}/weather?q=${city}&appid=${this.apiKey}&units=metric`
);
if (!response.ok) {
throw new Error(await this.getErrorMessage(response));
}
return await response.json();
}
async getErrorMessage(response) {
try {
const errorData = await response.json();
return errorData.message || '天気情報の取得に失敗しました';
} catch {
return `HTTPエラー: ${response.status}`;
}
}
}
// 使用例
const weatherApi = new WeatherApi('your_api_key');
async function displayWeather() {
try {
const weather = await weatherApi.getCurrentWeather('Tokyo');
console.log(`東京の気温: ${weather.main.temp}°C`);
} catch (error) {
console.error('エラー:', error.message);
}
}
displayWeather();
まとめ
外部API連携の重要なポイント:
- 現代のWeb開発ではAPI連携が不可欠
fetch
APIが標準的な方法- 適切なエラーハンドリングが重要
- 認証が必要なAPIが多い
- CORSなどのセキュリティ制約を理解
- コードを整理し、再利用可能な関数を作成
- パフォーマンスとセキュリティを考慮
- APIドキュメントをよく読むことが成功の鍵
API連携をマスターすると、外部サービスと連携した豊かなアプリケーションを作成できるようになります。
練習問題
問題1
以下のfetchリクエストにはいくつかの問題があります。それを指摘し、修正したコードを書いてください。
async function getPosts() {
const response = fetch('https://jsonplaceholder.typicode.com/posts');
const posts = response.json();
return posts;
}
問題2
次のAPI連携に関する記述について、正しいものには○、間違っているものには×をつけてください。
- APIキーはフロントエンドコードに直接書いても問題ない ( )
- fetch APIはPromiseを返す ( )
- CORSエラーはサーバー側の設定で回避できる ( )
- POSTリクエストではbodyにJSON文字列を指定する必要がある ( )
問題3
以下の要件を満たすAPIクライアントクラスを作成してください。
- ベースURLをコンストラクタで設定
- GET, POST, PUT, DELETEメソッドを実装
- すべてのリクエストに認証トークンを自動で付加
- エラーハンドリングを統一
- レスポンスのContent-Typeがapplication/jsonであることを確認
解答例
問題1の解答
問題点:
await
の欠如(fetchとjson()の両方)- エラーハンドリングがない
- レスポンスのステータスチェックがない
修正コード:
async function getPosts() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const posts = await response.json();
return posts;
} catch (error) {
console.error('投稿の取得に失敗:', error);
throw error;
}
}
問題2の解答
- × (APIキーは環境変数などで管理すべき)
- ○
- ○
- ○ (JSONを送信する場合)
問題3の解答
class ApiClient {
constructor(baseUrl, authToken) {
this.baseUrl = baseUrl;
this.authToken = authToken;
}
async request(endpoint, method = 'GET', body = null) {
const url = `${this.baseUrl}${endpoint}`;
const options = {
method,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.authToken}`
}
};
if (body) {
options.body = JSON.stringify(body);
}
try {
const response = await fetch(url, options);
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.message || 'リクエストに失敗しました');
}
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new Error('無効なコンテンツタイプ');
}
return await response.json();
} catch (error) {
console.error(`APIリクエストエラー (${method} ${endpoint}):`, error);
throw error;
}
}
get(endpoint) {
return this.request(endpoint);
}
post(endpoint, body) {
return this.request(endpoint, 'POST', body);
}
put(endpoint, body) {
return this.request(endpoint, 'PUT', body);
}
delete(endpoint) {
return this.request(endpoint, 'DELETE');
}
}
// 使用例
const api = new ApiClient('https://api.example.com/v1', 'your_token');
// GETリクエスト
api.get('/users').then(users => console.log(users));
// POSTリクエスト
api.post('/users', { name: 'John' }).then(user => console.log(user));