API Development Patterns
PLAPI development patterns for coding agents are three production fixes: idempotency-key middleware so a retried POST never charges twice, keyset pagination on a unique composite key so no row is dropped at a page boundary, and an OpenAPI document generated from the handlers’ Zod schemas. Each pattern ships with a test that proves it without a line-by-line review.
This recipe is for backend developers who let an agent write endpoints and want proof that they hold under retries, concurrent writes, and schema changes. Your POST /orders charges a customer twice when the mobile app retries on a weak connection. Your “next page” skips an order whenever two orders share a created_at. The OpenAPI file drifted from the code three sprints ago, so the generated client is wrong for every frontend developer who trusts it. All three bugs pass code review, because the code looks correct. Only a test that runs the failure shows the bug.
The anchor stack is Express, TypeScript, Zod, Postgres, and Redis. The prompts port to Fastify, NestJS, or Next.js Route Handlers with a one-line change. If you have not designed the contract yet, start with spec-first API development with agents; this page picks up once the routes exist.
What you’ll walk away with from these API patterns
Section titled “What you’ll walk away with from these API patterns”- A convention-matching prompt for a new endpoint, and how to launch it in each tool.
- An idempotency-key middleware prompt that claims the key before the handler runs, so two concurrent retries cannot both charge.
- A keyset pagination prompt with a composite sort, a matching index, and a cursor that keeps microsecond precision.
- An OpenAPI 3.1 from Zod prompt with a CI check that fails when the spec is stale.
- A verification run that turns all of this into evidence you check instead of reading the handler code.
How do you get an agent to follow your existing route conventions?
Section titled “How do you get an agent to follow your existing route conventions?”Give the agent one existing route as the reference and forbid new abstractions. Agents that are not shown a reference invent their own error classes, response envelopes, and validation helpers. This prompt works in all three tools.
How you launch it depends on the tool. Start in a planning mode, so you approve the file list before anything is written.
In the Agent panel, reference the two convention files with @src/routes/users.ts and @src/middleware/errors.ts, and paste the prompt. Switch to Plan Mode first for a new route: it writes an implementation plan before any code, and you confirm the file list. Then let Agent run the tests and review the per-file diffs it shows. Look first at the test file, not the handler.
Run it from the repository root in plan mode, so Claude Code proposes the change before editing:
claude --permission-mode plan "$(cat prompts/add-orders-route.txt)"Approve the plan, and Claude Code reads the reference files, edits, and runs the test command. To run the same prompt unattended in CI, use claude -p with --output-format json and an explicit --allowedTools list.
Run it interactively with writes confined to the workspace. The permission profile below is beta in Codex CLI 0.157.1. OpenAI now prefers it over the legacy --sandbox flag, and the two do not compose, so do not combine them.
codex -c 'default_permissions=":workspace"' -a on-request "$(cat prompts/add-orders-route.txt)"For a non-interactive run, put -a never before the subcommand (codex -a never exec …) and add -o result.md to capture the agent’s final report.
Save the prompt as prompts/add-orders-route.txt so the whole team runs the same one. The same pattern applies to every prompt on this page.
How do you stop a retried POST from charging twice?
Section titled “How do you stop a retried POST from charging twice?”A client that times out cannot tell whether the server processed the request, so it retries. The fix is an Idempotency-Key header. The server records the first response under that key and replays it for every repeat. Agents write the happy path correctly. They miss the concurrent case, because the naive version stores the response only after the handler finishes. Two simultaneous retries both find an empty cache, and both charge.
Two decisions stay with you, and neither is visible in the diff. First, the retention window: a 24-hour TTL means a retry on day two charges again. Match the TTL to the longest retry window of your slowest client, such as an offline mobile queue. Second, Redis is a cache. An eviction or a failover forgets keys, which is why the prompt asks for the unique constraint on orders.idempotency_key. The database refuses the second insert even when Redis has forgotten the first. Test 2 is the one that matters. If it passes with 10 parallel requests, the race is closed, whatever the middleware looks like inside.
How do you paginate an API without dropping or repeating rows?
Section titled “How do you paginate an API without dropping or repeating rows?”Offset pagination (?page=3&limit=20) shifts every time a row is inserted while someone pages. Cursor (keyset) pagination fixes that, but agents introduce two quieter bugs. They sort on a non-unique column, so rows that share a created_at are skipped or repeated at the page boundary. They also round-trip the timestamp through a JavaScript Date, which keeps milliseconds while Postgres timestamptz stores microseconds. That produces the same skip on data that looks unique.
Test 3 switches off sequential scans (or seeds enough rows) because on a table of 57 rows the Postgres planner rightly prefers a sequential scan, so a bare EXPLAIN assertion would flake, and an agent that sees it flake will weaken it instead of fixing the query.
You do not have to read the SQL to trust the result. Test 1 is a complete walk: if any row is lost or duplicated at any boundary, the set comparison fails. To widen it, turn the fixed 57 rows into a generated property (“for any multiset of timestamps and any page size, the walk returns every row once”), as described in property-based testing with agents. Test 3 guards the performance half of the pattern. Without the composite index, the keyset query is correct but scans the table, and that only shows up in production at scale. For index and query-plan work beyond this endpoint, see SQL optimization patterns.
How do you keep the OpenAPI spec from drifting away from the code?
Section titled “How do you keep the OpenAPI spec from drifting away from the code?”A hand-written spec drifts, because nothing fails when it goes stale. Generate it from the Zod schemas the handlers already validate against, commit the output, and let CI fail when the committed file differs from a fresh build. @asteasolutions/zod-to-openapi (npm, 9.1.0 on 2026-09-26) builds OpenAPI 3.x documents from registered Zod schemas.
The git diff --exit-code step is what keeps the spec current. It is more robust than an in-memory comparison test, because it checks the exact file that consumers download. Lint the result with npx @redocly/cli lint openapi.json (Redocly CLI 2.54.3 on 2026-09-26) to catch missing operation IDs and undeclared security. When a route has no schema, the prompt tells the agent to stop, not to invent one. An agent that “fills the gap” writes the hand-maintained spec you are trying to remove.
How do you verify the agent’s API code without reading every line?
Section titled “How do you verify the agent’s API code without reading every line?”Run the service and attack it with its own contract. Schemathesis (PyPI, 4.28.0 on 2026-09-26) reads openapi.json, generates valid and invalid requests for every operation, and checks each response against the spec: server errors, status codes, response schemas, and whether invalid input is rejected.
# Terminal, with the API running locally on port 3000uvx schemathesis run openapi.json --url http://localhost:3000 --checks all --max-time 120A green Schemathesis run, the concurrency test, and the pagination walk together prove more than a careful read of the handlers. Hand the whole run to the agent, and ask for the result as evidence rather than as a summary.
What the reviewer reads changes as a result. The reviewer reads the openapi.json diff (the contract) and the evidence table, not the middleware. A contract change that removes or narrows a field needs sign-off from the team that consumes the API. A change with no contract diff and green checks needs only the owning team’s approval. The page on the evidence bundle an agent’s pull request must carry turns this into a PR contract with a CI check. Protecting the oracle covers the rule in the last line of the prompt: an agent must not edit the tests that judge it.
How do you open the API pull request through the GitHub MCP server?
Section titled “How do you open the API pull request through the GitHub MCP server?”When the spec changes, the agent can open the pull request, attach the evidence section, and request review from the consuming team through GitHub’s official MCP server. The remote server at https://api.githubcopilot.com/mcp/ takes a GitHub personal access token in an Authorization header in all three clients. The commands below use a PAT kept in an environment variable, never in a committed file.
Add a github server with the URL https://api.githubcopilot.com/mcp/ and an Authorization: Bearer header in ~/.cursor/mcp.json (your user config, outside the repository). The GitHub MCP server guide has the exact JSON.
claude mcp add --transport http github https://api.githubcopilot.com/mcp/ \ -H "Authorization: Bearer $GITHUB_PAT"codex mcp add github --url https://api.githubcopilot.com/mcp/ --bearer-token-env-var GITHUB_PATIf the agent already has the gh CLI and a shell, gh pr create --body-file evidence.md does the same job with fewer tokens. Use the MCP server when you want the agent to also read CI logs and review comments without shell access.
When agent-written API patterns break in production
Section titled “When agent-written API patterns break in production”Where to go next with API patterns
Section titled “Where to go next with API patterns”- Spec-first API development with agents: design the contract, auth, and versioning before the routes on this page exist.
- API test automation: contract and consumer tests that extend the Schemathesis run.
- Node.js and Express recipes: JWT auth, rate limiting, and background jobs on the same stack.
- Serverless development patterns: deploying these APIs to functions and the edge, where idempotency matters even more.
- Reading evidence instead of code: why the reviewer on this page reads the contract and the checks rather than the code.
Did this guide help you?
One tap, no sign-in.
What will you do with it?
How did it read?
What got in the way? Pick any that apply
Your role?
Thanks. I read every answer. Michał Jaskólski
Did this guide help?
One tap each. Close whenever you like.
no sign-in