dot_claude/skills/api-design/SKILL.md
Use when designing or modifying any API endpoint, before writing handler code - contract-first approach covering resource modeling, URL design, schema conventions, versioning, and authentication that ensures the interface is right before implementation begins | APIエンドポイントの設計や変更時、ハンドラーコードを書く前に使用 - リソースモデリング、URL設計、スキーマ規約、バージョニング、認証を網羅するコントラクトファースト手法により、実装前にインターフェースの正しさを保証
npx skillsauth add lv416e/dotfiles api-designInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
APIs are contracts. Broken contracts break everyone downstream. Fixing a shipped API is ten times harder than designing it right.
Core principle: DESIGN THE API CONTRACT BEFORE IMPLEMENTING THE HANDLER. Implementation details leak into APIs when you code first.
Violating the letter of this process is violating the spirit of API design.
DESIGN THE API CONTRACT BEFORE IMPLEMENTING THE HANDLER
If you haven't written the OpenAPI spec (or equivalent contract), you cannot write handler code.
Always:
Use this ESPECIALLY when:
Don't skip when:
BEFORE touching URLs or HTTP methods:
Identify Resources, Not Actions
users, orders, invoicesgetUser, createOrder, sendInvoiceMap Relationships
/users/{id}/orders/orders?user_id=123Define Resource Representations
Distinguish Collection vs Instance
/orders (list, create)/orders/{id} (get, update, delete)URLs are the backbone of your API. Get them right.
| Rule | Good | Bad |
|------|------|-----|
| Plural nouns | /users, /orders | /user, /order |
| Kebab-case | /line-items | /lineItems, /line_items |
| No verbs | /orders + POST | /createOrder |
| No trailing slash | /users | /users/ |
| Lowercase only | /users/{id}/orders | /Users/{ID}/Orders |
Use methods correctly. They have semantics. Respect them.
| Method | Purpose | Idempotent | Safe | Example |
|--------|---------|------------|------|---------|
| GET | Read resource(s) | Yes | Yes | GET /orders/123 |
| POST | Create resource | No | No | POST /orders |
| PUT | Full replace | Yes | No | PUT /orders/123 |
| PATCH | Partial update | Yes | No | PATCH /orders/123 |
| DELETE | Remove resource | Yes | No | DELETE /orders/123 |
POST is not a catch-all. If you're using POST for everything, you're building RPC, not REST.
Actions that don't fit CRUD:
POST /orders/123/cancelPOST /order-cancellationsPOST /cancelOrderUse them. Use the RIGHT ones.
| Code | Meaning | When | |------|---------|------| | 200 | OK | Successful GET, PUT, PATCH, DELETE | | 201 | Created | Successful POST that created a resource | | 204 | No Content | Successful DELETE with no body | | 400 | Bad Request | Validation error, malformed input | | 401 | Unauthorized | Missing or invalid authentication | | 403 | Forbidden | Authenticated but not authorized | | 404 | Not Found | Resource doesn't exist | | 409 | Conflict | State conflict (duplicate, version mismatch) | | 422 | Unprocessable | Syntactically valid but semantically wrong | | 429 | Too Many Requests | Rate limit exceeded | | 500 | Internal Server Error | Server bug (never intentional) |
Don't return 200 with { "error": "something failed" }. That's lying to HTTP clients.
Version from day one. Not "when we need it."
Preferred: URL path versioning
/v1/users
/v2/users
Acceptable: Header versioning
Accept: application/vnd.myapi.v2+json
Unacceptable: No versioning You WILL break clients. It's a matter of when, not if.
Consistency is more important than cleverness.
Pick ONE envelope format. Use it EVERYWHERE.
{
"data": { ... },
"meta": {
"request_id": "abc-123",
"timestamp": "2024-01-15T10:30:00Z"
}
}
For collections:
{
"data": [ ... ],
"meta": {
"request_id": "abc-123",
"timestamp": "2024-01-15T10:30:00Z"
},
"pagination": {
"total": 142,
"page": 2,
"per_page": 20,
"next_cursor": "eyJpZCI6MTIzfQ=="
}
}
ONE error format. Consistent across ALL endpoints.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "email",
"message": "Must be a valid email address",
"code": "INVALID_FORMAT"
}
]
},
"meta": {
"request_id": "abc-123",
"timestamp": "2024-01-15T10:30:00Z"
}
}
Never return:
Cursor-based for large/real-time datasets:
GET /orders?cursor=eyJpZCI6MTIzfQ==&limit=20
Offset-based for small, stable datasets:
GET /orders?page=2&per_page=20
Always include: total count, current page/cursor, next page/cursor, per-page limit.
Always set a maximum per_page. Unbounded queries kill databases.
snake_case for JSON fields (most common convention)createdAt and updated_at2024-01-15T10:30:00ZSecurity is not optional. Design it in from the start.
| Pattern | Use When | |---------|----------| | OAuth 2.0 + JWT | User-facing APIs, third-party access | | API Keys | Server-to-server, simple integrations | | mTLS | Internal service mesh, high security |
API Keys:
Authorization: Bearer <key> or X-API-Key: <key>JWT:
GET /users/123/orders must verify caller can access user 123's ordersDesign it in. Don't bolt it on.
Headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1705312200
Retry-After headerWrite the OpenAPI spec BEFORE the handler.
openapi: 3.1.0
info:
title: Orders API
version: 1.0.0
paths:
/v1/orders:
get:
summary: List orders
parameters:
- name: cursor
in: query
schema:
type: string
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/OrderListResponse'
'401':
$ref: '#/components/responses/Unauthorized'
The spec is the source of truth. Generate types, validators, and documentation from it. Don't write them by hand.
When using GraphQL instead of REST:
type Query {
order(id: ID!): Order
orders(first: Int, after: String, filter: OrderFilter): OrderConnection!
}
type OrderConnection {
edges: [OrderEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
Good APIs tell you what you can do next.
Include relevant links in responses:
{
"data": {
"id": "order-123",
"status": "pending",
"links": {
"self": "/v1/orders/order-123",
"cancel": "/v1/orders/order-123/cancel",
"items": "/v1/orders/order-123/items",
"customer": "/v1/customers/cust-456"
}
}
}
At minimum, include self links. Full HATEOAS when clients need to discover transitions.
Breaking changes are trust violations.
Sunset header with removal dateSunset: Sat, 15 Jun 2025 00:00:00 GMT
Deprecation: true
Link: </v2/users>; rel="successor-version"
Never silently remove endpoints. Ever.
If you catch yourself:
ALL of these mean: STOP. Return to Phase 1.
| Excuse | Reality | |--------|---------| | "Internal API, doesn't need design" | Internal APIs become external. Design it right from the start. | | "Just one endpoint, don't need versioning" | One endpoint becomes twenty. Version from day one. | | "We'll add auth later" | Unauthenticated APIs get abused. Security from the start. | | "Database schema drives the API" | Database is implementation. API is contract. They're different. | | "POST for everything is simpler" | POST for everything is RPC. You lose HTTP semantics and caching. | | "Error format doesn't matter yet" | Inconsistent errors multiply. Fix on day one or fix forever. | | "Breaking change is fine, we control the client" | You control it today. Tomorrow you won't. | | "Spec is overhead, code is the spec" | Code drifts. Spec is the source of truth. | | "HATEOAS is over-engineering" | At minimum, include self links. Clients need discoverability. | | "Pagination can wait" | Unbounded queries will take down your database. Paginate from the start. |
| Phase | Key Activities | Success Criteria | |-------|---------------|------------------| | 1. Resource Modeling | Identify nouns, map relationships | Resources are clear, no verbs | | 2. URL Design | Define paths, methods, status codes | Consistent, RESTful, versioned | | 3. Schema Design | Envelope, errors, pagination, naming | One format everywhere | | 4. Auth | Authentication, authorization, rate limits | Security designed in | | 5. Contract Spec | OpenAPI/GraphQL schema | Spec exists before code | | 6. Discoverability | Links, HATEOAS | Clients can navigate the API | | 7. Compatibility | Deprecation plan, breaking change rules | No surprise breakage |
Before implementing any handler:
Can't check all boxes? You're not ready to write handler code.
This skill integrates with:
Complementary skills:
API spec → contract tests → handler implementation
Otherwise → not API design
No handler code without a contract. No exceptions without your human partner's permission.
development
Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like "the xlsx in my downloads") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.
testing
Use when creating new skills, editing existing skills, or verifying skills work before deployment - applies TDD to process documentation by testing with subagents before writing, iterating until bulletproof against rationalization | 新しいスキルの作成、既存スキルの編集、またはデプロイ前にスキルが機能するか検証する際に使用 - プロセスドキュメントにTDDを適用し、記述前にサブエージェントでテストし、合理化に対して堅牢になるまで反復
development
Use when design is complete and you need detailed implementation tasks for engineers with zero codebase context - creates comprehensive implementation plans with exact file paths, complete code examples, and verification steps assuming engineer has minimal domain knowledge | 設計が完了し、コードベースの知識がゼロのエンジニア向けに詳細な実装タスクが必要な場合に使用 - 正確なファイルパス、完全なコード例、検証ステップを含む包括的な実装計画を作成。エンジニアの領域知識が最小限であることを前提
tools
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.