DEV Community

Nex Tools
Nex Tools

Posted on • Originally published at nextools.hashnode.dev

Claude Code for API Design: How I Stopped Shipping Endpoints I Regret Six Months Later

Originally published on Hashnode. Cross-posted for the DEV.to community.

The first public API I designed had 47 endpoints. Eight months later, 31 of them were either deprecated, broken, or quietly ignored by the only client that ever consumed them. Two were so badly named that we shipped a v2 just to rename them. One returned a different shape depending on which day of the week you called it, because of a bug nobody had caught in code review. The whole thing was a monument to what happens when an engineer designs an API by writing endpoints in the order they get requested.

That was 2021. Since then I have shipped four more public APIs and a handful of internal ones. Three of them I actually like. The other one is fine. None of them have the embarrassing mid-stream redesigns that the first one had. The difference is not that I got smarter. The difference is that I stopped designing APIs by typing route handlers and started designing them by having a conversation with Claude Code about what the API is for.

This is a workflow article, not a theory article. I am going to walk you through how I use Claude Code to design APIs from a blank slate, how I review existing APIs for design problems before they ship, and how I evolve APIs without breaking the clients that depend on them. The patterns are language and framework agnostic. I have used them for REST, GraphQL, and gRPC services. The tooling matters less than the discipline.


Why API Design Goes Wrong

Most APIs that age badly share a common failure mode. The team designs the API by following the immediate request pattern. The first client wants a way to fetch users, so we add GET /users. The second client wants a way to fetch a user by id, so we add GET /users/:id. The third client wants to filter users by status, so we add GET /users?status=active. Six months later we have 40 endpoints, three different ways to filter, two different pagination strategies, and an inconsistent response envelope.

The problem is not that any individual decision was wrong. Each endpoint, viewed in isolation, made sense at the time it was added. The problem is that nobody designed the API as a whole. The API emerged from accumulated requests, and emergent designs almost always have rough edges.

The second failure mode is designing for the present implementation instead of the future contract. The team exposes the database schema directly because that is what the implementation looks like today. Six months later the database schema changes and now the API has to either change too (breaking clients) or include a translation layer that nobody has time to maintain. Either way, somebody is unhappy.

The third failure mode is the optimistic naming problem. The team names the endpoint after what it does today, not what it represents conceptually. POST /sendWelcomeEmail becomes a problem the moment the product team decides welcome emails should sometimes be SMS messages. Now you have an endpoint named after a transport when the actual concern is the welcome flow.

APIs are contracts. Contracts are about what they promise, not how they are currently fulfilled.

I have made all three of these mistakes more than once. The reason I have stopped making them is that Claude Code now flags them before they ship.


The Design Conversation Skill

Before I write any route handlers, I have a design conversation with Claude Code about what the API is for. This is not a casual chat. It is a structured process that produces a markdown document I commit to the repo before the first endpoint exists.

The conversation has five sections.

The first section is the actor inventory. Who calls this API, and what are they trying to accomplish? Not what features they need, but what jobs they are trying to do. A mobile app trying to render a user profile is doing a different job than a backend service trying to validate a webhook signature, even if both involve the same user record. Most APIs are easier to design when you know the jobs first.

The second section is the resource inventory. What are the nouns this API talks about? Not the database tables. The conceptual nouns. Sometimes a database has six tables but the API only has two resources because the other four are implementation details. Sometimes the database has one table but the API has three resources because what looks like one entity to the storage layer is three different concepts to the consumer.

The third section is the operation inventory. For each resource, what operations does the API support? Create, read, update, delete are the obvious ones, but most APIs need more. Listing with filters. Bulk operations. State transitions that are not just updates. Search. Subscriptions. Each one needs to be explicit so that nothing surprises us later.

The fourth section is the consistency rules. How does this API handle pagination? Errors? Idempotency? Versioning? Authentication? These are the cross-cutting concerns that, if left ad-hoc, end up inconsistent across endpoints. Decide them once and document them.

The fifth section is the explicit non-goals. What is this API not for? Which use cases are out of scope? This section saves more arguments than any other section in the document. Six months from now when somebody asks "can we add a search endpoint to this API," the non-goals section gives a principled answer.

The skill takes my rough description of what I am building and produces a draft of all five sections. I review it, push back on the parts that feel wrong, and iterate until I have a document I would be willing to defend in a design review.


