svngoku/coding-agents-skills

api-design

Design and review intuitive, scalable, maintainable HTTP APIs.

查看源码

使用方法

  1. 复制安装命令,在自己的智能体环境安装前先检查源码包。
  2. 从原始文档核对所需工具、凭据和支持的宿主。
  3. 说明输入材料与期望交付物,并对照来源检查输出。
npx skills add https://github.com/svngoku/coding-agents-skills --skill api-design

开始前需了解

  • 安装不包含模型订阅、API 额度或访问文件的权限。
  • 仓库星数和安装量反映活跃情况,不等于独立质量或安全测试。
仓库原始内容

按源仓库内容呈现,保留标题、案例、代码、表格、链接以及原文引用的演示图片。

API Design

HTTP APIs are the contract between your service and every client that consumes it. A well-designed API is consistent and predictable: the URL says which resource you are touching, the HTTP method says what happens to it, and the status code plus body say whether it worked and why not. This skill covers designing and reviewing such APIs — resource modeling, HTTP semantics, status codes, error envelopes, pagination, versioning, spec-first OpenAPI 3.x, and authentication basics — REST first, with GraphQL and gRPC covered in passing.

Quick Reference

TaskReference
Error envelopes, RFC 7807, idempotency keys, retry policyerror-handling.md
Cursor vs offset pagination, filtering, sorting, field selectionpagination-filtering.md
Versioning strategies, backward compatibility, deprecationversioning-evolution.md

Core Workflow

Design an endpoint set in five steps:

  1. Model resources and map HTTP semantics — identify the nouns (users, orders, products) and their relationships; name them as plural collections; one method per operation: read → GET, create → POST, full replace → PUT, partial update → PATCH, delete → DELETE, domain action → POST to an action sub-resource.
  2. Design the responses — success shapes, the error envelope (problem+json), and the exact status code per failure mode.
  3. Paginate and filter collections — choose cursor or offset, set defaults, define filter/sort/field-selection syntax.
  4. Write the OpenAPI spec first — the spec is the contract; generate docs and clients from it.
  5. Lock down auth and limits — authentication scheme, least-privilege scopes, rate limits with standard headers.

Resource Modeling

Nouns, not verbs

Resources are nouns; HTTP methods are the verbs. URLs must never contain verbs.

Anti-patternGood
GET /getUser?id=1GET /users/{id}
POST /createOrderPOST /orders
POST /deleteOrder?id=1DELETE /orders/{id}

Collections, sub-resources, actions

PatternExampleMeaning
CollectionGET /orderslist (paginated)
Sub-resourceGET /users/{id}/ordersorders owned by that user
ActionPOST /orders/{id}/canceldomain action with side effects

Relationships

  • Use sub-resources only for genuinely nested, exclusive ownership (/users/{id}/orders makes sense; /orders/{id}/customer does not — the customer is not owned by the order).
  • For non-ownership links, keep the related resource at top level: GET /orders?customer_id=.... Keep nesting shallow — never deeper than one level; embed related IDs in payloads, not whole objects.

Actions are POSTs

When a client operation is not CRUD — cancel, refund, publish, archive — model it as a POST to a named action sub-resource (POST /orders/{id}/cancel). POST is the only method with no idempotency guarantee, which fits side-effecting actions — but pair it with an Idempotency-Key (below).

HTTP Semantics

MethodSemanticsSafeIdempotentNotes
GETread a collection or instance✅✅never changes state; cacheable
POSTcreate a resource, or trigger an action❌❌returns 201 Created + Location
PUTfull replacement of an existing resource❌✅client sends the entire representation
PATCHpartial update (changed fields only)❌❌ by specsend only what changes
DELETEremove a resource❌✅repeat DELETE → 204 or 404, both fine

Safe = no side effects (safe to retry, cache, prefetch). Idempotent = N identical requests produce the same result as one.

Idempotency (PUT vs POST, Idempotency-Key)

  • PUT is inherently idempotent — use it when the client can supply the full representation. Same payload twice → same state.
  • POST and PATCH are not idempotent. A retried POST /orders creates two orders. Fix this with the `Idempotency-Key` request header: the client sends a UUID, the server stores key → response, and replays the stored response instead of re-executing.
http
POST /orders
Idempotency-Key: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d

{ "items": [ { "sku": "SKU-42", "qty": 2 } ] }
  • Require Idempotency-Key on any POST/PATCH that creates or mutates (payments, orders, subscriptions).
  • A replay with the same key but a different body → 409 Conflict.
  • Expire keys after a bounded window (Stripe uses 24h); document the window.
  • On replay, return the original stored response — that is what makes client retries safe.

