kensaurus/cursor-kenji

design-api

Design RESTful and GraphQL APIs following current best practices for naming, versioning, error shapes, and auth patterns. Use when the user says "design an API", "create endpoints", "structure my API responses", "plan API architecture", "REST vs GraphQL", or "API contract".

First seen Jun 15, 2026

Installation

$ npx skills add kensaurus/cursor-kenji --skill design-api

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from kensaurus/cursor-kenji · top by installs.

npx skills add kensaurus/cursor-kenji

Browse all from kensaurus/cursor-kenji

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 9
License LICENSE
Default branch main
Open issues 0
Status Active

Skill metadata

Parsed from SKILL.md frontmatter.

LicenseMIT

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 8,018 B
  • docs SUMMARY.md 292 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 31 installs

SKILL.md

API Design Skill

Degree of freedom: MIXED. Resource model, error shape, and REST vs GraphQL [HIGH freedom]; pre-design docs/schema/grep [LOW freedom — run exactly].

Design clean, consistent, and developer-friendly APIs.

How to reason

  1. Survey — existing docs, schema, and similar endpoints
  2. Model — resources, relations, REST vs GraphQL
  3. Contract — paths, statuses, error shape, auth, pagination
  4. Check — naming matches this repo; no duplicate endpoint

Worked example

Survey: orders has user_id; no GET /users/:id/orders; clients use useQuery.
Model: order is a nested user resource, not a /getUserOrders RPC.
Contract: GET /users/:id/orders{ data, meta }; shared { error: { code, message, details } }.
Check: plural kebab-case; list paginated; 401/404/422 only from the status table.

Self-critique before reporting

  • Pre-design stated — docs, schema, and similar endpoints were checked out loud
  • One error shape — every failure uses { error: { code, message, details } }
  • Lists paginate — no unbounded GET /resources
  • Right owner — live 4xx/5xx repro → debug-fe-be-integration; product scope still fuzzy → design-prd

MANDATORY: Pre-Design Checks [LOW freedom — run exactly]

BEFORE designing any API, you MUST:

1. Check Existing API Documentation

http://localhost:8080/api-docs (if backend running)
http://localhost:8080/naming-conventions (naming standards)
src/api/_api-README.md (frontend API layer docs)

2. Verify Database Schema

Use Supabase MCP to understand existing data structure:

-- Check table schema
SELECT column_name, data_type, is_nullable
FROM information_schema.columns WHERE table_name = 'your_table';

-- Check enum values
SELECT enum_range(NULL::your_enum_name);

-- Check foreign keys
SELECT tc.constraint_name, kcu.column_name, ccu.table_name AS foreign_table
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu ON tc.constraint_name = ccu.constraint_name
WHERE tc.table_name = 'your_table' AND tc.constraint_type = 'FOREIGN KEY';

3. Check for Existing Endpoints

Use Grep to search for similar endpoints already implemented:

Grep: "router.get|router.post" to find existing route patterns
Grep: "useQuery|useMutation" to find existing frontend integrations

4. Verification Statement (REQUIRED)

Before designing, state:

"Pre-design check:
- Existing API docs reviewed: [YES/NO]
- Database schema verified: [tables/enums checked]
- Similar endpoints found: [list or none]
- Naming conventions confirmed: [YES/NO]"

REST API Design [HIGH freedom]

URL Structure

GET /resources # List
GET /resources/:id # Get one
POST /resources # Create
PUT /resources/:id # Replace
PATCH /resources/:id # Update
DELETE /resources/:id # Delete

Naming Conventions

Do Don't
/users /getUsers, /user-list
/users/:id /user/:id, /users/get/:id
/users/:id/orders /getUserOrders
Plural nouns Verbs, singular
kebab-case camelCase, snake_case

Examples

GET /users # List users
GET /users/123 # Get user 123
GET /users/123/orders # User's orders
GET /users/123/orders/456 # Specific order
POST /users/123/orders # Create order for user

