Skip to content

Navid's Blog

Ideas, Experiments, and Lessons Learned

Menu
Menu

5 API Design Mistakes I Learned the Hard Way

Posted on April 4, 2026 by Navid

I’ve built a lot of APIs over the years. Some were good. Most had problems I didn’t notice until users started complaining or my future self had to maintain them.

Here’s what I’ve learned the hard way about API design — mistakes that cost me hours of debugging and refactoring.

1. Inconsistent Naming Conventions

This one seems small but it quietly destroys developer experience. Using userId in one endpoint and user_id in another, or mixing camelCase with snake_case — it adds up.

Pick one convention and stick with it everywhere. If your API uses camelCase for JSON responses, use it everywhere. Same for endpoints. /getUsers in one place and /fetch-products in another is a red flag.

2. Ignoring Error Responses

For the longest time, my APIs returned 200 OK with a generic “error” message in the body when things failed. That made debugging impossible and broke client-side error handling.

Use proper HTTP status codes:

  • 400 for bad requests (validation errors)
  • 401 for unauthorized access
  • 404 for missing resources
  • 500 for server failures

And return structured error bodies. Something like this:

{
  "error": "validation_failed",
  "message": "Email is required",
  "fields": ["email"]
}

Your frontend team will thank you.

3. Skipping API Versioning

I learned this the hard way when I had to make a breaking change to an API used by multiple clients. No version, no way to deploy safely.

Version from day one. Use URL versioning (/v1/users) or header versioning. URL is simpler and more visible. It gives you room to iterate without breaking existing integrations.

4. Not Planning for Pagination

Your test data has 50 records. Production has 50,000. Suddenly your endpoint times out because you’re returning everything at once.

Implement pagination from the start. Use limit and offset or cursor-based pagination for large datasets. It sounds like extra work upfront but it prevents real problems later.

5. Over-fetching or Under-fetching Data

I used to return everything in a response — all related data, all fields, everything. Clients only needed a few fields but got everything, causing slow response times.

Consider implementing field selection (?fields=id,name,email) or nested resource endpoints. GraphQL solves this differently, but even REST APIs can give clients what they actually need.

Final Thoughts

Good API design isn’t about being perfect on day one. It’s about making choices that don’t trap you later. Think about the developer who has to consume your API — it’s probably you in six months.

Start simple, version early, and make errors easy to debug. Everything else can be refined over time.

5 API Design Mistakes I Learned the Hard Way

Posted on April 4, 2026 by Navid

I’ve built a lot of APIs over the years. Some were good. Most had problems I didn’t notice until users started complaining or my future self had to maintain them.

Here’s what I’ve learned the hard way about API design — mistakes that cost me hours of debugging and refactoring.

1. Inconsistent Naming Conventions

This one seems small but it quietly destroys developer experience. Using userId in one endpoint and user_id in another, or mixing camelCase with snake_case — it adds up.

Pick one convention and stick with it everywhere. If your API uses camelCase for JSON responses, use it everywhere. Same for endpoints. /getUsers in one place and /fetch-products in another is a red flag.

2. Ignoring Error Responses

For the longest time, my APIs returned 200 OK with a generic “error” message in the body when things failed. That made debugging impossible and broke client-side error handling.

Use proper HTTP status codes:

  • 400 for bad requests (validation errors)
  • 401 for unauthorized access
  • 404 for missing resources
  • 500 for server failures

And return structured error bodies. Something like this:

{
  "error": "validation_failed",
  "message": "Email is required",
  "fields": ["email"]
}

Your frontend team will thank you.

3. Skipping API Versioning

I learned this the hard way when I had to make a breaking change to an API used by multiple clients. No version, no way to deploy safely.

Version from day one. Use URL versioning (/v1/users) or header versioning. URL is simpler and more visible. It gives you room to iterate without breaking existing integrations.

4. Not Planning for Pagination

Your test data has 50 records. Production has 50,000. Suddenly your endpoint times out because you’re returning everything at once.

Implement pagination from the start. Use limit and offset or cursor-based pagination for large datasets. It sounds like extra work upfront but it prevents real problems later.

5. Over-fetching or Under-fetching Data

I used to return everything in a response — all related data, all fields, everything. Clients only needed a few fields but got everything, causing slow response times.

Consider implementing field selection (?fields=id,name,email) or nested resource endpoints. GraphQL solves this differently, but even REST APIs can give clients what they actually need.

Final Thoughts

Good API design isn’t about being perfect on day one. It’s about making choices that don’t trap you later. Think about the developer who has to consume your API — it’s probably you in six months.

Start simple, version early, and make errors easy to debug. Everything else can be refined over time.

Categories

  • AI Experiments
  • Coding
  • Debugging Stories
  • Hot Takes
  • Ideas
  • Lessons Learned
  • Project Management
  • Uncategorized
  • Vibe Coding

Recent Posts

  • Why I Stopped Using Microservices for Small Projects
  • I Gave AI Full Access to Our Production Database. Here’s What Happened
  • 5 API Design Mistakes I Learned the Hard Way
  • 5 API Design Mistakes I Learned the Hard Way
  • My Team Spent 2 Weeks Replacing Our Authentication — Here’s What Happened