API 利用のベストプラクティスは「安全・高速・壊れない」を同時に満たす設計
API を使うときに初心者がつまずきやすいのは、
「動くコード」と「正しいコード」の違い です。
API は動くだけなら簡単です。
でも、実際のアプリでは
ネットワークが遅い
レスポンスが壊れている
サーバーが落ちている
ユーザーが連打する
攻撃者が変なデータを送る
こういう“現実の世界”が常に起きます。
API 利用のベストプラクティスとは、
「現実の世界でも壊れない API の使い方」 を身につけることです。
ここでは、初心者が最初に押さえるべきポイントを
例題つきで深掘りしていきます。
API の基本原則:失敗を前提に設計する
API は「成功することもあるし、失敗することもある」
API を叩くとき、初心者がやりがちな誤りは
「成功する前提でコードを書く」 ことです。
例えば、こういうコード。
const res = await fetch("/api/user");
const data = await res.json();
console.log(data.name);
JavaScript一見普通ですが、実際には
レスポンスが 500 エラー
JSON が壊れている
ネットワークが切れた
タイムアウトした
など、いくらでも失敗します。
だから API 利用の基本は
「成功したらこうする、失敗したらこうする」
を必ず書くことです。
正しい書き方の例(成功・失敗を分ける)
async function fetchUser() {
try {
const res = await fetch("/api/user");
if (!res.ok) {
throw new Error(`サーバーエラー: ${res.status}`);
}
const data = await res.json();
return data;
} catch (err) {
console.error("ユーザー情報の取得に失敗:", err);
return null;
}
}
JavaScriptここで重要なのは、
レスポンスが 200 以外ならエラー扱い
JSON パース失敗も catch で拾う
失敗時は null を返して UI 側で分岐
という「壊れない設計」です。
API のパフォーマンス:無駄なリクエストを減らす
同じ API を何度も叩かない
初心者がよくやるミスは、
「必要以上に API を叩く」 ことです。
例えば、スクロールするたびに API を呼ぶ
ボタン連打で API が連続で飛ぶ
画面遷移のたびに同じデータを取得する
こういうのは、
サーバーにもユーザーにも負担です。
対策:キャッシュ・デバウンス・メモ化
例:検索ボックスで入力のたびに API を叩くのは危険です。
悪い例:
input.addEventListener("input", async () => {
const res = await fetch(`/api/search?q=${input.value}`);
});
JavaScript良い例(デバウンスで 300ms 以内の連続入力をまとめる):
let timer;
input.addEventListener("input", () => {
clearTimeout(timer);
timer = setTimeout(() => {
fetch(`/api/search?q=${input.value}`);
}, 300);
});
JavaScriptこれで、
「入力のたびに API」→「落ち着いたタイミングで 1 回だけ」
に変わります。
API のセキュリティ:信頼しない・漏らさない・改ざんさせない
API に送るデータは“絶対に信用しない”
ユーザーが入力した値は、
攻撃者が自由に書き換えられる前提で扱います。
例えば、サーバーに送る前に
フロント側でバリデーションしても、
攻撃者は JavaScript を無視して送信できます。
だから API のセキュリティは
フロントでバリデーション(UX のため)
サーバーでバリデーション(安全のため)
の二段構えが基本です。
API キーをフロントに埋め込まない
初心者がやりがちな危険行為:
const API_KEY = "SECRET_ABC123"; // GitHub に上げてしまう
JavaScriptこれは 絶対に NG です。
API キーは必ずサーバー側で扱い、
フロントからは触れないようにします。
API のレスポンス設計:UI とセットで考える
API の結果を UI にどう反映するかが重要
API の結果は、
成功・失敗・読み込み中
の 3 状態を UI に反映する必要があります。
例:ユーザー情報を表示する UI
async function showUser() {
userBox.textContent = "読み込み中…";
const user = await fetchUser();
if (!user) {
userBox.textContent = "取得に失敗しました。再読み込みしてください。";
return;
}
userBox.textContent = `${user.name} さん`;
}
JavaScriptここで大事なのは、
読み込み中
成功
失敗
の 3 状態を UI で明確に分けていることです。
API の並列処理:Promise.all で高速化する
独立した API は同時に叩く方が速い
悪い例(直列):
const user = await fetch("/api/user");
const posts = await fetch("/api/posts");
JavaScript良い例(並列):
const [user, posts] = await Promise.all([
fetch("/api/user"),
fetch("/api/posts")
]);
JavaScriptこれだけで、
待ち時間が半分になることもある ので、
非同期パフォーマンスの基本テクニックです。
API のタイムアウト:永遠に待たない
fetch はデフォルトで“永遠に待つ”
初心者が知らない落とし穴:
await fetch("/api/slow");
JavaScriptこれは、
サーバーが応答しない限り永遠に待ち続けます。
対策:AbortController を使う
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
try {
const res = await fetch("/api/slow", { signal: controller.signal });
const data = await res.json();
} catch (err) {
console.log("タイムアウトしました");
}
clearTimeout(timeout);
JavaScriptこれで
「5 秒以内に返ってこなければ諦める」
という設計ができます。
API 利用のベストプラクティスまとめ
API は「動けばいい」ではなく
「失敗しても壊れない」「無駄に叩かない」「安全に扱う」
という視点で設計する必要があります。
成功・失敗・読み込み中の 3 状態を UI に反映する
レスポンスが壊れていても落ちないように try/catch を使う
Promise.all で並列化して高速化する
デバウンスやキャッシュで無駄なリクエストを減らす
API キーは絶対にフロントに置かない
タイムアウトを設けて永遠に待たない
サーバー側でも必ずバリデーションする
あなたが API を書くときに
「この API、失敗したらどうなる?」
「この API、本当に今必要?」
と一度でも考えられるようになったら、
それはもう“API を叩く人”から“API を設計できる人”への第一歩です。