Request/Response Format [LOW freedom — run this shape]

Request Body

{
 "name": "John Doe",
 "email": "[email protected]",
 "role": "admin"
}

Successful Response

{
 "data": {
 "id": "123",
 "name": "John Doe",
 "email": "[email protected]",
 "createdAt": "2024-01-15T10:30:00Z"
 }
}

List Response (with pagination)

{
 "data": [
 { "id": "1", "name": "John" },
 { "id": "2", "name": "Jane" }
 ],
 "meta": {
 "total": 100,
 "page": 1,
 "perPage": 20,
 "totalPages": 5
 }
}

Error Response

{
 "error": {
 "code": "VALIDATION_ERROR",
 "message": "Invalid input data",
 "details": [
 { "field": "email", "message": "Invalid email format" },
 { "field": "name", "message": "Name is required" }
 ]
 }
}

HTTP Status Codes [LOW freedom — use this table]

Success (2xx)

Code When to Use
200 OK GET, PUT, PATCH success
201 Created POST created new resource
204 No Content DELETE success, no body

Client Errors (4xx)

Code When to Use
400 Bad Request Invalid request body
401 Unauthorized Not authenticated
403 Forbidden Authenticated but not allowed
404 Not Found Resource doesn't exist
409 Conflict Resource conflict (duplicate)
422 Unprocessable Validation failed
429 Too Many Rate limited

Server Errors (5xx)

Code When to Use
500 Internal Error Unexpected server error
502 Bad Gateway Upstream service failed
503 Unavailable Service temporarily down

Query Parameters

Filtering

GET /users?role=admin
GET /users?role=admin&status=active
GET /orders?createdAfter=2024-01-01

Sorting

GET /users?sort=name # Ascending
GET /users?sort=-createdAt # Descending (prefix with -)
GET /users?sort=role,-name # Multiple fields

Pagination

GET /users?page=2&perPage=20
GET /users?offset=40&limit=20
GET /users?cursor=abc123 # Cursor-based

Field Selection

GET /users?fields=id,name,email
GET /users?include=orders,profile

Versioning

URL Path (Recommended)

GET /v1/users
GET /v2/users

Header

GET /users
Accept: application/vnd.api+json;version=2

Authentication

Bearer Token

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

API Key

X-API-Key: your-api-key
# or
?apiKey=your-api-key

Common Patterns

Bulk Operations

POST /users/bulk
{
 "create": [{ "name": "John" }, { "name": "Jane" }],
 "update": [{ "id": "1", "name": "Updated" }],
 "delete": ["2", "3"]
}

Search

POST /users/search
{
 "query": "john",
 "filters": { "role": "admin" },
 "sort": { "field": "name", "order": "asc" }
}

Actions (non-CRUD)

POST /orders/123/cancel
POST /users/123/verify-email
POST /payments/123/refund

API Design Checklist [LOW freedom — do not skip]

Consistency

  • Consistent naming conventions
  • Consistent response format
  • Consistent error format
  • Consistent pagination

Usability

  • Intuitive URLs
  • Clear documentation
  • Meaningful error messages
  • Sensible defaults

Security

  • Authentication required
  • Authorization checked
  • Input validation
  • Rate limiting

Performance

  • Pagination for lists
  • Field selection available
  • Efficient queries
  • Caching headers

Documentation Template

## Create User

Create a new user account.

**Endpoint:** `POST /users`

**Authentication:** Required (Bearer token)

**Request Body:**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| name | string | Yes | User's full name |
| email | string | Yes | Valid email address |
| role | string | No | User role (default: "user") |

**Response:** `201 Created`
\`\`\`json
{
 "data": {
 "id": "123",
 "name": "John Doe",
 "email": "[email protected]",
 "role": "user",
 "createdAt": "2024-01-15T10:30:00Z"
 }
}
\`\`\`

**Errors:**
- `400` - Invalid request body
- `409` - Email already exists
- `422` - Validation failed