Designing APIs That Are Hard to Misuse
Source: Dev.to
Assumptions About API Consumers
When designing an API, don’t assume:
- Consumers will read the docs carefully.
- Inputs will always be valid.
- Calls will be made in the correct order.
Assume instead:
- Someone will misunderstand it.
- Someone will skip validation.
- Someone will copy‑paste an example without thinking.
A good API doesn’t rely on “being used correctly.” It enforces correctness by design.
Ambiguous APIs Invite Misuse
Bad example
POST /updateUser
What does this update?
- name?
- email?
- password?
- all of them?
Better example
PATCH /users/{id}/email
Now:
- The intent is clear.
- The scope is limited.
- Misuse becomes harder.
If an endpoint can do “too many things,” it will eventually do the wrong one. Senior engineers try to design APIs where invalid states cannot exist.
Designing for Consistent State
Problematic payload
{
"status": "active",
"deleted": true
}
A user cannot be both active and deleted. The API should reject such contradictory inputs.
Desired design
- The API does not accept conflicting fields.
- The data model prevents impossible states.
If your API allows contradictory data, the bug isn’t in the client — it’s in the design.
Handling Invalid Input
Silent behavior (dangerous)
- Missing field → default value applied
- Invalid input → ignored
- Partial failure → success response
This makes bugs invisible.
Preferred approach
- Reject invalid input loudly.
- Return clear error messages.
- Fail fast and early.
APIs should teach consumers how to use them correctly through explicit errors.
Avoid “Magic” Behavior
Magic APIs feel convenient at first — and painful later.
Examples of magic behavior
- Auto‑creating resources without saying so.
- Silently retrying without limits.
- Changing behavior based on hidden flags.
If something important happens, make it explicit.
Idempotency and Safe Retries
In real systems:
- Requests get retried.
- Clients time out.
- Networks fail.
If calling an API twice causes unintended side effects, it will break in production.
Design guidelines
- Repeated requests are safe.
- Duplicate calls don’t corrupt state.
- Clients don’t need complex retry logic.
This alone prevents many production incidents.
Preventing Misunderstanding
The person using your API in six months might:
- Not be you.
- Not know the original context.
- Be under pressure.
Ask yourself:
- Can this API be misunderstood?
- Can it be called in the wrong order?
- Can misuse cause data corruption?
If the answer is “yes,” redesign.
Real‑world bug example
POST /processPayment
Called twice → double charge.
Better design
- Separate intent from execution.
- Require idempotency keys.
- Make side effects explicit.
The extra effort up front saves incidents later.
Final Takeaway
APIs are contracts, not just endpoints. A well‑designed API:
- Limits what can go wrong.
- Makes correct usage obvious.
- Makes incorrect usage difficult.
- Protects the system from human error.
Senior engineers don’t just design APIs that work — they design APIs that are hard to misuse.