Status Codes

Pick the narrowest correct code; do not invent meanings. Full 2xx–5xx table (304, 405, 502, 504 and friends): error-handling.md.

CodeUseExample
200 OKsuccessful read, update, or actionGET /orders/{id}
201 Createdresource created (set Location)POST /orders
400 Bad Requestmalformed syntax or missing required fieldinvalid JSON, unknown enum value
401 Unauthorizedmissing or invalid credentialsno/expired token
403 Forbiddenauthenticated but not allowedvalid token, wrong scope
404 Not Foundno such resource or routeGET /orders/9999
409 Conflictstate conflict; request cannot applyduplicate Idempotency-Key body
422 Unprocessable Entitywell-formed but semantically invalidorder with 0 items, negative price
429 Too Many Requestsrate limited (send Retry-After)burst over limit
500 Internal Server Errorunhandled server failurebug, DB outage
503 Service Unavailabledown / overloaded (send Retry-After)maintenance

Common mistakes

  • 200 with an error body — breaks every client's status-code handling. Errors live in 4xx/5xx.
  • 500 for client errors — validation failures are 4xx; 500 triggers alerts and pointless retries for something the client did.
  • 401 vs 403 — 401: who are you (no/expired credentials); 403: you are not allowed (authenticated, lacking permission or scope).

Error Responses

Use a consistent envelope everywhere, preferably RFC 7807 `application/problem+json`:

json
{
  "type": "https://api.example.com/problems/out-of-stock",
  "title": "Order cannot be placed",
  "status": 422,
  "detail": "SKU-42 has only 3 units in stock",
  "code": "OUT_OF_STOCK",
  "retryable": false,
  "errors": [{ "field": "items[0].qty", "code": "OUT_OF_STOCK", "message": "Only 3 units available" }]
}
  • type — stable machine-readable problem URI; title — short human summary; status — HTTP status; detail — human explanation; instance — URI of the request/resource.
  • Add a `code` field: a stable, documented string clients can branch on (OUT_OF_STOCK, INVALID_ARGUMENT, RATE_LIMITED). Never branch on the human-readable title/detail.
  • Add `retryable` (or derive it): 5xx and 429 are retryable; 4xx are not (except 408/425/429).
  • Field-level validation failures → an errors[] array with field, code, message.
  • Serve as Content-Type: application/problem+json; document every code in your API reference.

Pagination, Filtering, Sorting

Cursor vs offset

AspectOffset (?page=2&page_size=50)Cursor (?cursor=...)
Stabilitydrifts when rows are inserted/deleted mid-pagingstable — pages are anchored
UXsupports jump-to-page Nnext/prev only (no jump)
ImplementationOFFSET/LIMIT (trivial)keyset: WHERE (id > :cursor) LIMIT n
Best foradmin tables, small datasetslive, high-churn feeds
Orderinganyrequires a stable sort key

Default to cursor for public/live collections, offset for internal/admin. Set a default page size (25–50) and a hard max (100–1000); clamp or return 400 on overflow — and document it.

json
{ "data": [{ "id": "ord_8f2", "total": "129.00" }],
  "pagination": { "next_cursor": "eyJpZCI6Im9yZF84ZjIifQ", "has_more": true } }

Filtering, sorting, field selection

ConcernConventionExample
Exact match?key=value on known fields?status=shipped
Ranges*_gte / *_lte suffix (or [gte])?created_at_gte=2024-01-01
Sortingsort param; - prefix = descending?sort=-created_at,sku
Field selectionsparse fieldsets?fields=id,name,price

Validate every filter and sort field against a whitelist — unknown keys → 400, never silently ignored.

Versioning

StrategyExampleProsCons
URL path/api/v2/ordersvisible, cacheable per version, easy routingmultiple code paths over time
Media typeAccept: application/vnd.api+json; version=2clean URLshidden from casual inspection, harder to debug
Query param/orders?v=2trivial to addpollutes cache keys and logs; widely discouraged

URL path is the default for public APIs. Never version with query parameters for a public API.

Backward compatibility

Additive (safe, no version bump)Breaking (requires a new version)
new optional fields or query parametersremove or rename a field
new endpoint; widen enums; relax validationchange a field's type or meaning; make an optional field required

Evolve additively as long as you can; version only when a breaking change is unavoidable. When deprecating: announce it, keep the old version alive on a documented sunset schedule, and emit Deprecation / Sunset (RFC 8594) response headers.

