API Design: What Makes an API Good or Bad
An API Is a Promise to Every Future Caller
Once something calls your API in production, every field name, status code, and behavior becomes something you can't casually change without breaking someone - even if "someone" is just your own frontend six months from now, after you've forgotten the details. Good API design is mostly about making that promise as small, clear, and stable as possible.
Bad: GET /getUserData?userid=42&format=json
Good: GET /users/42
Bad: 200 OK {"error": "user not found"}
Good: 404 Not Found {"error": "user not found"}
Bad: a field silently renamed from "name" to "fullName" in v1
Good: a new /v2/ path, with /v1/ kept working until callers migrateREST's actual convention: resources are nouns in the URL (`/users/42`), actions are HTTP methods (GET to read, POST to create, PUT/PATCH to update, DELETE to remove) - not verbs stuffed into the path (`/getUser`, `/deleteUser`). Status codes should reflect what actually happened, not just always return 200 with an error buried in the body - that breaks caching, monitoring, and every HTTP client's built-in error handling.
Versioning matters the moment more than one client depends on your API. It doesn't need to be elaborate - even "the old behavior keeps working at /v1/ while a genuinely breaking change ships at /v2/" beats silently changing a response shape underneath every existing caller and hoping nothing downstream breaks.