jpskill.com
🛠️ 開発・MCP コミュニティ

api-organization

Explains the standardized API organization pattern for this codebase. Use when creating new API endpoints, API clients, or modifying existing API structure. Covers the 5-file system (endpoint-types, endpoints, api-client, admin-api-client, protected-endpoints), role-based access patterns (admin vs regular users), and TypeScript type safety across the API layer. All API code lives in src/lib/api/ following this exact pattern.

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o api-organization.zip https://jpskill.com/download/17557.zip && unzip -o api-organization.zip && rm api-organization.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/17557.zip -OutFile "$d\api-organization.zip"; Expand-Archive "$d\api-organization.zip" -DestinationPath $d -Force; ri "$d\api-organization.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して api-organization.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → api-organization フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
4

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

API Organization Pattern

このスキルは、このコードベース全体で使用される標準化された API organization pattern を定義します。すべての外部 API 連携は、一貫性、型安全性、および保守性のために、同じ 5 ファイル構造に従います。

このスキルを使用する場面

このスキルは、以下の場合に使用します。

  • 新しい API エンドポイントまたは連携を作成する場合
  • 新しい API カテゴリまたはドメインを追加する場合
  • ロールベースの API アクセス(管理者 vs 一般ユーザー)を実装する場合
  • 既存の API 構造を変更する場合
  • API 呼び出しの認証を設定する場合
  • 型安全な API ラッパーを作成する場合

コア原則

  1. Single Source of Truth - すべての API URL は endpoints.ts で一度定義されます
  2. Type Safety - パラメータからレスポンスまで、完全な TypeScript カバレッジ
  3. Role-Based Access - 一般ユーザーと管理者用エンドポイントで別々のクライアント
  4. Centralized Auth - 認証はクライアントによって自動的に処理されます
  5. DRY Code - 再利用可能なクライアント関数、重複したエンドポイント定義はありません

5 ファイルシステム

すべての API コードは src/lib/api/ に存在し、正確に以下のファイルで構成されます。

src/lib/api/
├── endpoint-types.ts       # すべてのエンドポイントの TypeScript 型
├── endpoints.ts            # ドメインごとに整理された URL 定義
├── api-client.ts           # ジェネリックな認証済み API クライアント
├── admin-api-client.ts     # ロールチェック付きの管理者専用 API クライアント
└── protected-endpoints.ts  # 型安全なラッパー関数

ファイルの目的

1. endpoint-types.ts

  • API データ用のすべての TypeScript インターフェースを定義します
  • 型をドメイン(例:audiences、instances、membership)ごとに整理します
  • パラメータ型、レスポンス型、およびリクエストボディ DTO を含めます
  • 型を抽出するためのユーティリティ型を提供します

詳細な構造については、references/endpoint-types-pattern.md を参照してください。

2. endpoints.ts

  • すべての API エンドポイント URL を 1 か所で定義します
  • 型に一致する機能/ドメインごとに整理します
  • パラメータを受け取り URL を返す関数を使用します
  • 環境変数ベースの URL をサポートします

詳細な構造については、references/endpoints-pattern.md を参照してください。

3. api-client.ts

  • 自動認証付きのジェネリック API クライアント
  • エラー解析と処理
  • GET、POST、PUT、DELETE メソッドのサポート
  • サーバーサイド専用 ('use server')

実装については、references/api-client-pattern.md を参照してください。

4. admin-api-client.ts

  • 管理者専用 API クライアント
  • ロール検証(Admin/SuperAdmin グループ)
  • 権限チェック関数
  • 承認されていない場合は AdminAuthError をスローします

実装については、references/admin-api-client-pattern.md を参照してください。

5. protected-endpoints.ts

  • URL + 型 + クライアントを組み合わせた型安全なラッパー関数
  • endpoint-types の構造に合わせて整理されています
  • クリーンなインポートを提供します: import { api } from '@/lib/api/protected-endpoints'
  • 'use server' ディレクティブはありません(オブジェクトをエクスポートします)

詳細な構造については、references/protected-endpoints-pattern.md を参照してください。

認証システム

このアプリケーションは、認証に Supabase Auth を使用します。すべての API リクエストには、Supabase アクセストークンによる認証が必要です。

Supabase クライアント構造

src/lib/supabase/
├── client.ts      # ブラウザ側の Supabase クライアント
├── server.ts      # サーバー側の Supabase クライアント (RSC, Server Actions)
└── middleware.ts  # 認証 Cookie のリフレッシュ用ミドルウェアヘルパー