Spec-First with OpenAPI 3.x

  1. Write the OpenAPI spec before the implementation — it is the single source of truth for shape, examples, and behavior.
  2. Lint it in CI — Spectral rules catch missing responses, undocumented status codes, and naming drift.
  3. Generate docs and clients from the spec — ReDoc / Redocly, Swagger UI, openapi-generator, openapi-typescript, orval.
  4. Contract-test it and treat spec and implementation as one — Schemathesis fuzzes the spec against the running service; Pact handles consumer-driven contracts; when a review finds a mismatch, fix the spec first, then the code.

Authentication & Rate Limiting

Schemes

SchemeUse forHowNotes
API keysimple machine clients, first-party toolsAuthorization: Bearer <key> or X-API-Key: <key>long-lived; treat as a secret; support rotation
OAuth2 client credentialsmachine-to-machinePOST /oauth/token (grant_type=client_credentials&scope=read:orders) → access tokenshort-lived tokens
OAuth2 authorization codeuser-facing apps acting for a userbrowser flow → access tokendelegate to an IdP (Auth0, Clerk, …)

Use scopes for least privilege: read:orders, write:orders, admin. A token with only read:orders calling a write endpoint → 403.

Rate limiting

On exceeding the limit, return 429 with Retry-After (seconds) plus the standard headers: X-RateLimit-Limit (window quota), X-RateLimit-Remaining, X-RateLimit-Reset (epoch seconds when the window resets). Document your window ("100 requests/minute per API key") and whether limits are per-key, per-IP, or per-user.

Worked Example: Orders API

An orders resource with a lifecycle — the endpoint set, and why each choice:

MethodPathSemantics
GET/orderslist, cursor-paginated, filterable by status, sortable by created_at
POST/orderscreate; requires Idempotency-Key; returns 201 + Location
GET/orders/{id}fetch one; 404 if unknown
PATCH/orders/{id}partial update (e.g. shipping address)
POST/orders/{id}/canceldomain action (triggers refunds); idempotency-keyed; 409 if already shipped
GET/orders/{id}/itemssub-resource — items belong exclusively to the order

Notes: no DELETE /orders — physical deletion is not part of the lifecycle; cancellation is a named action. No PUT — partial updates fit PATCH. Errors use the RFC 7807 envelope; collections use cursor pagination.

OpenAPI 3.1 excerpt (paths, security, components — trimmed):

