Antigravity で外部サービス(GitHub、Slack、Firebase、Supabase など)と連携する際、思わぬエラーが発生することがあります。このガイドでは、認証エラー「CORS エラー」「レート制限」「データ形式の不一致」など、連携エラーの原因と確実な修正方法を解説します。
外部サービス連携の仕組みと一般的なエラーパターン
Antigravity から外部サービスへのリクエストは、以下のフローで処理されます:
[Antigravity]
↓ HTTP/REST リクエスト
[ファイアウォール / プロキシ]
↓ リクエスト通過
[外部 API エンドポイント]
↓ 認証確認 → 権限チェック → リクエスト処理
[API レスポンス]
↓ JSON / データ返却
[Antigravity] クライアント処理
エラーは各ステップで発生する可能性があります。効率的に原因を特定するために、まずエラーメッセージの種類を把握しましょう。
エラーメッセージ分類と初期診断
HTTP ステータスコード別のエラー対応
| ステータスコード | 原因 | 対処法 |
|---|---|---|
| 400 Bad Request | リクエスト形式が不正 | Request body、パラメータを確認 |
| 401 Unauthorized | 認証に失敗 | API キーやトークンを再確認 |
| 403 Forbidden | 権限不足 | スコープ・パーミッションを確認 |
| 404 Not Found | エンドポイントが存在しない | API URL を確認 |
| 429 Too Many Requests | レート制限に達した | リトライロジック・キャッシュを実装 |
| 500 Internal Server Error | API サーバーエラー | リトライ・ステータスページを確認 |
| CORS Error | ブラウザから直接呼び出しの際のクロスオリジン問題 | バックエンドプロキシまたはサーバーサイド呼び出しを使用 |
原因別トラブルシューティング
原因 1: 認証エラー(401 / 403)
最も一般的な問題は API キーやトークンの設定です。
診断方法:
// コンソールログで実際のリクエストを確認
console.log('Auth Header:', headers.Authorization);
// 出力: Authorization: Bearer YOUR_API_KEY または undefined
// undefined なら認証が正しく設定されていない対処法:
GitHub API の場合:
// 正しい方法: Personal Access Token(PAT)を使用
const github = new Octokit({
auth: process.env.GITHUB_TOKEN, // .env から読み込み
});
// .env ファイル
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// テスト: 認証が正しいか確認
const user = await github.rest.users.getAuthenticated();
console.log('Authenticated as:', user.data.login);Slack API の場合:
// Bot Token を使用(Slack App から取得)
const slack = new WebClient(process.env.SLACK_BOT_TOKEN);
// スコープ確認(必要な権限が付与されているか)
// 例: chat:write, files:write が必要な場合、Bot Token のスコープに含まれているか確認
const auth = await slack.auth.test();
console.log('Bot scopes:', auth.response_metadata.messages[0]);
// スコープが不足していれば Slack App 設定で追加Google / Gemini API の場合:
// API キーの有効期限確認
// Google Cloud Console > APIs & Services > Credentials > API Key
// 問題がある場合、新しいキーを作成
const genai = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);
const model = genai.getGenerativeModel({ model: "gemini-2-flash" });
// テスト呼び出し
const result = await model.generateContent("Test prompt");認証トークンの有効期限チェック:
// JWT トークンの場合、有効期限を確認
const jwt = require('jsonwebtoken');
const decoded = jwt.decode(token);
console.log('Token expires at:', new Date(decoded.exp * 1000));
// 有効期限が切れていたら、リフレッシュトークンで新しいトークンを取得
if (Date.now() > decoded.exp * 1000) {
const newToken = await refreshToken(refreshToken);
// 新しいトークンで再試行
}原因 2: CORS エラー
ブラウザから直接外部 API を呼び出す際に発生:
エラーメッセージ例:
Access to XMLHttpRequest at 'https://api.github.com/user' from origin 'http://localhost:3000'
has been blocked by CORS policy:
Response to preflight request doesn't have required access-control-allow-origin header.
診断方法:
# ブラウザコンソールで CORS エラーが出ているか確認
# Network タブで OPTIONS リクエストが 403 で失敗しているか確認対処法 1: バックエンドプロキシを使用(推奨):
// Antigravity バックエンド
app.post('/api/github-proxy', async (req, res) => {
try {
// サーバーサイドから GitHub API を呼び出し(CORS 制限なし)
const response = await fetch('https://api.github.com/user', {
headers: {
'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`,
'Accept': 'application/vnd.github.v3+json'
}
});
const data = await response.json();
res.json(data); // クライアントに返す
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// クライアント側
const response = await fetch('/api/github-proxy', { method: 'POST' });
const user = await response.json();対処法 2: CORS ヘッダーを自分で設定(API 側が非対応の場合):
// Antigravity のバックエンド(Express.js 例)
const cors = require('cors');
// 特定のオリジンのみ許可
app.use(cors({
origin: ['http://localhost:3000', 'https://yourdomain.com'],
credentials: true
}));対処法 3: 外部サービスの CORS 設定を確認・変更:
- GitHub API: CORS に対応済み(特別な設定不要)
- Firebase: Firebase SDK 経由でアクセス(自動的に CORS 対応)
- Stripe: CORS に対応済み(ホワイトドメイン設定をダッシュボードで確認)
原因 3: レート制限エラー(429)
API のレート制限に達した場合:
診断方法:
# ログでレート制限ヘッダーを確認
# Response Headers:
# X-RateLimit-Limit: 60
# X-RateLimit-Remaining: 0
# X-RateLimit-Reset: 1640000000 (Unix timestamp)対処法 1: リトライロジック(指数バックオフ)の実装:
async function callApiWithRateLimit(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429) {
// レート制限エラー
const retryAfter = error.response.headers['retry-after'] || Math.pow(2, i);
console.log(`Rate limited. Retrying after ${retryAfter}s`);
await new Promise(resolve =>
setTimeout(resolve, retryAfter * 1000)
);
} else {
throw error;
}
}
}
}
// 使用例
const result = await callApiWithRateLimit(
() => github.rest.repos.get({ owner: 'google', repo: 'antigravity' })
);対処法 2: リクエストキャッシング:
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 3600 }); // 1時間キャッシュ
async function getGitHubUserCached(username) {
const cacheKey = `github-user-${username}`;
// キャッシュにあれば返す
const cached = cache.get(cacheKey);
if (cached) return cached;
// なければ API 呼び出し
const response = await github.rest.users.getByUsername({ username });
// キャッシュに保存
cache.set(cacheKey, response.data);
return response.data;
}対処法 3: バッチリクエスト・GraphQL の活用:
// REST API は複数の呼び出しが必要→レート制限に引っかかりやすい
// ❌ 非効率
for (let i = 0; i < 100; i++) {
const repo = await github.rest.repos.get({
owner: 'google',
repo: `antigravity-${i}`
});
}
// ✅ 効率的: GraphQL で複数リポジトリを一度に取得
const query = `
query {
repository1: repository(owner: "google", name: "antigravity-1") { name }
repository2: repository(owner: "google", name: "antigravity-2") { name }
...(最大 10 個程度を 1 リクエストで)
}
`;原因 4: データ形式の不一致
API が返すデータ形式が予期と異なる場合:
診断方法:
// API レスポンスの形式を確認
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log('Response type:', typeof data);
console.log('Response keys:', Object.keys(data));
console.log('Full response:', JSON.stringify(data, null, 2));対処法 1: スキーマ検証ライブラリの使用:
const zod = require('zod');
// 期待するデータ形式を定義
const UserSchema = zod.object({
id: zod.number(),
name: zod.string(),
email: zod.string().email(),
created_at: zod.string().datetime(),
});
// API レスポンスを検証
const response = await fetch('https://api.example.com/user/123');
const data = await response.json();
try {
const validData = UserSchema.parse(data);
console.log('Valid:', validData);
} catch (error) {
console.error('Data format mismatch:', error.errors);
// 例: [{ code: 'invalid_type', path: ['email'], message: 'Expected string, got undefined' }]
}対処法 2: データ変換・マッピング:
// API は snake_case で返すが、アプリは camelCase を使う
function convertSnakeToCamel(obj) {
if (Array.isArray(obj)) {
return obj.map(convertSnakeToCamel);
}
if (obj !== null && typeof obj === 'object') {
const result = {};
for (const key in obj) {
const camelKey = key.replace(/_([a-z])/g, (g) => g[1].toUpperCase());
result[camelKey] = convertSnakeToCamel(obj[key]);
}
return result;
}
return obj;
}
// 使用例
const apiData = {
user_id: 123,
user_name: 'John Doe',
created_at: '2026-03-29'
};
const appData = convertSnakeToCamel(apiData);
// { userId: 123, userName: 'John Doe', createdAt: '2026-03-29' }原因 5: ネットワーク問題・タイムアウト
API 呼び出しが応答なく失敗する場合:
診断方法:
# ネットワーク接続を確認
ping api.github.com
curl -I https://api.github.com
# DNS 解決の確認
nslookup api.github.com対処法:
// タイムアウト時間を設定
async function fetchWithTimeout(url, options = {}) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
return response;
} finally {
clearTimeout(timeoutId);
}
}
// リトライロジック付き呼び出し
async function robustFetch(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fetchWithTimeout(url);
} catch (error) {
if (i === maxRetries - 1) throw error;
const delay = Math.pow(2, i) * 1000; // 指数バックオフ
console.log(`Attempt ${i + 1} failed. Retrying in ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}全体を振り返って
外部サービス連携エラーは、認証 → CORS → レート制限 → データ形式 → ネットワーク という順序で原因を切り分けるのが効果的です。各エラーに対応するコード例を参考に、ロバストな連携を実装しましょう。さらに詳しい実装パターンについては「MCP サーバーガイド」や「GitHub 統合」もご参照ください。