認証フロー

  1. ユーザーは Supabase 経由で認証します(メール/パスワード、OAuth など)
  2. Supabase はセッションを httpOnly Cookie に保存します
  3. ミドルウェアはリクエストごとにセッションをリフレッシュします
  4. サーバーコンポーネント/アクションは server.ts から createClient() を使用します
  5. API クライアントはセッションからアクセストークンを自動的に抽出します

詳細な実装については、references/supabase-auth-integration.md を参照してください。

ロールベースのアクセスパターン

一般ユーザー向けエンドポイント

自動 Supabase 認証で api-client.ts 関数を使用します。

import { apiGet, apiPost } from '@/lib/api/api-client';

// アクセストークンは Supabase セッションから自動的に抽出されます
const data = await apiGet<ResponseType>(url);

管理者専用エンドポイント

ロール検証で admin-api-client.ts 関数を使用します。

import { adminApiRequest, checkAdminPermission } from '@/lib/api/admin-api-client';

// 最初に管理者アクセスを検証します(データベースからユーザーロールをチェックします)
await checkAdminPermission(); // 管理者でない場合はスローします

// 管理者 API リクエストを作成します
const data = await adminApiRequest<ResponseType>(url, options);

管理者ロール

管理者ロールは users テーブルに保存されます。

  • users.role = 'admin' - 標準管理者アクセス
  • users.role = 'member' - 一般ユーザーアクセス

家族の最初のユーザーには、自動的に管理者ロールが割り当てられます。

新しい API エンドポイントの追加

新しい API をアプリケーションに統合する場合は、次の正確な順序に従ってください。

ステップ 1: endpoint-types.ts で型を定義する

// 1. レスポンス型を定義する
export interface ResourceItem {
  id: string;
  name: string;
  // ... API レスポンスからの他のフィールド
}

// 2. ミューテーションのリクエスト DTO を定義する
export interface CreateResourceDto {
  name: string;
  // ... 作成に必要なフィールド
}

// 3. EndpointParams インターフェースにパラメータ型を追加する
export interface EndpointParams {
  // ... 既存のドメイン

  resources: {
    list: void;              // パラメータは不要
    get: { id: string };     // ID が必要
    create: void;            // リクエストの本文、パラメータではない
    update: { id: string };
    delete: { id: string };
  };
}

// 4. EndpointResponses インターフェースにレスポンス型を追加する
export interface EndpointResponses {
  // ... 既存のドメイン

  resources: {
    list: ResourceItem[];
    get: ResourceItem;
    create: ResourceItem;
    update: ResourceItem;
    delete: void;
  };
}

// 5. EndpointBodies インターフェースにリクエストボディ型を追加する (必要な場合)
export interface EndpointBodies {
  // ... 既存のドメイン

  resources: {
    create: CreateResourceDto;
    update: CreateResourceDto;
  };
}

ステップ 2: endpoints.ts で URL を定義する

