Install
$ agentstack add skill-code-saurabh-openskills-api-design ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo 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 Used
- ✓ 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.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
API Design
Approach every API as a product. The developer calling your API is your user. An API that is hard to understand, inconsistent, or unpredictable is a broken product — even if it technically works.
Design the API before writing a single line of implementation. An API is a contract. Changing it after clients depend on it is expensive. Getting it right upfront is cheap.
API Design Principles
- Spec first, implement second. Write the OpenAPI spec, GraphQL schema, or proto file before any implementation. The spec is the contract. Implementation details are irrelevant to the caller.
- Consistency is the most important quality. Every endpoint in an API should behave according to the same rules: same error format, same naming convention, same pagination pattern, same auth mechanism. Inconsistency forces callers to write special-case code for every endpoint.
- APIs are forever. Every field you add is a field you must support until you version or sunset the API. Every field you remove is a breaking change. Design with permanence in mind.
- Design for the caller, not the data model. Your database schema is an implementation detail. Your API shape should reflect what callers need, not what your ORM produces.
- Explicit over implicit. Undefined behaviour in an API becomes the behaviour callers depend on. Make every behaviour explicit: required vs optional fields, error codes, rate limits, pagination behaviour at the end of a list.
- Developer experience is a first-class requirement. An API that requires a PhD to understand will not be adopted. Good error messages, consistent naming, and accurate documentation are as important as correct behaviour.
Step 0: Ground the API Design
Before designing any endpoint, answer these questions:
- Who is the caller? Internal service, third-party developer, mobile app, browser, CLI? Each has different needs (auth mechanism, response size, error verbosity).
- What resources does the API expose? List the core domain entities the API manages.
- What operations does each resource support? CRUD is not always the right decomposition — sometimes
cancel,approve,publishare better verbs than generic CRUD. - What are the read/write patterns? High-read, low-write? Real-time? Bulk operations? Streaming? This determines the API style.
- What are the latency and payload size constraints? A mobile API on a 3G connection has different constraints than a backend-to-backend integration.
- What versioning strategy is needed from day one? If this API will have external consumers, versioning must be designed in before the first endpoint ships.
Choosing the Right API Style
| Style | Best for | Avoid when | |-------|----------|------------| | REST | Resource-oriented APIs, public APIs, broad client compatibility, simple CRUD | Complex queries with many relationships, real-time, or highly variable response shapes | | GraphQL | Flexible queries, multiple clients with different data needs, frontend-driven development, deeply nested data | Simple APIs, teams without GraphQL tooling, when over-fetching is not a real problem | | gRPC | High-performance internal service communication, streaming, strongly-typed contracts, polyglot microservices | Browser clients (requires grpc-web proxy), teams unfamiliar with protobuf | | WebSocket | Real-time bidirectional communication (chat, live dashboards, multiplayer) | Request-response patterns that do not need real-time; adds complexity without benefit | | Webhooks | Asynchronous event notification to external systems | When the caller needs to poll or query state; use REST polling or SSE instead |
REST API Design Standards
URL Structure
# Pattern
/{version}/{resource}/{id}/{sub-resource}
# Examples — good
GET /v1/users
GET /v1/users/{userId}
GET /v1/users/{userId}/orders
POST /v1/users
PUT /v1/users/{userId}
PATCH /v1/users/{userId}
DELETE /v1/users/{userId}
# Actions that don't map to CRUD — use sub-resources
POST /v1/orders/{orderId}/cancel
POST /v1/invoices/{invoiceId}/send
POST /v1/users/{userId}/password-reset
URL rules:
- Always lowercase, hyphen-separated (
user-profiles, notuserProfilesoruser_profiles) - Nouns for resources, not verbs (
/users, not/getUsers) - Plural for collections (
/users, not/user) - Version in the URL path (
/v1/) for public APIs — query param or header for internal APIs - Never expose database IDs directly where possible (use UUIDs or opaque string IDs)
HTTP Methods — Correct Usage
| Method | Semantics | Idempotent | Safe | |--------|-----------|------------|------| | GET | Retrieve resource(s) | ✅ | ✅ | | POST | Create a new resource or trigger an action | ❌ | ❌ | | PUT | Replace a resource entirely | ✅ | ❌ | | PATCH | Partially update a resource | ❌ (should be) | ❌ | | DELETE | Remove a resource | ✅ | ❌ |
Rule: GET requests must never have side effects. Never use GET to trigger a state change.
Request & Response Shape
Request body — always:
{
"name": "Jane Doe",
"email": "jane@example.com",
"role": "admin"
}
Single resource response:
{
"id": "usr_01HXYZ",
"name": "Jane Doe",
"email": "jane@example.com",
"role": "admin",
"createdAt": "2026-01-15T10:30:00Z",
"updatedAt": "2026-01-15T10:30:00Z"
}
Collection response — always wrap in an envelope:
{
"data": [
{ "id": "usr_01HXYZ", "name": "Jane Doe" },
{ "id": "usr_02HABC", "name": "John Smith" }
],
"pagination": {
"cursor": "eyJpZCI6InVzcl8wMkhBQkMifQ==",
"hasMore": true,
"total": 247
}
}
Why an envelope? Adding metadata (pagination, request ID, warnings) to a bare array response is a breaking change. An envelope allows non-breaking additions forever.
Naming Conventions
- Field names:
camelCasefor JSON APIs (firstName, notfirst_nameorFirstName) - Timestamps: ISO 8601 UTC (
"2026-01-15T10:30:00Z") — never Unix timestamps in the response body - Booleans: positive framing (
isActive, notisNotActive;isEnabled, notisDisabled) - IDs: string type always, even if internally numeric (prevents JavaScript integer overflow)
- Money: integer cents, never floating-point (
"amount": 1999means $19.99) - Enums: SCREAMINGSNAKECASE (
"status": "IN_PROGRESS")
Error Response Standard
Every API must have one error format used consistently across all endpoints:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Must be a valid email address"
}
],
"requestId": "req_01HXYZ123",
"docsUrl": "https://docs.example.com/errors/VALIDATION_ERROR"
}
}
Rules:
codeis a machine-readable string constant — callers switch on this, not on the HTTP statusmessageis human-readable — never put a machine-parseable value heredetailsis an array — multiple validation errors in one response, never force callers to fix one error at a timerequestIdon every error response — this is how support traces the request in logsdocsUrlfor each error code — link to documentation explaining the error and how to fix it
HTTP Status Codes — Correct Usage
| Code | When to use | |------|------------| | 200 OK | Successful GET, PATCH, PUT | | 201 Created | Successful POST that creates a resource | | 204 No Content | Successful DELETE or action with no response body | | 400 Bad Request | Validation error, malformed request | | 401 Unauthorized | Not authenticated | | 403 Forbidden | Authenticated but not authorized for this resource | | 404 Not Found | Resource does not exist | | 409 Conflict | State conflict (duplicate, version mismatch) | | 422 Unprocessable Entity | Semantically invalid request (valid syntax, invalid business logic) | | 429 Too Many Requests | Rate limit exceeded | | 500 Internal Server Error | Unexpected server error | | 503 Service Unavailable | Planned downtime or dependency unavailable |
Never use 200 with an error body. { "success": false, "error": "..." } with a 200 status is a broken API.
Pagination Patterns
Cursor-based Pagination (recommended for most cases)
GET /v1/users?cursor=eyJpZCI6InVzcl8wMkhBQkMifQ==&limit=20
When: Ordered, append-heavy collections (feeds, logs, events). Stable pages even when new items are inserted.
Offset-based Pagination (simple, but has edge cases)
GET /v1/products?page=3&pageSize=20
When: Admin UIs where users jump to specific pages. Avoid for large or frequently-updated datasets (items shift as pages load).
Keyset Pagination (for high-performance sorted queries)
GET /v1/orders?afterId=ord_01HXYZ&limit=50
When: Database queries on an indexed column where offset queries become slow.
Pagination response fields (always include):
cursorornextPage— how to get the next pagehasMore(boolean) — whether more results exist after this pagetotal(optional) — total count (expensive on large datasets; omit if not needed)limit— the limit that was applied (echo it back)
API Versioning Strategy
URL Path Versioning (recommended for public APIs)
/v1/users
/v2/users
Pros: Explicit, easy to route in proxies/gateways, cacheable. Use for: External/public APIs, mobile app APIs (clients pin to a version).
Header Versioning (recommended for internal APIs)
API-Version: 2026-01-15
Pros: Keeps URLs clean; date-based versions are self-documenting. Use for: Internal services, APIs with sophisticated clients.
Breaking vs Non-Breaking Changes
Non-breaking (safe to add without versioning):
- Adding new optional fields to responses
- Adding new optional request parameters
- Adding new endpoints
- Loosening validation on existing fields
Breaking (requires version bump):
- Removing or renaming fields
- Changing field types
- Changing HTTP status codes
- Tightening validation
- Changing authentication requirements
- Removing endpoints
Deprecation policy: Mark deprecated fields with a X-Deprecated-Fields response header and a deprecated note in the OpenAPI spec. Give callers a minimum of 6 months notice before removal.
OpenAPI Spec Standards
Every REST API ships with an OpenAPI 3.x spec. No exceptions.
openapi: 3.1.0
info:
title: User Management API
version: 1.0.0
description: Manages user accounts and profiles
paths:
/v1/users/{userId}:
get:
summary: Get a user by ID
operationId: getUserById
tags: [Users]
parameters:
- name: userId
in: path
required: true
schema:
type: string
responses:
'200':
description: User found
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
$ref: '#/components/responses/NotFound'
'401':
$ref: '#/components/responses/Unauthorized'
components:
schemas:
User:
type: object
required: [id, name, email, createdAt]
properties:
id:
type: string
example: usr_01HXYZ
name:
type: string
example: Jane Doe
email:
type: string
format: email
createdAt:
type: string
format: date-time
OpenAPI rules:
operationIdon every endpoint — used for SDK generationtagson every endpoint — groups endpoints in documentation- Every response code documented — not just 200
$reffor shared schemas — no duplication- Realistic
examplevalues — notstring,foo, or123 - Security schemes defined and applied to every protected endpoint
Rate Limiting
Every public API must implement rate limiting. Communicate it clearly:
Response headers (always include on rate-limited APIs):
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 842
X-RateLimit-Reset: 1737892800
Retry-After: 60 (only on 429 responses)
Rate limit strategy:
- Per API key / per user: prevents one caller from starving others
- Per endpoint: expensive endpoints get tighter limits than cheap ones
- Sliding window preferred over fixed window (avoids burst at window boundary)
- Return
429withRetry-Afterheader — never silently drop requests
Authentication Standards
| Mechanism | Use case | |-----------|----------| | Bearer JWT | User-facing APIs, mobile/web clients | | API Key (Authorization: Bearer sk_...) | Server-to-server, third-party integrations | | OAuth 2.0 + PKCE | Third-party access on behalf of a user | | mTLS | High-security internal service communication |
Rules:
- Always use
Authorization: Bearerheader — never query parameters for auth tokens - API keys in query parameters appear in server logs. Never.
- Short-lived access tokens (15 min – 1 hour) with refresh token rotation
- Scopes on API keys — a key should only have access to what it needs
Bundled Reference
Read [openapi-review.md](./references/openapi-review.md) when reviewing or writing an OpenAPI contract. It supplements, but does not replace, the API-specific requirements in this skill.
API Design Review Checklist
Before finalising any API design:
Resource & URL Design
- [ ] URLs are nouns, lowercase, hyphenated
- [ ] HTTP methods used correctly (no state-changing GETs)
- [ ] Version included in URL or header strategy defined
- [ ] IDs are string type (not integer)
- [ ] Actions not mappable to CRUD use sub-resource + POST
Request & Response
- [ ] Collections wrapped in an envelope object
- [ ] Consistent field naming (camelCase)
- [ ] Timestamps in ISO 8601 UTC format
- [ ] Money in integer cents, not floats
- [ ] All required fields documented
Errors
- [ ] Single error format used across all endpoints
- [ ] Machine-readable error codes defined
- [ ] Field-level validation errors returned in one response (not one at a time)
- [ ] Correct HTTP status codes used
- [ ] RequestId on every error response
Pagination
- [ ] All collection endpoints paginated (never return unbounded lists)
- [ ] Pagination strategy documented
- [ ]
hasMoreand cursor/nextPage in every paginated response
Versioning & Breaking Changes
- [ ] Versioning strategy defined before first endpoint ships
- [ ] Deprecation policy defined
- [ ] No breaking changes to existing endpoints without a version bump
Security
- [ ] Auth mechanism defined for all endpoints
- [ ] Rate limiting applied and communicated via headers
- [ ] No secrets in URLs or query parameters
- [ ] HTTPS only — no HTTP fallback
Documentation
- [ ] OpenAPI 3.x spec complete with all endpoints, schemas, and error responses
- [ ] Realistic examples on all request/response fields
- [ ] Authentication documented with example token format
- [ ] Rate limits documented
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: CODE-SAURABH
- Source: CODE-SAURABH/OpenSkills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.