api-design-advanced
Advanced API design — per-language implementation patterns (TypeScript/Next.js, Go/net-http), anti-patterns (200 for everything, 500 for validation, contract breaking), and full pre-ship checklist.
Best use case
api-design-advanced is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Advanced API design — per-language implementation patterns (TypeScript/Next.js, Go/net-http), anti-patterns (200 for everything, 500 for validation, contract breaking), and full pre-ship checklist.
Teams using api-design-advanced should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/api-design-advanced/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How api-design-advanced Compares
| Feature / Agent | api-design-advanced | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Advanced API design — per-language implementation patterns (TypeScript/Next.js, Go/net-http), anti-patterns (200 for everything, 500 for validation, contract breaking), and full pre-ship checklist.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# API Design — Advanced Patterns
This skill extends `api-design` with implementation patterns and anti-patterns. Load `api-design` first.
## When to Activate
- Implementing API handlers in TypeScript (Next.js) or Go
- Reviewing code for common API anti-patterns
- Applying the full pre-ship checklist to a new endpoint
---
## Implementation Patterns
### TypeScript (Next.js API Route)
```typescript
import { z } from "zod";
import { NextRequest, NextResponse } from "next/server";
const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
});
const PROBLEM_CONTENT_TYPE = "application/problem+json";
export async function POST(req: NextRequest) {
const body = await req.json();
const parsed = createUserSchema.safeParse(body);
if (!parsed.success) {
return NextResponse.json({
type: "https://api.example.com/problems/validation-failed",
title: "Validation Failed",
status: 422,
detail: "One or more fields failed validation.",
errors: parsed.error.issues.map(i => ({ field: i.path.join("."), detail: i.message })),
}, { status: 422, headers: { "Content-Type": PROBLEM_CONTENT_TYPE } });
}
const user = await createUser(parsed.data);
return NextResponse.json(
{ data: user },
{ status: 201, headers: { Location: `/api/v1/users/${user.id}` } },
);
}
```
### Go (net/http)
```go
func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
var req CreateUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeProblem(w, r, http.StatusBadRequest,
"https://api.example.com/problems/bad-request", "Bad Request",
"Invalid request body.")
return
}
if err := req.Validate(); err != nil {
writeProblem(w, r, http.StatusUnprocessableEntity,
"https://api.example.com/problems/validation-failed", "Validation Failed",
err.Error())
return
}
user, err := h.service.Create(r.Context(), req)
if err != nil {
switch {
case errors.Is(err, domain.ErrEmailTaken):
writeProblem(w, r, http.StatusConflict,
"https://api.example.com/problems/email-taken", "Email Taken",
"This email is already registered.")
default:
writeProblem(w, r, http.StatusInternalServerError,
"about:blank", "Internal Server Error", "")
}
return
}
w.Header().Set("Location", fmt.Sprintf("/api/v1/users/%s", user.ID))
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(map[string]any{"data": user})
}
// writeProblem writes an RFC 7807 Problem Details response.
func writeProblem(w http.ResponseWriter, r *http.Request, status int,
type_, title, detail string) {
w.Header().Set("Content-Type", "application/problem+json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(map[string]any{
"type": type_, "title": title, "status": status,
"detail": detail, "instance": r.RequestURI,
})
}
```
---
## Anti-Patterns
### Using 200 OK for Every Response
**Wrong:**
```json
HTTP/1.1 200 OK
Content-Type: application/json
{ "success": false, "error": "User not found" }
```
**Correct:**
```json
HTTP/1.1 404 Not Found
Content-Type: application/problem+json
{
"type": "https://api.example.com/problems/not-found",
"title": "Not Found",
"status": 404,
"detail": "User abc-123 not found.",
"instance": "/api/v1/users/abc-123"
}
```
**Why:** Returning 200 for errors forces clients to parse the body to detect failure, breaks HTTP caches and load balancers, and defeats the purpose of the status code system.
---
### Returning 500 for Validation Errors
**Wrong:**
```json
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{ "error": "Invalid email format" }
```
**Correct:**
```json
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json
{
"type": "https://api.example.com/problems/validation-failed",
"title": "Validation Failed",
"status": 422,
"errors": [
{ "field": "email", "detail": "must be a valid email address" }
]
}
```
**Why:** Validation errors are client mistakes (4xx), not server failures (5xx) — misusing 500 triggers false alerts, hides real server errors, and confuses API consumers.
---
### Breaking the API Contract Without a Version Bump
**Wrong:**
```yaml
# v1 response — field renamed in-place, silently breaking all clients
responses:
'200':
content:
application/json:
schema:
properties:
full_name: { type: string } # was "name" — breaking change without /v2/
```
**Correct:**
```yaml
# /api/v1/ keeps "name" intact; /api/v2/ introduces "full_name"
# Deprecate v1 with Sunset header over a 6-month notice period
Sunset: Sat, 01 Jan 2027 00:00:00 GMT
```
**Why:** Renaming, removing, or retyping fields in an existing version silently breaks all existing clients; any breaking change must be introduced under a new API version.
---
## API Design Checklist
Before shipping a new endpoint:
- [ ] Resource URL follows naming conventions (plural, kebab-case, no verbs)
- [ ] Correct HTTP method used (GET for reads, POST for creates, etc.)
- [ ] Appropriate status codes returned (not 200 for everything)
- [ ] Input validated with schema (Zod, Pydantic, Bean Validation)
- [ ] Error responses use RFC 7807 Problem Details (`Content-Type: application/problem+json`)
- [ ] Pagination implemented for list endpoints (cursor or offset)
- [ ] Authentication required (or explicitly marked as public)
- [ ] Authorization checked (user can only access their own resources)
- [ ] Rate limiting configured
- [ ] Response does not leak internal details (stack traces, SQL errors)
- [ ] Consistent naming with existing endpoints (camelCase vs snake_case)
- [ ] OpenAPI spec written **before** implementation (`api/v1/openapi.yaml`)
- [ ] Spec linted (`spectral lint`) with zero errors
- [ ] Types/stubs generated from spec — not hand-written
- [ ] Breaking change detection configured in CI (`oasdiff`)
- [ ] Every operation has non-empty `description` (not just `summary`)
- [ ] Every parameter has `description` + realistic `example`
- [ ] Every schema property has `description` + `example`
- [ ] `x-codeSamples` added for curl + TypeScript + Python + Go
- [ ] `x-stability` set (stable / beta / experimental)
- [ ] CHANGELOG.md updated for new/changed/deprecated endpoints
## Reference
- `api-design` — core REST patterns (resource naming, status codes, response format, auth, rate limiting, versioning)
- `api-contract` — Contract-First workflow (OpenAPI spec, code generation, CI breaking-change detection)Related Skills
typography-design
Typography as a creative discipline: typeface selection criteria, type pairing (serif + sans, display + body), modular scale systems, line-height and tracking ratios, hierarchy construction, and web/mobile rendering considerations. The decisions behind design tokens, not the tokens themselves.
typescript-patterns-advanced
Advanced TypeScript — mapped types, template literal types, conditional types, infer, type guards, decorators, async patterns, testing with Vitest/Jest, and performance. Extends typescript-patterns.
tdd-workflow-advanced
TDD anti-patterns — writing code before tests, testing implementation details instead of behavior, using waitForTimeout as a sync strategy, chaining tests that share state, mocking the system under test instead of its dependencies.
swift-patterns-advanced
Advanced Swift patterns — property wrappers, result builders, Combine basics, opaque & existential types, macro system, advanced generics, and performance optimization. Extends swift-patterns.
serverless-patterns-advanced
Advanced Serverless patterns — Lambda idempotency (Lambda Powertools + DynamoDB persistence layer), Lambda cost model (pricing formula, break-even vs containers), and CloudWatch Insights observability queries for cold starts, duration, and errors.
security-review-advanced
Security anti-patterns — localStorage token storage (XSS risk), trusting client-side authorization checks, reflecting full error details to clients, blacklist vs whitelist input validation, using npm install instead of npm ci in CI pipelines.
sdk-design-patterns
SDK design patterns — API ergonomics, backward compatibility (semantic versioning, deprecation), multi-language SDK generation (openapi-generator vs Speakeasy), error hierarchy design, SDK testing strategies, and documentation as first-class SDK artifact.
rust-testing-advanced
Advanced Rust testing anti-patterns and corrections — cfg(test) placement, expect() over unwrap(), mockall expectation ordering, executor mixing (#[tokio::test] vs block_on), PgPool isolation with
rust-patterns-advanced
Advanced Rust patterns — zero-cost abstractions, proc macros, unsafe FFI, WASM, Axum web architecture, trait objects vs generics, and performance profiling.
python-testing-advanced
Advanced Python testing — async testing with pytest-asyncio, exception/side-effect testing, test organization, common patterns (API, database, class methods), pytest configuration, and CLI reference. Extends python-testing.
python-patterns-advanced
Advanced Python patterns — concurrency (threading, multiprocessing, async/await), hexagonal architecture with FastAPI, RFC 7807 error handling, memory optimization, pyproject.toml tooling, and anti-patterns. Extends python-patterns.
presentation-design
Presentation structure, narrative design, and slide layout principles. Covers the problem-solution-evidence arc, slide density rules (one idea per slide), slide type catalogue, opening hooks, and closing patterns. Use when structuring any slide deck — conference talk, demo, investor pitch, or team update.