TechAPI design

Design an API People Can Live With

Picking REST or GraphQL is the smallest decision you will make. Retries, auth and rate limits are the ones your callers will actually feel.

8 articles · about 74 min in total

Start with What Is an API, Really

REST or GraphQL is the decision teams argue about, and it is close to the least consequential one on the list. Callers do not remember your resource modeling. They remember the day a retry double-charged a customer.

The properties that actually determine whether an API is pleasant to depend on are operational. Can I retry this safely. What happens when I exceed the limit, and does the response tell me when to come back. How does auth fail, and does the error say enough to fix it without opening a support ticket.

That is why idempotency and rate limiting sit in the middle of this path rather than at the end as an afterthought. They are contract, not infrastructure. A caller has to know them before writing the first integration, which means they belong in the design.

The last three steps are the auth stack, in order of how often each is misused. JWTs are adopted to avoid session state and then given a denylist, which is sessions with extra network calls. OAuth is used as a login system, which is not what it is. Both mistakes are common enough to be worth naming.

Key takeaways

  • Retry safety, rate limit behavior and auth failure modes shape an API developer experience far more than the choice between REST and GraphQL.
  • A JWT that requires a revocation denylist has become a session with extra network calls, so the stateless argument for it no longer applies.
  • OAuth is an authorization framework rather than a login system, and OpenID Connect is the layer that turns it into authentication.
  • A rate limit response should say when the caller may retry, because a limit without that information forces every client to guess.
  1. Step 1: What Is an API, Really

    An API is the contract that lets one piece of software ask another for something without knowing how it works inside. Here is what that means, from the waiter analogy down to endpoints, JSON, keys, and rate limits, plus why APIs quietly run the whole economy.

    May 16, 2026 · 8 min read

  2. Step 2: REST vs GraphQL vs gRPC: How to Actually Pick an API Style

    Most REST vs GraphQL vs gRPC posts list features in a table and stop. The real decision isn't about features. It's about who consumes your API and what hurts at scale.

    May 28, 2026 · 11 min read

  3. Step 3: Rate Limiting: The Algorithm Is the Easy Part

    Everyone compares token bucket to sliding window and stops there. The decisions that actually determine whether a rate limiter works are what you key it on, whether your Retry-After header is quietly scheduling a thundering herd, and whether a client that gets a 429 can safely retry at all.

    Jul 29, 2026 · 9 min read

  4. Step 4: An Idempotency Key Promises One Execution, Not Eventual Success

    The design detail that surprises people: Stripe caches the result of the first request under a key even when that result was a 500, and replays the failure to every retry. That is correct, and once you see why, the rest of the design follows, including where most homegrown implementations go wrong.

    Jul 29, 2026 · 9 min read

  5. Step 5: Webhooks vs Polling: The Four Problems Push Hands You

    Polling a resource once a minute costs 1,440 requests a day, almost all of them empty. A webhook fixes that by inverting the call, and in exchange hands you signature verification, duplicate events, out-of-order events, and retry storms. Here is what each one actually costs.

    Aug 8, 2026 · 9 min read

  6. Step 6: If Your JWT Needs a Denylist, You Have Rebuilt Sessions With Extra Steps

    JWTs are the default choice for new apps and usually the wrong one. The reason is revocation: there is no row to delete. And the standard fix, a server-side denylist, reintroduces the database lookup that was the entire point of going stateless.

    Jul 29, 2026 · 9 min read

  7. Step 7: OAuth Is Not a Login System. And as of 2.1 There Is Only One Flow.

    Two things would prevent most OAuth bugs. OAuth answers what a caller may access, not who they are, so using it to log people in is a category error. And the flow chart everyone agonized over has collapsed: authorization code plus PKCE, for every client type, no exceptions.

    Jul 29, 2026 · 9 min read

  8. Step 8: OWASP API Security Top 10: A Developer's Practical Defense Guide

    Walk through every OWASP API Security Top 10 vulnerability with real attack examples and code-level mitigations you can ship this week.

    Mar 12, 2026 · 10 min read

Frequently asked questions

Should I use REST, GraphQL or gRPC?
REST for public APIs with many unknown consumers, gRPC for internal service-to-service calls where both sides ship together, and GraphQL when clients genuinely need to shape their own queries. The operational contract matters more than the choice in all three cases.
How do I make an API safe to retry?
Accept an idempotency key on any request that changes state, store the result against that key, and return the stored result on a repeat. That way a client can retry a timed-out request without risking a second charge or a duplicate record.
Are JWTs better than sessions?
Only when you genuinely need stateless verification across services that cannot share a session store. As soon as you need immediate revocation you add a denylist, which reintroduces the shared state sessions already had, plus a larger token on every request.
What is the difference between webhooks and polling?
A webhook pushes an event to you when it happens, and polling asks repeatedly whether anything changed. Webhooks are more efficient and harder to operate, because you now own an endpoint that must be idempotent, fast and available.