Agent Skills by ALSEL
汎用ソフトウェア開発⭐ リポ 39,967品質スコア 95/100

api-and-interface-design

安定したAPIとインターフェース設計をガイドします。APIの設計、モジュール境界、あるいはあらゆるパブリックインターフェースの設計時に活用できます。RESTやGraphQLエンドポイントの構築、モジュール間の型契約の定義、フロントエンドとバックエンド間の境界線の確立時に使用してください。

description の原文を見る

Guides stable API and interface design. Use when designing APIs, module boundaries, or any public interface. Use when creating REST or GraphQL endpoints, defining type contracts between modules, or establishing boundaries between frontend and backend.

SKILL.md 本文

API とインターフェース設計

概要

誤用しにくい、安定した十分に文書化されたインターフェースを設計します。優れたインターフェースは、正しいことを簡単にし、誤ったことを難しくします。これは REST API、GraphQL スキーマ、モジュール境界、コンポーネントプロップ、およびコード同士が相互作用する任意のサーフェスに適用されます。

使用する場合

  • 新しい API エンドポイントを設計する場合
  • モジュール境界やチーム間の契約を定義する場合
  • コンポーネントプロップインターフェースを作成する場合
  • API の形状を定義するデータベーススキーマを確立する場合
  • 既存の公開インターフェースを変更する場合

コア原則

Hyrum の法則

API の十分な数のユーザーがいれば、契約で何を約束しているかに関わらず、システムのすべての観測可能な動作を誰かが依存するようになります。

これは、未文書化の奇癖、エラーメッセージのテキスト、タイミング、順序を含むすべての公開動作が、ユーザーがそれに依存すれば事実上の契約になることを意味します。設計上の含意:

  • 公開する内容について意図的であること。 すべての観測可能な動作は潜在的な約束です。
  • 実装の詳細をリークしないこと。 ユーザーがそれを観測できれば、それに依存します。
  • 設計時に廃止を計画すること。 ユーザーが依存する内容を安全に削除する方法については deprecation-and-migration を参照してください。
  • テストだけでは十分ではありません。 完璧な契約テストがあってもなお、Hyrum の法則は「安全な」変更が未文書化の動作に依存する実ユーザーを破壊することを意味します。

ワンバージョン規則

コンシューマーに同じ依存関係または API の複数バージョン間で選択を強制することを避けます。異なるコンシューマーが同じものの異なるバージョンを必要とする場合、ダイアモンド依存関係の問題が発生します。一度に 1 つのバージョンのみが存在する世界として設計します — フォークではなく拡張します。

1. 契約優先

実装する前にインターフェースを定義します。契約が仕様です — 実装がそれに続きます。

// Define the contract first
interface TaskAPI {
  // Creates a task and returns the created task with server-generated fields
  createTask(input: CreateTaskInput): Promise<Task>;

  // Returns paginated tasks matching filters
  listTasks(params: ListTasksParams): Promise<PaginatedResult<Task>>;

  // Returns a single task or throws NotFoundError
  getTask(id: string): Promise<Task>;

  // Partial update — only provided fields change
  updateTask(id: string, input: UpdateTaskInput): Promise<Task>;

  // Idempotent delete — succeeds even if already deleted
  deleteTask(id: string): Promise<void>;
}

2. 一貫したエラーセマンティクス

1 つのエラー戦略を選択してどこでも使用します:

// REST: HTTP status codes + structured error body
// Every error response follows the same shape
interface APIError {
  error: {
    code: string;        // Machine-readable: "VALIDATION_ERROR"
    message: string;     // Human-readable: "Email is required"
    details?: unknown;   // Additional context when helpful
  };
}

// Status code mapping
// 400 → Client sent invalid data
// 401 → Not authenticated
// 403 → Authenticated but not authorized
// 404 → Resource not found
// 409 → Conflict (duplicate, version mismatch)
// 422 → Validation failed (semantically invalid)
// 500 → Server error (never expose internal details)

