
API design best practices for modern web applications
How to design an API that stays clear, secure and extensible: resource naming, error formats, pagination, versioning, authentication and documentation.
In short: Good API design means a developer can understand your interface without reading its source code. That takes consistent resource names, predictable error responses, a clear versioning strategy and documentation generated from the code itself. Set these rules before the first endpoint ships and you avoid costly breaking changes across your frontend, mobile app and partner integrations later.
Why API design shapes the whole life of a web application
An API is a contract. Once a frontend, an app or an external partner depends on it, you can no longer reshape it at will. Every renamed field or restructured response forces changes on the other side. That is why the ground rules are worth deciding before anything goes live.
For many mid-sized companies, the API is also how systems get connected: online shop, ERP, CRM. If that is your situation, our post on API-first strategy covers the business side. This one is about the craft.
REST, GraphQL or tRPC: picking the interface style
REST as the sensible default
For public and partner-facing APIs, REST is usually the right call. Every HTTP tool understands it, HTTP caching works out of the box, and every backend developer knows the conventions. Name resources as plural nouns (/orders, /customers/42/invoices) and let the HTTP method express the action.
GraphQL when many different clients need different data
GraphQL pays off when several clients need very different slices of data, for example a full web app and a lean mobile app. The cost is a more complex backend: caching, field-level permissions and protection against expensive queries all need deliberate work.
tRPC for internal TypeScript projects
When frontend and backend live in the same TypeScript repository and only your own team consumes the API, tRPC is a pragmatic option. Types flow straight from server to client without a separate schema. It is not a fit for external partners.
Rules that make an API easy to understand
Consistent names and formats
Pick one casing for field names (camelCase, for instance) and stick to it. Dates go out as ISO 8601 with a time zone. Money goes out as integer cents or a decimal string, never as a floating-point number.
Errors people can act on
A 500 response with the body "Error" helps nobody. Use the right status codes (400 for invalid input, 401 and 403 for missing permissions, 404, 409 for conflicts) and one consistent error object. RFC 9457, "Problem Details for HTTP APIs", defines a proven format for this. Validation errors should name the offending field so the frontend can show the message right next to the input.
Pagination and filtering from day one
List endpoints grow. Ship /orders without pagination and one day it returns tens of thousands of records. For large, changing datasets, cursor-based pagination is more stable than page numbers because new records do not shift the order under the client.
Versioning without chaos
Make changes backwards compatible wherever possible. Adding fields is harmless, removing or renaming them is not. For genuine breaking changes, a version in the path (/v2/) works well because it is visible and easy to route. Announce deprecations early and only switch an old version off once usage has demonstrably dropped to near zero.
Security belongs in the design
Authentication and authorization are part of API design. For web applications, secure session cookies or OAuth 2.0 with short-lived tokens are solid choices. We cover the details in our article on authentication with OAuth, JWT and sessions.
Just as important: check on every request whether this user may access this specific object. Broken object-level authorization sits at the top of the OWASP API Security Top 10. Rate limiting, input validation and a tight CORS configuration round it off. For a broader view, see our post on web security fundamentals.
Documentation that stays current
Hand-written docs go stale. A better approach is an OpenAPI specification that is either generated from the code or used as the source for code and validation. In TypeScript projects, libraries like Zod combined with a generator can produce schema, validation and docs from a single definition. An interactive API explorer and a few realistic example requests save your partners a lot of back-and-forth.
Frequently asked questions (FAQ)
Does a small web application really need careful API design?
Yes, on a small scale. As soon as there are two clients, say web and mobile, consistent errors and clear names pay off. The rules take little time up front and spare you rework later.
Should we use REST or GraphQL?
For most business applications and every partner integration, REST is the simpler and better supported choice. GraphQL is worth it when many different clients need very different data and your team can carry the extra backend complexity.
How do we change an API without breaking existing integrations?
Extend rather than rebuild: add new fields and endpoints while continuing to serve the old ones. For unavoidable breaks, introduce a new version, announce the old one's shutdown well in advance and monitor who still calls it.
What is the best way to document an API?
An OpenAPI specification that stays in sync with the code automatically. Add short explanations of authentication, error format and pagination, because those three topics cause most integration questions.
Conclusion
A good API is barely noticeable in daily use because it behaves the way people expect. That predictability comes from a handful of rules decided early and the discipline to follow them. If you are planning a web application with a clean interface, talk to us about web development.
Related posts
- Why React Remains the Safe Choice for Web Applications
Why React is still the solid choice for business applications: ecosystem, hiring, Server Components, React Native, and an honest look at its weaknesses.
- Next.js 15: what changed and what it means for your project
Next.js 15 explained: React 19, async request APIs, new caching defaults, Turbopack and what these changes mean for web projects and upgrades today.
- Full-stack development with TypeScript: a practical guide
Full-stack TypeScript explained: shared types for frontend and backend, runtime validation, database access, project structure and testing in one overview.
- How to Choose the Right Web Development Agency
How to recognise a good web development agency: references, technology, who does the work, contracts, and the questions to ask in the first conversation.