yaml
openapi: 3.1.0
info: { title: Orders API, version: 2.0.0 }
servers: [{ url: https://api.example.com/v2 }]
security: [{ oauth2: [read:orders, write:orders] }]
paths:
  /orders:
    get:
      summary: List orders
      parameters:
        - { name: status, in: query, schema: { type: string, enum: [created, confirmed, shipped, cancelled] } }
        - { name: cursor, in: query, schema: { type: string, description: "Opaque pagination token" } }
        - { name: limit, in: query, schema: { type: integer, maximum: 100, default: 25 } }
      responses:
        "200": { description: A page of orders, content: { application/json: { schema: { $ref: "#/components/schemas/OrderPage" } } } }
        "429": { description: Too many requests, headers: { Retry-After: { schema: { type: integer } } }, content: { application/problem+json: { schema: { $ref: "#/components/schemas/Problem" } } } }
    post:
      summary: Create an order
      parameters:
        - { name: Idempotency-Key, in: header, required: true, schema: { type: string, format: uuid } }
      requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/NewOrder" } } } }
      responses:
        "201": { description: Order created, headers: { Location: { schema: { type: string } } }, content: { application/json: { schema: { $ref: "#/components/schemas/Order" } } } }
        "422": { description: Unprocessable entity, content: { application/problem+json: { schema: { $ref: "#/components/schemas/Problem" } } } }
components:
  securitySchemes:
    oauth2: { type: oauth2, flows: { clientCredentials: { tokenUrl: https://auth.example.com/oauth/token, scopes: { read:orders: Read orders, write:orders: Create and update orders } } } }
  schemas:
    Problem: { type: object, required: [type, title, status, code], properties: { type: { type: string, format: uri }, title: { type: string }, status: { type: integer }, detail: { type: string }, instance: { type: string }, code: { type: string }, retryable: { type: boolean } } }
    Order: { type: object, required: [id, status, total, currency], properties: { id: { type: string, example: ord_8f2 }, status: { type: string, enum: [created, confirmed, shipped, cancelled] }, total: { type: string, example: "129.00" }, currency: { type: string, example: USD } } }
    NewOrder: { type: object, required: [items], properties: { items: { type: array, minItems: 1, items: { type: object, required: [sku, qty], properties: { sku: { type: string }, qty: { type: integer, minimum: 1 } } } } } }
    OrderPage: { type: object, required: [data, pagination], properties: { data: { type: array, items: { $ref: "#/components/schemas/Order" } }, pagination: { type: object, required: [has_more], properties: { next_cursor: { type: string }, has_more: { type: boolean } } } } }

Pre-Review Checklist

Run this on any existing API before approving changes or declaring it done:

#AreaCheck
1Naming & URLsPlural nouns, consistent casing, no verbs in URLs
2Methods & idempotencyGET never mutates; PUT full replace, PATCH partial; creating/mutating POST/PATCH accept Idempotency-Key
3Status codesNo 200-with-error-body; 4xx for client errors; narrowest correct code
4ErrorsOne envelope everywhere (RFC 7807); stable machine-readable codes documented
5PaginationCursor or offset chosen and documented; default + max page size; has_more / next token
6Filtering/sortingParams whitelisted and validated; unknown keys → 400
7VersioningStrategy documented; no silent breaking changes; deprecation has a sunset plan
8Spec fidelityOpenAPI exists, linted, matches behavior (contract tests in CI)
9Auth & rate limitsLeast-privilege scopes; X-RateLimit-* headers; Retry-After on 429
10SecurityTLS everywhere; no secrets in URLs/logs; no stack traces in responses

Anti-Patterns to Avoid

  • Verbs in URLs (/getUser, /createOrder) — the method is the verb.
  • 200 with an error body — clients branch on status codes; you have just broken all of them.
  • 500 for client mistakes — mis-validated input is a 4xx; 500 means a server bug.
  • Deep nesting (/users/{id}/orders/{oid}/items/{iid}) — flat resources + query params scale better.
  • Bare POST without idempotency on creates and money-adjacent operations — double-submits are real.
  • Unbounded collections — every list endpoint paginates or dies.

When to Use / Not Use

Use this skill when:

  • Designing a new REST API, or a new set of endpoints for an existing service
  • Reviewing an API design doc, an OpenAPI spec, or a PR that changes endpoint behavior
  • Establishing API design standards for a team or platform

Do not use when:

  • The "API" is a library or function interface (Python SDK internals, method signatures) — different concerns
  • Designing event payloads or message-broker contracts (Kafka, SQS) — no status codes or idempotency keys in the same sense
  • The user wants a deep GraphQL- or gRPC-only treatment — this skill covers them in passing only; use dedicated GraphQL/gRPC guides

按任务相关推荐

来自同一仓库

更多 Skills

全部 Skills
svngoku
社区

adaption-ai

Adaption AI SDK for synthetic data augmentation and dataset adaptation. Use when building data pipelines with the Adaption Python SDK, uploading datasets (local files, Hugging Face, Kaggle), running augmentation/adaptation jobs, configuring brand controls (hallucination mitigation, safety categories, length), recipe specifications (reasoning traces, deduplication, preference pairs, prompt rephrase), evaluating dataset quality, downloading results, or any workflow involving pip install adaption,

安装量
1
GitHub Stars
12
最近更新
10月20日
svngoku
社区

microservices-patterns

Decompose systems into microservices and apply canonical distributed-systems patterns. Use this skill whenever the user wants to split a monolith into services, design service boundaries, choose between microservices and a modular monolith, implement sagas or the outbox pattern, set up CQRS or event sourcing, configure an API gateway or BFF, add resilience (circuit breakers, retries, timeouts), or implement distributed tracing with OpenTelemetry. Also trigger for distributed transactions, servic

安装量
1
GitHub Stars
12
最近更新
10月20日
svngoku
社区

security-best-practices

Practical security review and hardening guidance for application code in Python, JavaScript/TypeScript, and Go. Use this skill whenever the user asks for a security review or audit, wants to harden authentication (password hashing, sessions, JWT, OAuth2/OIDC, MFA), fix OWASP Top 10 issues (injection, XSS, IDOR, CSRF, SSRF, deserialization), threat-model with STRIDE, clean up secrets and .env handling, or set up dependency scanning (pip-audit, npm audit, osv-scanner, gitleaks, SBOM). Also trigger

安装量
1
GitHub Stars
12
最近更新
10月20日
svngoku
社区

testing-patterns

Plan, write, and maintain automated tests in any language, with worked examples in Python and JavaScript/TypeScript. Use this skill whenever the user wants to write or plan tests, apply TDD (red-green-refactor), structure unit tests with arrange-act-assert and given-when-then naming, choose between fakes, stubs, and mocks, set up dependency injection for testability, build integration tests with testcontainers, database seeding, or transaction rollback, write Playwright or Cypress end-to-end tes

安装量
1
GitHub Stars
12
最近更新
10月20日