Quality Assurance Labs
Web Development

Backend API & Microservices Architecture Guide

Senior Web Engineer9 min readPublished Updated

APIs are the contract between frontend and backend. Design them like contracts — versioned, documented, authenticated, rate-limited, and monitored. Here's how we architect backend APIs at QA Labs.

Interconnected microservice server pods
#REST#GraphQL#microservices#API-design#backend-architecture

Your frontend is only as good as the API it talks to. And your API is only as good as its architecture.

Backend API design is the discipline of building interfaces that are stable, versioned, documented, secure, and observable. Get it right and frontend teams move fast. Get it wrong and every release is a negotiation.

REST vs GraphQL vs tRPC

REST: Best for public APIs, simple CRUD, broad client support. Predictable, cacheable, universal.

GraphQL: Best for complex data graphs, multi-client products, evolving frontends. Powerful, but has learning curve and performance pitfalls (N+1, query complexity).

tRPC: Best for TypeScript monorepos, internal tools. End-to-end type safety, zero codegen.

Pick based on context, not hype. Most teams default to REST for public, GraphQL for complex internal, tRPC for TypeScript-internal.

API versioning

Version your API from day one. Even if you never release v2, the discipline prevents breaking changes.

Options:

URL versioning (/v1/users) — Simple, explicit

Header versioning (Accept: application/vnd.api.v2+json) — Clean URLs

Query parameter (/users?version=2) — Easiest, least clean

URL versioning is the most common. Stick with it.

Authentication and authorization

API keys for server-to-server

OAuth 2.0 + JWT for user-facing

mTLS for high-security internal

RBAC or ABAC for authorization

Never roll your own auth. Use battle-tested libraries.

Rate limiting

Every public API needs rate limiting. Common strategies:

Per user (100 req/min)

Per API key (1000 req/hour)

Global (10,000 req/sec)

Return 429 Too Many Requests with Retry-After headers. Document limits publicly.

Microservices — when and when not

Microservices solve specific problems:

Different scaling needs per service

Different teams owning different domains

Different languages for different services

Independent deploy cadence

Microservices introduce:

Network complexity

Distributed tracing needs

Distributed data consistency issues

Operational overhead

Recommendation: Start with a monolith. Split into services when you have a concrete reason (not theoretical scale).

Observability

Logs: Structured JSON, correlation IDs

Metrics: Latency (P50/P95/P99), error rate, throughput

Traces: Distributed tracing (OpenTelemetry)

Alerts: Error rate thresholds, latency thresholds, saturation

You can't operate what you can't observe.

Documentation

Every API needs:

OpenAPI spec (Swagger)

Auth details

Rate limits

Error codes

Example requests/responses

Generate docs from code where possible. Keep them current.

Common mistakes

No versioning strategy

Rolling your own auth

No rate limits

No observability

Microservices too early

Undocumented APIs

Key takeaways

  • REST for public, GraphQL for complex, tRPC for TS-internal
  • Version from day one
  • Never roll your own auth
  • Rate limit every public endpoint
  • Start with a monolith; split when justified
  • Observability is not optional

Further reading

About the author

Senior Web Engineer →

Senior Web Engineer · Quality Assurance Labs

Notes from the lab.

Testing, engineering and growth — delivered to your inbox.

Need a backend architecture review? Book a call

Let's talk →