Over the past two years we have designed more than a dozen REST APIs for various clients. Some turned out well, some less so. Here is a summary of what works, what does not, and what we would do differently.
URL Design — Consistency Over Cleverness¶
Nouns, not verbs. /api/v1/users, not /api/v1/getUsers. Plural consistently. Nesting only one level deep — /users/123/orders is fine, deeper is not. Prefer /order-items/789 with filtering instead.
Versioning — URL Path Won¶
We tried three approaches: URL path (/api/v1/), header (Accept: application/vnd.myapp.v1+json), and query param. URL path won — every developer understands it, it works in a browser, and caches understand it too.
Error Handling — Be Verbose¶
Our first API returned: {"error": "Bad request"}. Useless. Our current format (inspired by RFC 7807):
{
"status": 422,
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [
{"field": "email", "message": "Invalid email address format"}
],
"traceId": "abc-123-def"
}
HATEOAS — Theory vs. Practice¶
We tried Spring HATEOAS. For public APIs it makes sense. For internal APIs where the frontend team sits next to you? Overhead with no benefit. Frontend developers ignored the links and hardcoded URLs anyway. Beautiful in theory, different in practice.
Documentation — Swagger Is a Necessity¶
Swagger generates interactive documentation from annotations. A game-changer for onboarding. But contract-first is better — write the YAML manually and generate code from it. More work, but a single source of truth.
Security — OAuth 2.0 and JWT¶
OAuth 2.0 with JWT tokens. Access token in the Authorization header, refresh token in an httpOnly cookie. JWT is self-contained — verification does not require a call to the auth server. But JWT cannot be revoked — we handle this with a blacklist in Redis.
Top 5 Mistakes We Made¶
- Returning 200 OK for errors (with an error in the body)
- No rate limiting — DoS from our own frontend
- Using PUT instead of PATCH for partial updates
- No request/response logging
- Excessive optimism about backward compatibility
An API Is a Product¶
A REST API is not just a technical detail — it is an interface for people (developers). Design it with empathy. Document it. Version it. And above all — test it from the consumer’s perspective.
Need help with implementation?
Our experts can help with design, implementation, and operations. From architecture to production.
Contact us