seb1n/api-design
Design RESTful APIs with proper resource modeling, HTTP method semantics, status codes, pagination, versioning, and documentation.
npx skills add https://github.com/seb1n/awesome-ai-agent-skills --skill api-design
This skill enables an AI agent to design production-quality RESTful APIs. The agent models resources, defines endpoints with correct HTTP method semantics, selects appropriate status codes, implements pagination and versioning strategies, and produces OpenAPI documentation. The output follows REST constraints including statelessness, uniform interface, and resource-based URIs.
/tasks/{id}/comments).limit and offset (or cursor) query parameters. Support filtering via query parameters (e.g., ?status=active) and sorting with sort and order parameters. Return pagination metadata in the response body including total count, next/previous links./v1/tasks), query parameter (?version=1), or Accept header (Accept: application/vnd.api.v1+json). URI path versioning is simplest and most common. Ensure backward compatibility within a version and document deprecation timelines.X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) in response documentation.Provide the agent with a description of the application domain, the entities involved, and the operations users need to perform. The agent will produce endpoint definitions, request/response schemas, and an OpenAPI specification. You can iterate by requesting changes to specific endpoints, adding pagination, or adjusting error formats.
openapi: 3.0.3
info:
title: Task Management API
version: 1.0.0
description: RESTful API for managing tasks and projects.
servers:
- url: https://api.example.com/v1
paths:
/tasks:
get:
summary: List all tasks
parameters:
- name: status
in: query
schema:
type: string
enum: [pending, in_progress, done]
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
- name: cursor
in: query
schema:
type: string
responses:
"200":
description: Paginated list of tasks
headers:
X-RateLimit-Limit:
schema:
type: integer
X-RateLimit-Remaining:
schema:
type: integer
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: "#/components/schemas/Task"
pagination:
$ref: "#/components/schemas/CursorPagination"
post:
summary: Create a new task
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/TaskCreate"
responses:
"201":
description: Task created
content:
application/json:
schema:
$ref: "#/components/schemas/Task"
"422":
description: Validation error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/tasks/{taskId}:
get:
summary: Get a task by ID
parameters:
- name: taskId
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: Task details
"404":
description: Task not found
components:
schemas:
Task:
type: object
properties:
id:
type: string
format: uuid
title:
type: string
description:
type: string
status:
type: string
enum: [pending, in_progress, done]
created_at:
type: string
format: date-time
TaskCreate:
type: object
required: [title]
properties:
title:
type: string
maxLength: 255
description:
type: string
assignee_id:
type: string
format: uuid
CursorPagination:
type: object
properties:
next_cursor:
type: string
nullable: true
has_more:
type: boolean
ErrorResponse:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
details:
type: array
items:
type: object
properties:
field:
type: string
reason:
type: string
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed.",
"details": [
{
"field": "title",
"reason": "Title is required and cannot be empty."
},
{
"field": "assignee_id",
"reason": "Must be a valid UUID."
}
],
"request_id": "req_abc123",
"documentation_url": "https://api.example.com/docs/errors#VALIDATION_ERROR"
}
}
Standard error codes to use consistently across all endpoints:
| HTTP Status | Error Code | Meaning |
|---|---|---|
| 400 | BAD_REQUEST | Malformed request syntax |
| 401 | UNAUTHORIZED | Missing or invalid authentication |
| 403 | FORBIDDEN | Authenticated but insufficient permissions |
| 404 | NOT_FOUND | Resource does not exist |
| 409 | CONFLICT | Resource state conflict (e.g., duplicate) |
| 422 | VALIDATION_ERROR | Semantic validation failure |
| 429 | RATE_LIMITED | Too many requests |
| 500 | INTERNAL_ERROR | Unexpected server error |
/tasks, not /task) and avoid verbs in URIs. Actions that don't map to CRUD should use sub-resources (e.g., POST /tasks/{id}/archive).Idempotency-Key headers on POST requests. PUT and DELETE are naturally idempotent; document this behavior clearly.X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) on every response so clients can self-throttle._links with self, next, prev, and related resource URIs where appropriate.Sunset and Deprecation headers.Location header on 201 Created responses pointing to the newly created resource URI.200 OK with an empty data array and has_more: false, not 404.404 Not Found for hard-deleted resources. For soft-deleted resources, return 410 Gone with metadata about when the resource was deleted.ETag and If-Match headers for optimistic concurrency control. Return 412 Precondition Failed if the resource has changed since the client last fetched it.207 Multi-Status with per-item status codes so clients know which items succeeded and which failed./tasks/ and /tasks to the same handler. Return 301 redirects if you enforce one canonical form.400 with a clear message—pick one strategy and be consistent.Take seb1n/api-design from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.