ライブラリなしで実戦運用できるfetchの型。GET/POST、タイムアウトとエラー処理を必ず入れるのがポイント。
小さな検証ページから本番のユーティリティまで、そのまま流用できます。



よく使うGETの最小型
HTML
<div id="result">Loading...</div>
<script>
async function getUser() {
  const ctrl = new AbortController();
  const timer = setTimeout(() => ctrl.abort(), 8000); // 8秒でタイムアウト

  try {
    const res = await fetch('https://jsonplaceholder.typicode.com/users/1', {
      signal: ctrl.signal,
      headers: { 'Accept': 'application/json' }
    });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const data = await res.json();
    document.getElementById('result').textContent = `ユーザー: ${data.name} / ${data.email}`;
  } catch (err) {
    document.getElementById('result').textContent = `失敗: ${err.message}`;
  } finally {
    clearTimeout(timer);
  }
}
getUser();
</script>
JSONをPOSTする最小形
HTML
<script>
async function createPost() {
  const body = { title: 'hello', content: 'world' };
  const res = await fetch('/api/posts', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  });
  const data = await res.json();
  console.log('作成結果', data);
}
</script>
再利用しやすい小さなラッパ
JavaScript
// api.js
export async function api(path, options = {}, timeout = 8000) {
  const ctrl = new AbortController();
  const id = setTimeout(() => ctrl.abort(), timeout);
  try {
    const res = await fetch(path, { signal: ctrl.signal, ...options });
    const type = res.headers.get('content-type') || '';
    const parse = type.includes('application/json') ? res.json() : res.text();
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return await parse;
  } finally {
    clearTimeout(id);
  }
}

・AbortControllerでタイムアウト(疑似)を実装
res.okを必ずチェック → 4xx/5xxを例外化
content-typeでJSON/テキストを自動判定して雑に使える