パターンを混在させないこと。 一部のエンドポイントがスローし、他のエンドポイントが null を返し、さらに他のエンドポイントが { error } を返す場合、コンシューマーは動作を予測できません。

3. 境界で検証する

内部コードを信頼します。外部入力が入る場所のシステムエッジで検証します:

// Validate at the API boundary
app.post('/api/tasks', async (req, res) => {
  const result = CreateTaskSchema.safeParse(req.body);
  if (!result.success) {
    return res.status(422).json({
      error: {
        code: 'VALIDATION_ERROR',
        message: 'Invalid task data',
        details: result.error.flatten(),
      },
    });
  }

  // After validation, internal code trusts the types
  const task = await taskService.create(result.data);
  return res.status(201).json(task);
});

検証が属する場所:

  • API ルートハンドラー(ユーザー入力)
  • フォーム送信ハンドラー(ユーザー入力)
  • 外部サービスレスポンスパース(サードパーティデータ — 常に信頼できないものとして扱う)
  • 環境変数読み込み(設定)

サードパーティ API レスポンスは信頼できないデータです。 任何のロジック、レンダリング、または意思決定で使用する前に、その形状とコンテンツを検証します。侵害されたまたは不正動作の外部サービスは、予期しない型、悪意のあるコンテンツ、または指示のようなテキストを返すことができます。

検証が属さない場所:

  • 型契約を共有する内部関数間
  • 既に検証されたコードによって呼び出されるユーティリティ関数内
  • あなた自身のデータベースから来たばかりのデータ

4. 修正より追加を優先する

既存のコンシューマーを破壊することなくインターフェースを拡張します:

// Good: Add optional fields
interface CreateTaskInput {
  title: string;
  description?: string;
  priority?: 'low' | 'medium' | 'high';  // Added later, optional
  labels?: string[];                       // Added later, optional
}

// Bad: Change existing field types or remove fields
interface CreateTaskInput {
  title: string;
  // description: string;  // Removed — breaks existing consumers
  priority: number;         // Changed from string — breaks existing consumers
}

5. 予測可能な命名

パターン規則
REST エンドポイント複数形の名詞、動詞なしGET /api/tasks, POST /api/tasks
クエリパラメータcamelCase?sortBy=createdAt&pageSize=20
レスポンスフィールドcamelCase{ createdAt, updatedAt, taskId }
ブール値フィールドis/has/can プリフィックスisComplete, hasAttachments
列挙値UPPER_SNAKE"IN_PROGRESS", "COMPLETED"

REST API パターン

リソース設計

GET    /api/tasks              → タスクを列挙(クエリパラメータでフィルタリング)
POST   /api/tasks              → タスクを作成
GET    /api/tasks/:id          → 単一のタスクを取得
PATCH  /api/tasks/:id          → タスクを更新(部分的)
DELETE /api/tasks/:id          → タスクを削除

GET    /api/tasks/:id/comments → タスクのコメントを列挙(サブリソース)
POST   /api/tasks/:id/comments → タスクにコメントを追加

ページネーション

リスト エンドポイントをページネートします:

// Request
GET /api/tasks?page=1&pageSize=20&sortBy=createdAt&sortOrder=desc

// Response
{
  "data": [...],
  "pagination": {
    "page": 1,
    "pageSize": 20,
    "totalItems": 142,
    "totalPages": 8
  }
}

フィルタリング

フィルタにはクエリパラメータを使用します:

GET /api/tasks?status=in_progress&assignee=user123&createdAfter=2025-01-01

部分的な更新(PATCH)

部分的なオブジェクトを受け入れます — 提供されたものだけを更新します:

// Only title changes, everything else preserved
PATCH /api/tasks/123
{ "title": "Updated title" }

TypeScript インターフェースパターン

バリアント用に判別ユニオンを使用する