The Endpoint Specification Skill

Once the design document is settled, I move to specifying individual endpoints. The endpoint specification skill takes a resource and an operation and produces a complete specification including the URL path, the HTTP method, the request shape, the response shape, the error responses, the idempotency behavior, and the authentication requirements.

This is where most of the bugs in API design get caught. Writing a specification forces you to confront edge cases that are easy to ignore when you are typing route handlers. What happens if the request body is malformed? What happens if the resource does not exist? What happens if the user is authenticated but lacks permission? What happens if a required field is empty versus missing?

The specification format I use looks like this:

POST /api/v1/orders
Auth: Bearer token (scope: orders:write)
Idempotency: Idempotency-Key header (UUID, 24h retention)

Request:
  {
    customer_id: string (required)
    line_items: [{
      product_id: string (required)
      quantity: integer (required, min: 1, max: 999)
      unit_price_cents: integer (optional, defaults to product price)
    }] (required, min: 1, max: 50)
    shipping_address: AddressObject (required)
    notes: string (optional, max: 500)
  }

Response 201:
  Order resource (full shape)
  Location: /api/v1/orders/{id}

Response 400:
  ValidationError with field-level details

Response 409:
  IdempotencyConflict if same key seen with different body

Response 422:
  BusinessLogicError (e.g., product out of stock)
Enter fullscreen mode Exit fullscreen mode

The skill produces these specifications for every endpoint in the API. I commit them to a specs/ directory. They become the contract that the implementation has to match and that the tests verify.

The discipline of writing specifications first sounds bureaucratic. It is not. It is faster than typing route handlers and discovering the design problems through bugs. The specifications take maybe an hour each. The bugs they prevent take days each.

Want the playbook for setting up Claude Code skills like the API design conversation skill? It is in the Claude Code skills guide. Start with one skill and add more as you find friction in your workflow.


The Consistency Audit Skill

Designing endpoints in isolation is how inconsistencies creep in. The third endpoint uses created_at and the fourth uses createdAt and the fifth uses creationDate. The first list endpoint uses cursor pagination and the second uses offset pagination. The first error response includes a code field and the second does not. Each individual decision is fine. The collection is a mess.

The consistency audit skill takes the full set of endpoint specifications and produces a report of inconsistencies. Naming conventions, pagination strategies, error formats, authentication patterns, response envelopes. Anything that varies across endpoints when it should not.

I run this skill at three points in the API lifecycle. First, after the initial design pass, before any code is written. The earliest fixes are the cheapest. Second, after every batch of new endpoints is added. The skill catches drift from the original conventions. Third, before any major release. The skill provides a final sanity check.

The audit report is brutal in a useful way. Last month it told me I had three different pagination strategies in an API I thought was internally consistent. I had been pattern matching against whichever endpoint I was looking at most recently. The skill noticed what my tired eyes had missed.


The Versioning Strategy Skill

Versioning is where most APIs go to die. The team picks a strategy that sounds reasonable, ships v1, and discovers six months later that the strategy does not work for the actual changes the API needs. By then there are clients depending on v1 and changing the strategy means breaking them.

The versioning strategy skill takes the API design document and produces a versioning plan that covers four scenarios. How do additive changes get versioned? How do breaking changes get versioned? How long does each version stay supported? What is the deprecation process?

The reason this matters is that different versioning strategies suit different APIs. URL path versioning (/api/v1/, /api/v2/) is simple but creates massive code duplication if you maintain multiple major versions. Header versioning is more flexible but harder for clients to discover. Date-based versioning works well for SaaS APIs where clients pin to a specific release. Each strategy has tradeoffs and the right choice depends on the API.

The skill walks through the tradeoffs for the specific API and recommends a strategy with reasoning. I have never accepted the first recommendation without modification, but the recommendation is always close enough to argue with productively.


The Client SDK Generation Skill

Most APIs are easier to use through an SDK than through raw HTTP calls. The problem is that maintaining SDKs in five languages is more work than most teams can sustain. So the SDK either does not exist, or exists in only one language, or exists in five languages but only two are kept up to date.

The client SDK generation skill takes the endpoint specifications and produces SDK code for whatever languages I need. TypeScript, Python, Ruby, Go, Java. The generated SDKs include type definitions, error handling, retries, idempotency key generation, and pagination helpers. They are not as polished as a hand-written SDK by an expert in that language, but they are 80 percent of the way there and they stay in sync with the API automatically.

