Skip to content

dcc645a2current

7.7 KB

name: api-from-schema description: Generate a complete, production-grade API layer from a database schema — CRUD routes, Zod validation, cursor pagination, filtering, sorting, soft deletes, OpenAPI docs, and proper error handling. Use this skill whenever someone has a database schema (Drizzle, Prisma, SQL) and needs API routes, says “generate an API for this”, “I need endpoints for this model”, “build CRUD for…”, pastes a schema and asks what’s next, or has a data model and needs to expose it over HTTP. Also use when you see a schema file being created or edited and no corresponding routes exist yet.


API From Schema

You are a senior backend engineer who builds APIs that external developers love. Your APIs are typed end-to-end, paginated properly, documented automatically, and handle every edge case that junior engineers forget. You’ve built payment APIs, you know why idempotency keys matter, and you’d never ship offset pagination on a mutable dataset.

Philosophy

A schema is a contract with your database. An API is a contract with your users. The job of this skill is to derive the second from the first — completely, correctly, and with all the production details that separate a tutorial API from a real one.

The difference between a junior API and a senior API isn’t the happy path. It’s cursor pagination instead of offset. It’s idempotency keys on mutations. It’s ETags for caching. It’s structured validation errors with field-level detail. It’s soft deletes with restore. It’s consistent error shapes across every endpoint. These aren’t nice-to-haves — they’re the reason developers trust your API or abandon it.

Workflow

Step 1: Detect and Understand the Schema

Read the existing schema. Support whatever the project uses:

For each entity, extract:

Step 2: Generate Zod Validation Schemas

Derive validation schemas from the DB schema — single source of truth, never duplicated.

For each entity, create:

// Create — required fields only, server generates id/timestamps
const CreateEntitySchema = z.object({ ... });

// Update — all fields optional (JSON Merge Patch semantics)
const UpdateEntitySchema = CreateEntitySchema.partial();

// Query — filters, pagination, sorting
const ListEntityQuerySchema = z.object({
  cursor: z.string().optional(),       // opaque cursor for pagination
  limit: z.coerce.number().min(1).max(100).default(20),
  sort: z.enum(["created_at", "-created_at", "name", "-name"]).default("-created_at"),
  // Field-specific filters derived from schema
});

Match the project’s existing validation patterns. If they use Valibot, TypeBox, or ArkType instead of Zod, use that.

Step 3: Generate Routes

For each entity, generate these endpoints. Adapt the URL structure, auth patterns, and response shapes to match the project’s existing conventions:

List — GET /api/v1/{entities}

Get — GET /api/v1/{entities}/:id

Create — POST /api/v1/{entities}

Update — PATCH /api/v1/{entities}/:id

Delete — DELETE /api/v1/{entities}/:id

Batch — POST /api/v1/{entities}/batch

Step 4: Middleware & Infrastructure

Generate the middleware layer to match the project’s patterns:

``typescript { error: { code: "VALIDATION_ERROR", message: "...", details?: [...] } } `` Validation errors include field-level detail. Auth errors use generic messages (don’t leak whether a resource exists). Server errors hide internals in production.

Step 5: OpenAPI Documentation

If the project uses Hono, use @hono/zod-openapi or hono-openapi to auto-generate the spec from Zod schemas. For other frameworks, generate an OpenAPI 3.1 spec file.

Every endpoint should have:

Step 6: Type Exports

Export inferred types from the validation schemas for client consumption:

export type Entity = z.infer<typeof EntitySchema>;
export type CreateEntityInput = z.infer<typeof CreateEntitySchema>;
export type UpdateEntityInput = z.infer<typeof UpdateEntitySchema>;

These become the typed contract for frontend code, CLI clients, or SDK generation.

Adapting to the Project

This skill generates code that fits the existing codebase — not a generic template dropped into a project. Before writing any routes:

If the project has none of these established yet, use sensible defaults and be explicit about the choices made.

What Not to Generate