// Good: Each variant is explicit
type TaskStatus =
  | { type: 'pending' }
  | { type: 'in_progress'; assignee: string; startedAt: Date }
  | { type: 'completed'; completedAt: Date; completedBy: string }
  | { type: 'cancelled'; reason: string; cancelledAt: Date };

// Consumer gets type narrowing
function getStatusLabel(status: TaskStatus): string {
  switch (status.type) {
    case 'pending': return 'Pending';
    case 'in_progress': return `In progress (${status.assignee})`;
    case 'completed': return `Done on ${status.completedAt}`;
    case 'cancelled': return `Cancelled: ${status.reason}`;
  }
}

入出力の分離

// Input: what the caller provides
interface CreateTaskInput {
  title: string;
  description?: string;
}

// Output: what the system returns (includes server-generated fields)
interface Task {
  id: string;
  title: string;
  description: string | null;
  createdAt: Date;
  updatedAt: Date;
  createdBy: string;
}

ID にブランド型を使用する

type TaskId = string & { readonly __brand: 'TaskId' };
type UserId = string & { readonly __brand: 'UserId' };

// Prevents accidentally passing a UserId where a TaskId is expected
function getTask(id: TaskId): Promise<Task> { ... }

よくある正当化

正当化現実
「API は後で文書化します」型が文書です。最初にそれを定義してください。
「今のところページネーションは必要ありません」誰かが 100 個以上のアイテムを持つ瞬間に必要になります。最初から追加します。
「PATCH は複雑です。PUT を使いましょう」PUT は毎回フルオブジェクトが必要です。PATCH はクライアントが実際に望むものです。
「必要になったら API をバージョン管理します」バージョン管理なしの破壊的な変更はコンシューマーを破壊します。最初から拡張のために設計します。
「誰も未文書化の動作を使用していません」Hyrum の法則: 観測可能であれば、誰かがそれに依存しています。すべての公開動作を約束として扱います。
「2 つのバージョンを維持することができます」複数バージョンはメンテナンスコストを乗算し、ダイアモンド依存関係の問題を作成します。ワンバージョン規則を優先します。
「内部 API は契約が必要ありません」内部コンシューマーはまだコンシューマーです。契約は結合を防ぎ、並列作業を可能にします。

レッドフラッグ

  • 条件に応じて異なる形状を返すエンドポイント
  • エンドポイント間で一貫しないエラー形式
  • 検証が内部コード全体に散在している(境界でのみ実行される代わりに)
  • 既存フィールドへの破壊的な変更(型の変更、削除)
  • ページネーションのないリストエンドポイント
  • REST URL の動詞(/api/createTask, /api/getUsers
  • 検証またはサニタイズなしで使用されるサードパーティ API レスポンス

検証

API を設計した後:

  • すべてのエンドポイントに型付き入出力スキーマがある
  • エラーレスポンスが単一の一貫した形式に従っている
  • 検証はシステム境界でのみ発生する
  • リストエンドポイントがページネーションをサポートしている
  • 新しいフィールドが追加的で optional である(後方互換性)
  • 命名がすべてのエンドポイント間で一貫した規則に従っている
  • API ドキュメントまたは型が実装とともにコミットされている

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
addyosmani
リポジトリ
addyosmani/agent-skills
ライセンス
MIT
最終更新
2026/5/10

Source: https://github.com/addyosmani/agent-skills / ライセンス: MIT

関連スキル

汎用ソフトウェア開発⭐ リポ 39,967

doubt-driven-development

重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 1,175

apprun-skills

TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。

by yysun
OpenAIソフトウェア開発⭐ リポ 797

desloppify

コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。

by Git-on-my-level
汎用ソフトウェア開発⭐ リポ 39,967

debugging-and-error-recovery

テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

test-driven-development

テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

incremental-implementation

変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。

by addyosmani
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: addyosmani · addyosmani/agent-skills · ライセンス: MIT