AgentStack
SKILL verified MIT Self-run

Api Design

skill-kwhorne-elyra-skills-api-design · by kwhorne

Design consistent HTTP/REST endpoints with sensible naming, status codes, pagination, error formats, and versioning. Use when the user asks to design, review, or extend an HTTP API, or wants feedback on endpoint shape.

No reviews yet
0 installs
6 views
0.0% view→install

Install

$ agentstack add skill-kwhorne-elyra-skills-api-design

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Api Design? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

API Design

Principles for HTTP/REST APIs that are predictable, debuggable, and pleasant to consume. Opinionated where the field has converged; flexible where reasonable people disagree.

When to use

  • "Design an endpoint for X"
  • "How should this API look?"
  • "Review this API"
  • "Add an endpoint to …"

Procedure

  1. Anchor to existing patterns. Read 2–3 existing endpoints in the same codebase. New endpoints should look like neighbors.
  2. Model the resource, not the action. Most actions become CRUD on a resource. If they don't (e.g. "publish"), see "Actions on resources" below.
  3. Sketch the contract before writing code: path, method, request body, response body, status codes, errors.
  4. Check it against the consistency checklist below.
  5. Document it — even one paragraph in the PR is better than nothing.

Resource naming

  • Use plural nouns for collections: /users, /orders, /articles
  • Use IDs, not slugs, for identity: /users/42 (slugs are for SEO, not for APIs)
  • Nest to express ownership, max 2 levels deep:
  • /users/42/orders
  • /users/42/orders/7/items/3/shipments
  • Use kebab-case in paths: /account-settings, not /accountSettings or /account_settings
  • Lowercase everything in paths
  • No verbs in paths — the HTTP method is the verb

Methods

| Method | Purpose | Idempotent | Safe | |---|---|---|---| | GET | Retrieve | yes | yes | | POST | Create, or non-idempotent action | no | no | | PUT | Replace (full update) | yes | no | | PATCH | Partial update | no\* | no | | DELETE | Remove | yes | no |

\ PATCH can* be idempotent if you design it that way; don't rely on it.

Status codes

Pick from this short list. Resist the urge to be clever.

| Code | Meaning | Use for | |---|---|---| | 200 OK | Success with body | GET, PATCH, PUT returning resource | | 201 Created | Resource created | POST that creates a resource (return it + Location header) | | 202 Accepted | Accepted for async processing | Long-running jobs | | 204 No Content | Success, no body | DELETE, PUT without return | | 400 Bad Request | Malformed request | Bad JSON, missing required fields | | 401 Unauthorized | Not authenticated | Missing/invalid credentials | | 403 Forbidden | Authenticated but not allowed | Permission denied | | 404 Not Found | Resource doesn't exist | Unknown ID | | 409 Conflict | State conflict | Duplicate, version mismatch | | 422 Unprocessable Entity | Validation failed | Well-formed but semantically invalid | | 429 Too Many Requests | Rate-limited | Include Retry-After | | 500 Internal Server Error | We broke it | Unexpected server fault | | 503 Service Unavailable | Temporarily down | Maintenance, dependency outage |

Don't invent custom codes. Don't return 200 with {"error": "..."}.

Errors

Use a single, documented error shape across the entire API:

{
  "error": {
    "code": "validation_failed",
    "message": "Request failed validation.",
    "details": [
      { "field": "email", "code": "invalid_format" },
      { "field": "age", "code": "must_be_positive" }
    ],
    "request_id": "req_01HX…"
  }
}
  • Stable, machine-readable code (snake_case, never localized)
  • Human-readable message (English; localize on the client)
  • details for per-field validation
  • request_id for support / log correlation

Consider RFC 9457 Problem Details if the consumer already uses it.

Pagination

Pick one and stick with it across the API.

  • Cursor-based (preferred for large/changing data):
  • Request: ?limit=50&cursor=eyJpZCI6...
  • Response: { "data": [...], "next_cursor": "...", "has_more": true }
  • Page-based (fine for small/static data):
  • Request: ?page=2&per_page=50
  • Response: { "data": [...], "page": 2, "per_page": 50, "total": 1234 }

Always cap limit / per_page server-side. Document the max.

Filtering, sorting, sparse fields

  • Filter: ?status=active&created_after=2025-01-01
  • Sort: ?sort=-created_at,name (leading - = descending)
  • Sparse fields: ?fields=id,email,created_at

Versioning

Pick one strategy and commit:

  • URL: /v1/users — most visible, easiest to route
  • Header: Accept: application/vnd.example.v1+json — cleaner URLs, harder to debug
  • Avoid query-string versioning

Only bump the major version for breaking changes. Additive changes (new fields, new endpoints) don't require a new version.

Actions on resources

When CRUD doesn't fit (publish, archive, retry, refund), prefer:

  • State transitions via PATCH: PATCH /articles/42 {"status": "published"} — best if you have multiple states
  • Sub-resources for explicit actions: POST /articles/42/publish — pragmatic when the action has side effects or its own payload

Don't go full RPC: POST /publishArticle?id=42. You're using HTTP; use it.

Consistency checklist

  • [ ] Resource name is a plural noun
  • [ ] Path uses kebab-case and lowercase
  • [ ] HTTP method matches semantics (idempotency!)
  • [ ] Status codes from the short list
  • [ ] Error response matches the API-wide error shape
  • [ ] POST that creates returns 201 + Location header
  • [ ] List endpoints paginate and cap limit
  • [ ] Timestamps are ISO 8601 with timezone (2026-05-22T14:30:00Z)
  • [ ] IDs are opaque strings (not auto-increment ints leaked) when possible
  • [ ] No sensitive data in URLs (use headers / body)
  • [ ] Versioning strategy followed
  • [ ] Authentication / authorization checks documented per endpoint

Anti-patterns

  • GET /getUser?id=42 — verb in path, query param for identity
  • POST /users/delete/42 — DELETE exists for a reason
  • ❌ Returning 200 with {"success": false}
  • ❌ Inconsistent casing: userId in one response, user_id in another
  • ❌ Auto-increment IDs in URLs leaking row counts to the public
  • ❌ Pagination with no upper bound on limit
  • ❌ Mixing snake_case and camelCase in the same payload
  • ❌ "Soft 200" — returning HTTP success but logical failure

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.