export const API_ENDPOINTS = {
  // ... 既存のカテゴリ

  resources: {
    list: () => `${API_BASE}/api/resources`,
    get: (id: string) => `${API_BASE}/api/resources/${id}`,
    create: ()

(原文がここで切り詰められています)
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

API Organization Pattern

This skill defines the standardized API organization pattern used throughout this codebase. All external API integrations follow the same 5-file structure for consistency, type safety, and maintainability.

When to Use This Skill

Use this skill when:

  • Creating new API endpoints or integrations
  • Adding new API categories or domains
  • Implementing role-based API access (admin vs regular users)
  • Modifying existing API structure
  • Setting up authentication for API calls
  • Creating type-safe API wrappers

Core Principles

  1. Single Source of Truth - All API URLs defined once in endpoints.ts
  2. Type Safety - Full TypeScript coverage from params to responses
  3. Role-Based Access - Separate clients for regular vs admin endpoints
  4. Centralized Auth - Authentication handled automatically by clients
  5. DRY Code - Reusable client functions, no duplicate endpoint definitions

The 5-File System

All API code lives in src/lib/api/ with exactly these files:

src/lib/api/
├── endpoint-types.ts       # TypeScript types for all endpoints
├── endpoints.ts            # URL definitions organized by domain
├── api-client.ts           # Generic authenticated API client
├── admin-api-client.ts     # Admin-only API client with role checks
└── protected-endpoints.ts  # Type-safe wrapper functions

File Purposes

1. endpoint-types.ts

  • Define all TypeScript interfaces for API data
  • Organize types by domain (e.g., audiences, instances, membership)
  • Include param types, response types, and request body DTOs
  • Provide utility types for extracting types

See references/endpoint-types-pattern.md for detailed structure.

2. endpoints.ts

  • Define all API endpoint URLs in one place
  • Organize by feature/domain matching types
  • Use functions that accept parameters and return URLs
  • Support environment variable base URLs

See references/endpoints-pattern.md for detailed structure.

3. api-client.ts

  • Generic API client with automatic authentication
  • Error parsing and handling
  • Support for GET, POST, PUT, DELETE methods
  • Server-side only ('use server')

See references/api-client-pattern.md for implementation.

4. admin-api-client.ts

  • Admin-specific API client
  • Role validation (Admin/SuperAdmin groups)
  • Permission checking functions
  • Throws AdminAuthError if unauthorized

See references/admin-api-client-pattern.md for implementation.

5. protected-endpoints.ts

  • Type-safe wrapper functions combining URLs + types + clients
  • Organized to match endpoint-types structure
  • Provides clean import: import { api } from '@/lib/api/protected-endpoints'
  • No 'use server' directive (exports objects)

See references/protected-endpoints-pattern.md for detailed structure.

Authentication System

This application uses Supabase Auth for authentication. All API requests require authentication via Supabase access tokens.

Supabase Client Structure

src/lib/supabase/
├── client.ts      # Browser-side Supabase client
├── server.ts      # Server-side Supabase client (RSC, Server Actions)
└── middleware.ts  # Middleware helper for auth cookie refresh

Auth Flow

  1. User authenticates via Supabase (email/password, OAuth, etc.)
  2. Supabase stores session in httpOnly cookies
  3. Middleware refreshes session on every request
  4. Server components/actions use createClient() from server.ts
  5. API client extracts access token from session automatically

See references/supabase-auth-integration.md for detailed implementation.

Role-Based Access Pattern

Regular User Endpoints

Use api-client.ts functions with automatic Supabase auth:

import { apiGet, apiPost } from '@/lib/api/api-client';

// Access token extracted from Supabase session automatically
const data = await apiGet<ResponseType>(url);

Admin-Only Endpoints

Use admin-api-client.ts functions with role validation:

import { adminApiRequest, checkAdminPermission } from '@/lib/api/admin-api-client';

// Validate admin access first (checks user role from database)
await checkAdminPermission(); // Throws if not admin

// Make admin API request
const data = await adminApiRequest<ResponseType>(url, options);

Admin Roles

Admin roles are stored in the users table:

  • users.role = 'admin' - Standard admin access
  • users.role = 'member' - Regular user access

First user in a family is automatically assigned admin role.

Adding New API Endpoints

Follow this exact order when integrating a new API into the application:

Step 1: Define Types in endpoint-types.ts

// 1. Define response type(s)
export interface ResourceItem {
  id: string;
  name: string;
  // ... other fields from your API response
}

// 2. Define request DTO(s) for mutations
export interface CreateResourceDto {
  name: string;
  // ... fields required to create
}

// 3. Add parameter types to EndpointParams interface
export interface EndpointParams {
  // ... existing domains

  resources: {
    list: void;              // No params needed
    get: { id: string };     // Requires ID
    create: void;            // Body in request, not params
    update: { id: string };
    delete: { id: string };
  };
}

// 4. Add response types to EndpointResponses interface
export interface EndpointResponses {
  // ... existing domains

  resources: {
    list: ResourceItem[];
    get: ResourceItem;
    create: ResourceItem;
    update: ResourceItem;
    delete: void;
  };
}

// 5. Add request body types to EndpointBodies interface (if needed)
export interface EndpointBodies {
  // ... existing domains

  resources: {
    create: CreateResourceDto;
    update: CreateResourceDto;
  };
}

Step 2: Define URLs in endpoints.ts

export const API_ENDPOINTS = {
  // ... existing categories

  resources: {
    list: () => `${API_BASE}/api/resources`,
    get: (id: string) => `${API_BASE}/api/resources/${id}`,
    create: () => `${API_BASE}/api/resources`,
    update: (id: string) => `${API_BASE}/api/resources/${id}`,
    delete: (id: string) => `${API_BASE}/api/resources/${id}`,
  },
};

Step 3: Add Wrapper in protected-endpoints.ts

export const api = {
  // ... existing domains

  resources: {
    async list(): Promise<ResourceItem[]> {
      return apiGet<ResourceItem[]>(
        API_ENDPOINTS.resources.list()
      );
    },

    async get(id: string): Promise<ResourceItem> {
      return apiGet<ResourceItem>(
        API_ENDPOINTS.resources.get(id)
      );
    },

    async create(data: CreateResourceDto): Promise<ResourceItem> {
      return apiPost<ResourceItem, CreateResourceDto>(
        API_ENDPOINTS.resources.create(),
        data
      );
    },

    async update(id: string, data: CreateResourceDto): Promise<ResourceItem> {
      return apiPut<ResourceItem, CreateResourceDto>(
        API_ENDPOINTS.resources.update(id),
        data
      );
    },

    async delete(id: string): Promise<void> {
      return apiDelete<void>(
        API_ENDPOINTS.resources.delete(id)
      );
    },
  },
};

Step 4: Use in Application Code

'use server';

import { api } from '@/lib/api/protected-endpoints';

// In a server component or server action
const resources = await api.resources.list();
const resource = await api.resources.get(id);
const newResource = await api.resources.create({
  name: 'New Resource'
});

Naming Conventions

Endpoint Operations

  • list / listAll - GET multiple items
  • get - GET single item
  • create - POST new item
  • update - PUT/PATCH existing item
  • delete - DELETE item

Type Naming

  • Response types: PascalCase describing entity (e.g., AudienceListItem)
  • DTOs: PascalCase with suffix (e.g., CreateUserDto, UpdateSettingsDto)
  • Interfaces match plural for collections, singular for items

Error Handling

All API clients handle errors automatically:

try {
  const data = await api.myFeature.get(id);
} catch (error) {
  // Error already parsed and formatted
  console.error('API error:', error.message);
}

Common error types:

  • AdminAuthError - Admin permission denied
  • AdminApiError - Admin API request failed
  • Generic errors from api-client with parsed messages

Authentication Flow

Regular Endpoints

  1. Client calls protected endpoint wrapper (e.g., api.resources.list())
  2. Wrapper calls apiGet/apiPost/etc from api-client
  3. api-client calls getAuthHeaders()
  4. getAuthHeaders uses Supabase server client to get session:
    const supabase = await createClient();
    const { data: { session } } = await supabase.auth.getSession();
    const accessToken = session?.access_token;
  5. Access token added to Authorization header
  6. Request sent with automatic authentication

Admin Endpoints

Same flow as above, but with additional role check:

  1. Call checkAdminPermission() first
  2. checkAdminPermission queries users table for current user's role
  3. Throws AdminAuthError if role is not 'admin'
  4. Then proceeds with normal authentication flow

Best Practices

  1. Never hardcode URLs - Always use API_ENDPOINTS
  2. Always define types first - Types drive implementation
  3. One wrapper per endpoint - Keep protected-endpoints clean
  4. Group by domain - Match structure across all 5 files
  5. Use helper functions - apiGet, apiPost, etc. handle auth
  6. Validate admin access early - Call checkAdminPermission() first
  7. Document complex endpoints - Add JSDoc comments
  8. Handle errors gracefully - API clients provide good error messages

Environment Variables

Required for Supabase Auth

  • NEXT_PUBLIC_SUPABASE_URL - Supabase project URL
  • NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY - Supabase anonymous public key

Required for API Clients

  • INSTANCE_API_URL or API_URL - Base URL for external API endpoints
  • NEXT_PUBLIC_SITE_URL - Site URL for redirects (optional, defaults to localhost:3000)

Database

  • Supabase connection is handled automatically via the Supabase client
  • No manual connection strings needed

Migration from Other Patterns

If migrating existing API code to this pattern:

  1. Extract all endpoint URLs to endpoints.ts
  2. Create types in endpoint-types.ts for params/responses
  3. Replace direct fetch calls with apiGet/apiPost/etc
  4. Add wrappers to protected-endpoints.ts
  5. Update imports to use api object

Example migration:

// Before (scattered fetch calls)
const response = await fetch(`${API_BASE}/api/resources/${id}`, {
  headers: { Authorization: `Bearer ${token}` }
});
const resource = await response.json();

// After (centralized pattern)
import { api } from '@/lib/api/protected-endpoints';
const resource = await api.resources.get(id); // Auth automatic, types included

References

See reference files for detailed implementation patterns:

  • references/supabase-auth-integration.md - Supabase auth setup and integration
  • references/endpoint-types-pattern.md - Type definition structure
  • references/endpoints-pattern.md - URL organization pattern
  • references/api-client-pattern.md - Generic client implementation with Supabase
  • references/admin-api-client-pattern.md - Admin client with role-based access
  • references/protected-endpoints-pattern.md - Wrapper function patterns

同梱ファイル

※ ZIPに含まれるファイル一覧。`SKILL.md` 本体に加え、参考資料・サンプル・スクリプトが入っている場合があります。