rest-api-design
Design REST API endpoints with Zod validation and OpenAPI documentation. Use when creating new API routes, validating request/response schemas, or updating API documentation. Activates for endpoint design, schema validation, error handling, and API docs.
Best use case
rest-api-design is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Design REST API endpoints with Zod validation and OpenAPI documentation. Use when creating new API routes, validating request/response schemas, or updating API documentation. Activates for endpoint design, schema validation, error handling, and API docs.
Teams using rest-api-design 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/rest-api-design/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How rest-api-design Compares
| Feature / Agent | rest-api-design | 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?
Design REST API endpoints with Zod validation and OpenAPI documentation. Use when creating new API routes, validating request/response schemas, or updating API documentation. Activates for endpoint design, schema validation, error handling, and API docs.
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
# REST API Design
This skill helps you design and implement REST API endpoints following project patterns with Zod validation and OpenAPI documentation.
## When to Use
✅ **USE this skill for:**
- Creating new REST API endpoints with Next.js App Router
- Designing request/response schemas with Zod
- Implementing proper error handling and status codes
- Adding rate limiting and authentication
- Generating OpenAPI documentation
❌ **DO NOT use for:**
- GraphQL APIs → different paradigm entirely
- Cloudflare Workers → use `cloudflare-worker-dev` skill
- Supabase Edge Functions → use Supabase docs
- WebSocket/real-time APIs → different patterns
## API Route Structure
```
src/app/api/
├── auth/ # Authentication endpoints
├── check-in/ # Daily check-in CRUD
├── chat/ # AI coaching chat
├── journal/ # Journal entries
├── admin/ # Admin-only endpoints
└── health/ # Health check
```
## Standard Route Template
```typescript
// src/app/api/[feature]/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
import { getSession } from '@/lib/auth';
import { createRateLimiter } from '@/lib/rate-limit';
import { logPHIAccess } from '@/lib/hipaa/audit';
import { db } from '@/db';
// 1. Define schemas
const RequestSchema = z.object({
field: z.string().min(1).max(1000),
optional: z.string().optional(),
enumField: z.enum(['option1', 'option2']),
number: z.number().int().positive(),
});
const ResponseSchema = z.object({
id: z.string(),
createdAt: z.string().datetime(),
});
// 2. Configure rate limiter
const rateLimiter = createRateLimiter({
windowMs: 60000, // 1 minute
maxRequests: 30, // 30 requests per window
keyPrefix: 'api:feature',
});
// 3. Implement handlers
export async function GET(request: NextRequest) {
// Auth check
const session = await getSession();
if (!session) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
// Rate limit
const rateLimitResult = await rateLimiter.check(session.userId);
if (!rateLimitResult.allowed) {
return NextResponse.json(
{ error: 'Rate limit exceeded' },
{ status: 429, headers: rateLimitResult.headers }
);
}
// Query data
const data = await db.query.features.findMany({
where: eq(features.userId, session.userId),
});
// Audit log (if PHI)
await logPHIAccess(session.userId, 'feature', null, 'LIST');
return NextResponse.json(data);
}
export async function POST(request: NextRequest) {
// Auth check
const session = await getSession();
if (!session) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
// Rate limit
const rateLimitResult = await rateLimiter.check(session.userId);
if (!rateLimitResult.allowed) {
return NextResponse.json(
{ error: 'Rate limit exceeded' },
{ status: 429, headers: rateLimitResult.headers }
);
}
// Parse and validate body
let body: unknown;
try {
body = await request.json();
} catch {
return NextResponse.json(
{ error: 'Invalid JSON' },
{ status: 400 }
);
}
const parsed = RequestSchema.safeParse(body);
if (!parsed.success) {
return NextResponse.json(
{
error: 'Validation failed',
details: parsed.error.issues.map(i => ({
path: i.path.join('.'),
message: i.message,
})),
},
{ status: 400 }
);
}
// Create resource
const [created] = await db.insert(features).values({
id: generateId(),
userId: session.userId,
...parsed.data,
createdAt: new Date(),
}).returning();
// Audit log
await logPHIAccess(session.userId, 'feature', created.id, 'CREATE');
return NextResponse.json(created, { status: 201 });
}
```
## Zod Schema Patterns
### Basic Types
```typescript
import { z } from 'zod';
const Schema = z.object({
// Strings
name: z.string().min(1).max(100),
email: z.string().email(),
url: z.string().url(),
uuid: z.string().uuid(),
// Numbers
count: z.number().int().positive(),
rating: z.number().min(1).max(5),
price: z.number().nonnegative(),
// Booleans
isActive: z.boolean(),
// Dates
date: z.string().datetime(),
dateOnly: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
// Enums
status: z.enum(['pending', 'approved', 'denied']),
// Arrays
tags: z.array(z.string()).min(1).max(10),
// Optional fields
notes: z.string().optional(),
metadata: z.record(z.string()).optional(),
// Nullable
deletedAt: z.string().datetime().nullable(),
});
```
### Advanced Patterns
```typescript
// Discriminated unions
const EventSchema = z.discriminatedUnion('type', [
z.object({ type: z.literal('click'), x: z.number(), y: z.number() }),
z.object({ type: z.literal('keypress'), key: z.string() }),
]);
// Refinements
const PasswordSchema = z.string()
.min(12, 'Password must be at least 12 characters')
.regex(/[A-Z]/, 'Must contain uppercase')
.regex(/[a-z]/, 'Must contain lowercase')
.regex(/[0-9]/, 'Must contain number')
.regex(/[^A-Za-z0-9]/, 'Must contain special character');
// Transform
const DateSchema = z.string()
.datetime()
.transform(str => new Date(str));
// Preprocess (coerce types)
const NumberFromString = z.preprocess(
val => typeof val === 'string' ? parseInt(val, 10) : val,
z.number()
);
```
### Query Parameter Validation
```typescript
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const QuerySchema = z.object({
page: z.coerce.number().int().positive().default(1),
limit: z.coerce.number().int().min(1).max(100).default(20),
sort: z.enum(['asc', 'desc']).default('desc'),
status: z.enum(['all', 'active', 'archived']).optional(),
});
const query = QuerySchema.safeParse({
page: searchParams.get('page'),
limit: searchParams.get('limit'),
sort: searchParams.get('sort'),
status: searchParams.get('status'),
});
if (!query.success) {
return NextResponse.json(
{ error: 'Invalid query parameters', details: query.error.issues },
{ status: 400 }
);
}
const { page, limit, sort, status } = query.data;
// Use validated params...
}
```
## Error Response Format
```typescript
// Standard error response
interface APIError {
error: string; // Human-readable message
code?: string; // Machine-readable code
details?: ErrorDetail[]; // Validation details
}
interface ErrorDetail {
path: string;
message: string;
}
// Error responses
return NextResponse.json(
{ error: 'Not found', code: 'NOT_FOUND' },
{ status: 404 }
);
return NextResponse.json(
{
error: 'Validation failed',
code: 'VALIDATION_ERROR',
details: [
{ path: 'email', message: 'Invalid email format' },
],
},
{ status: 400 }
);
```
## HTTP Status Codes
| Code | Use Case |
|------|----------|
| 200 | Successful GET, PUT, PATCH |
| 201 | Successful POST (created) |
| 204 | Successful DELETE (no content) |
| 400 | Invalid request/validation error |
| 401 | Not authenticated |
| 403 | Not authorized (authenticated but forbidden) |
| 404 | Resource not found |
| 409 | Conflict (duplicate, etc.) |
| 429 | Rate limit exceeded |
| 500 | Server error |
## OpenAPI Documentation
Update `docs/openapi.yaml` when adding endpoints:
```yaml
paths:
/api/feature:
get:
summary: List features
tags: [Features]
security:
- cookieAuth: []
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
'200':
description: Success
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Feature'
'401':
$ref: '#/components/responses/Unauthorized'
post:
summary: Create feature
tags: [Features]
security:
- cookieAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateFeatureRequest'
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/Feature'
'400':
$ref: '#/components/responses/ValidationError'
'401':
$ref: '#/components/responses/Unauthorized'
components:
schemas:
Feature:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
createdAt:
type: string
format: date-time
required: [id, name, createdAt]
CreateFeatureRequest:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 100
required: [name]
responses:
Unauthorized:
description: Not authenticated
content:
application/json:
schema:
type: object
properties:
error:
type: string
example: Unauthorized
ValidationError:
description: Validation failed
content:
application/json:
schema:
type: object
properties:
error:
type: string
details:
type: array
items:
type: object
properties:
path:
type: string
message:
type: string
```
## Route Handler Patterns
### Dynamic Routes
```typescript
// src/app/api/feature/[id]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
// Validate ID format
if (!isValidUUID(id)) {
return NextResponse.json(
{ error: 'Invalid ID format' },
{ status: 400 }
);
}
const item = await db.query.features.findFirst({
where: eq(features.id, id),
});
if (!item) {
return NextResponse.json(
{ error: 'Not found' },
{ status: 404 }
);
}
return NextResponse.json(item);
}
```
### Pagination
```typescript
interface PaginatedResponse<T> {
data: T[];
pagination: {
page: number;
limit: number;
total: number;
totalPages: number;
};
}
async function getPaginated(page: number, limit: number) {
const offset = (page - 1) * limit;
const [data, [{ count }]] = await Promise.all([
db.query.features.findMany({
limit,
offset,
orderBy: desc(features.createdAt),
}),
db.select({ count: count() }).from(features),
]);
return {
data,
pagination: {
page,
limit,
total: count,
totalPages: Math.ceil(count / limit),
},
};
}
```
## References
- [Zod Documentation](https://zod.dev)
- [Next.js Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/route-handlers)
- [OpenAPI Specification](https://swagger.io/specification/)
- [Dub.co Zod Validation](https://dub.co/blog/zod-api-validation)Related Skills
windows-95-web-designer
Modern web applications with authentic Windows 95 aesthetic. Gradient title bars, Start menu paradigm, taskbar patterns, 3D beveled chrome. Extrapolates Win95 to AI chatbots, mobile UIs, responsive layouts. Activate on 'windows 95', 'win95', 'start menu', 'taskbar', 'retro desktop', '95 aesthetic', 'clippy'. NOT for Windows 3.1 (use windows-3-1-web-designer), vaporwave/synthwave, macOS, flat design.
windows-3-1-web-designer
Modern web applications with authentic Windows 3.1 aesthetic. Solid navy title bars, Program Manager navigation, beveled borders, single window controls. Extrapolates Win31 to AI chatbots (Cue Card paradigm), mobile UIs (pocket computing). Activate on 'windows 3.1', 'win31', 'program manager', 'retro desktop', '90s aesthetic', 'beveled'. NOT for Windows 95 (use windows-95-web-designer - has gradients, Start menu), vaporwave/synthwave, macOS, flat design.
win31-pixel-art-designer
Expert in Windows 3.1 era pixel art and graphics. Creates icons, banners, splash screens, and UI assets with authentic 16/256-color palettes, dithering patterns, and Program Manager styling. Activate on 'win31 icons', 'pixel art 90s', 'retro icons', '16-color', 'dithering', 'program manager icons', 'VGA palette'. NOT for modern flat icons, vaporwave art, or high-res illustrations.
win31-audio-design
Expert in Windows 3.1 era sound vocabulary for modern web/mobile apps. Creates satisfying retro UI sounds using CC-licensed 8-bit audio, Web Audio API, and haptic coordination. Activate on 'win31 sounds', 'retro audio', '90s sound effects', 'chimes', 'tada', 'ding', 'satisfying UI sounds'. NOT for modern flat UI sounds, voice synthesis, or music composition.
web-wave-designer
Creates realistic ocean and water wave effects for web using SVG filters (feTurbulence, feDisplacementMap), CSS animations, and layering techniques. Use for ocean backgrounds, underwater distortion, beach scenes, ripple effects, liquid glass, and water-themed UI. Activate on "ocean wave", "water effect", "SVG water", "ripple animation", "underwater distortion", "liquid glass", "wave animation", "feTurbulence water", "beach waves", "sea foam". NOT for 3D ocean simulation (use WebGL/Three.js), video water effects (use video editing), physics-based fluid simulation (use canvas/WebGL), or simple gradient backgrounds without wave motion.
web-design-expert
Creates unique web designs with brand identity, color palettes, typography, and modern UI/UX patterns. Use for brand identity development, visual design systems, layout composition, and responsive web design. Activate on "web design", "brand identity", "color palette", "UI design", "visual design", "layout". NOT for typography details (use typography-expert), color theory deep-dives (use color-theory-expert), design system tokens (use design-system-creator), or code implementation without design direction.
web-cloud-designer
Creates realistic cloud effects for web using SVG filters (feTurbulence, feDisplacementMap), CSS animations, and layering techniques. Use for atmospheric backgrounds, weather effects, skyboxes, parallax scenes, and decorative cloud elements. Activate on "cloud effect", "SVG clouds", "realistic clouds", "atmospheric background", "sky animation", "feTurbulence", "weather effects", "parallax clouds". NOT for 3D rendering (use WebGL/Three.js skills), photo manipulation (use image editing tools), weather data APIs (use data integration skills), or simple CSS gradients without volumetric effects.
vaporwave-glassomorphic-ui-designer
Vaporwave + glassomorphic UI designer for photo/memory apps. Masters SwiftUI Material effects, neon pastels, frosted glass blur, retro-futuristic design. Expert in 2025 UI trends (glassmorphism, neubrutalism, Y2K), iOS HIG, dark mode, accessibility, Metal shaders. Activate on 'vaporwave', 'glassmorphism', 'SwiftUI design', 'frosted glass', 'neon aesthetic', 'retro-futuristic', 'Y2K design'. NOT for backend/API (use backend-architect), Windows 3.1 retro (use windows-3-1-web-designer), generic web (use web-design-expert), non-photo apps (use native-app-designer).
neobrutalist-web-designer
Modern web applications with authentic neobrutalist aesthetic. Bold typography, hard shadows (no blur), thick black borders, high-contrast primary colors, raw visual tension. Extrapolates neobrutalism to SaaS dashboards, e-commerce, landing pages, startup MVPs. Activate on 'neobrutalism', 'neubrutalism', 'brutalist', 'bold borders', 'hard shadows', 'raw aesthetic', 'anti-minimalism', 'gumroad style', 'figma style'. NOT for glassmorphism (use vaporwave-glassomorphic-ui-designer), Windows retro (use windows-3-1-web-designer or windows-95-web-designer), soft shadows, gradients, neumorphism.
native-app-designer
Creates breathtaking iOS/Mac and web apps with organic, non-AI aesthetic. Expert in SwiftUI, React animations, physics-based motion, and human-crafted design. Use for iOS/Mac app UI, React/Vue animations, native-feel web apps, physics-based motion design. Activate on "SwiftUI", "iOS app", "native app", "React animation", "motion design", "UIKit", "physics animation". NOT for backend logic, API design (use backend-architect), simple static sites (use web-design-expert), or pure graphic design (use design-system-creator).
ml-system-design-interview
Coaches end-to-end ML system design interviews covering inference pipelines, recommendation systems, RAG, feature stores, and monitoring. Use for L6+ design rounds, ML architecture whiteboarding, system design practice, serving tradeoff analysis. Activate on "ML system design", "ML interview", "recommendation system design", "RAG architecture", "feature store design", "model serving". NOT for coding interviews, behavioral questions, ML theory quizzes, or paper implementations.
interior-design-expert
Expert interior designer with deep knowledge of space planning, color theory (Munsell, NCS), lighting design (IES standards), furniture proportions, and AI-assisted visualization. Use for room layout optimization, lighting calculations, color palette selection for interiors, furniture placement, style consultation. Activate on "interior design", "room layout", "lighting design", "furniture placement", "space planning", "Munsell color". NOT for exterior/landscape design, architectural structure, web/UI design (use web-design-expert), brand color theory (use color-theory-palette-harmony-expert), or building codes/permits.