The trick is that the SDK generation reads the same specifications that the implementation tests verify. If the implementation drifts from the spec, the tests fail. If the spec is updated, the SDK regenerates. The whole pipeline is connected.

This is the kind of thing that used to require a dedicated developer experience team. Now it requires a half day of skill setup and an evening of polish per language.

The same spec-driven workflow applies to internal team APIs too. If you are building a service mesh of internal APIs, the Claude Code memory files approach gives every service a shared context that makes cross-service design conversations dramatically easier.


The Breaking Change Detector

The single most expensive class of API mistake is the accidental breaking change. You think you are making a backwards-compatible change. You are not. A client breaks in production. You roll back. The team loses a day. Trust in the deployment process drops.

The breaking change detector takes the current API specification, the proposed API specification, and produces a report of every change classified as additive, breaking, or ambiguous. Adding a new optional field is additive. Removing a field is breaking. Changing a field from optional to required is breaking. Changing a field from required to optional is technically additive but might break clients that expect the field to always be present.

The ambiguous category is the interesting one. There are changes that are technically backwards-compatible but practically break some clients. Changing the order of fields in a list response. Changing the precision of a float. Changing the timezone of a timestamp. The detector flags these explicitly so I can make a deliberate decision rather than discovering the breakage in production.

I run the detector on every PR that touches the specifications. It is wired into CI. If the PR introduces a breaking change without a corresponding version bump, CI fails. The discipline is enforced by tooling rather than memory.


The Documentation Generation Skill

API documentation is the work that nobody has time for and that everybody complains about when it is missing. Most teams ship documentation that is either nonexistent, out of date, or autogenerated from code in a way that makes it technically complete but practically unusable.

The documentation generation skill takes the endpoint specifications and produces documentation that is more useful than autogenerated reference material. It includes example requests and responses. It includes common workflows that span multiple endpoints. It includes troubleshooting guides for common error conditions. It includes migration guides between versions.

The trick is that the documentation reads the same specifications that everything else reads. So the documentation never drifts from the actual API behavior. If the spec changes, the documentation regenerates. If there is a bug in the documentation, fixing it usually means fixing the spec, which means fixing the implementation, which means the bug gets fixed everywhere at once.

This is one of the workflows where the leverage from Claude Code is most obvious. Documentation that used to take a week to write and that nobody trusted now takes an afternoon to generate and reflects reality.


What This Workflow Has Cost Me

Setting up the design conversation, endpoint specification, consistency audit, versioning strategy, SDK generation, breaking change detector, and documentation generation skills took me about three days. Most of that was iterating on the prompts to produce output I trusted. The skills themselves are short. The expertise is in knowing what good API design looks like, which is not something Claude Code can give me but is something Claude Code can amplify.

The ongoing cost is essentially zero. I run the skills as part of my normal development flow. They produce artifacts I would have wanted to produce anyway. The friction of using them is lower than the friction of skipping them.

The benefit is that I have not shipped a regrettable API since I started using this workflow. The APIs I ship are more consistent, better documented, and more pleasant to consume. The clients that integrate with them complain less. The teams that maintain them complain less. The on-call burden from API issues is lower.

There is a version of this article that is about specific tools. This is not that article. The tools I use are not magic. The discipline is.


The Bottom Line

API design is a leverage activity. The decisions you make in the first week of an API live with you for years. The cost of getting them right early is dramatically lower than the cost of getting them wrong and discovering the mistake six months later when there are clients depending on the wrong shape.

Claude Code does not turn me into a better API designer. It turns me into the API designer I would be if I had infinite patience for writing specifications, running consistency audits, and producing migration guides. Most engineers know what good API design looks like. Most engineers do not have time to do all the work that good API design requires. Claude Code closes that gap.

If you are about to design a new API, do not start by typing route handlers. Start by writing the design document. Then write the endpoint specifications. Then audit them for consistency. Then implement. The implementation will be faster because you will not be redesigning while you type, and the API will be better because you will have thought it through before you committed to it.

If this workflow resonates, the team workflows guide shows how to scale these patterns across an engineering team. The hardest part is not the tooling. The hardest part is the cultural shift from typing first to thinking first.

The APIs I am proudest of were the ones I designed slowest. Claude Code makes slow design fast.

Top comments (0)