API & Communication

How services talk to each other and to the outside world. Choice of protocol shapes your entire system design.

Communication Protocol Overview

Protocol Style Best For
REST Request/Response over HTTP External APIs, browser clients, simplicity
gRPC Binary RPC over HTTP/2 Internal service-to-service, high throughput
GraphQL Query language over HTTP Complex frontends with varied data needs
Messaging (Kafka/SQS) Async event streaming Decoupled workflows, high volume
WebSocket Persistent bidirectional connection Real-time: chat, live dashboards

REST

Concept Description
Richardson Maturity Level 0: HTTP tunnel · Level 1: Resources · Level 2: HTTP verbs + status codes · Level 3: HATEOAS
HATEOAS Responses include links to next actions; true REST; rarely implemented
Idempotency GET, PUT, DELETE are idempotent; POST is not
Status codes 2xx success · 3xx redirect · 4xx client error · 5xx server error

Deep Dive: REST — Richardson Maturity, HATEOAS, versioning, idempotency

API Versioning Strategies

Strategy Example Pros / Cons
URI Path /api/v1/orders Simple, visible; not RESTful
Header Accept: application/vnd.api.v1+json RESTful; less discoverable
Query Param /orders?version=1 Easy to test; caching issues
Content Negotiation Accept: application/json;version=2 Clean; complex to implement

gRPC

Concept Description
Protocol Buffers Binary serialization; strongly typed schema; code generation for all languages
HTTP/2 Multiplexed streams; lower latency and overhead than HTTP/1.1
Streaming types Unary (1 req, 1 res) · Server streaming · Client streaming · Bidirectional
Use case Internal service-to-service; high throughput; polyglot environments
Trade-offs Less debuggable than REST; browsers need grpc-web proxy; requires schema management

Deep Dive: gRPC — Protocol Buffers, HTTP/2, streaming types, when to use

GraphQL

Concept Description
Schema Strongly typed; defines Queries, Mutations, Subscriptions
Single endpoint POST /graphql; client specifies exact data shape
N+1 Problem Nested resolvers each trigger individual DB queries — performance killer
DataLoader Batching and caching solution for N+1; groups queries into one
Introspection Schema is self-documenting; disable in production
Use case Complex frontends with varied clients; BFF replacement; rapidly evolving APIs

Deep Dive: GraphQL — Schema, N+1 problem, DataLoader, when GraphQL beats REST

API Gateway

graph TD
    M[Mobile Client] --> GW[API Gateway]
    W[Web App] --> GW
    P[Partner API] --> GW
    GW --> O[Order Service]
    GW --> U[User Service]
    GW --> PAY[Payment Service]

Responsibilities:

Concern What Gateway Does
Routing Path-based, header-based, method-based routing
Authentication Validate JWT / API key before forwarding
Rate Limiting Per-client throttling; return 429 Too Many Requests
SSL Termination TLS at gateway; plain HTTP to internal services
Request Transform Add/remove/rewrite headers; request shaping
Caching Cache idempotent GET responses
Load Balancing Round-robin, least connections across service instances
Observability Centralized access logs, metrics per route

Tools: Kong, AWS API Gateway, Spring Cloud Gateway, Nginx, Envoy, Traefik

Deep Dive: API Gateway — Routing, auth, rate limiting, aggregation patterns

Backend for Frontend (BFF)

Problem: One generic API cannot optimally serve mobile, web, and partner clients simultaneously.

Solution: A separate gateway per client type, each tailored to that client's data shape, auth flow, and performance needs.

graph TD
    MB[Mobile App] --> MBFF[Mobile BFF]
    WB[Web App] --> WBFF[Web BFF]
    PA[Partner] --> PBFF[Partner BFF]
    MBFF --> OS[Order Service]
    WBFF --> OS
    PBFF --> OS
    MBFF --> US[User Service]
    WBFF --> US
Benefit Cost
Each BFF tailored to its client More services to own and deploy
Reduces over-fetching / under-fetching Logic duplication if not careful
Teams own their BFF end-to-end Coordination when backend changes

Deep Dive: BFF Pattern — Per-client backends, ownership models, trade-offs

Service Mesh

Component Description
Data Plane Envoy sidecar proxies injected alongside every service pod
Control Plane Istiod (Istio) — distributes config to all sidecars
VirtualService Traffic routing rules: canary splits, fault injection, retries
DestinationRule Load balancing policy, circuit breaking, mTLS settings
PeerAuthentication Enforce mutual TLS between services
Observability Automatic metrics, distributed traces, access logs — no code changes

When to use: Mature microservices with many services needing consistent security, observability, and traffic management. Overhead not worth it for < 5 services.

Deep Dive: Service Mesh — Istio, Envoy, mTLS, traffic management

Sync vs Async — Decision Guide

Factor Choose Synchronous Choose Asynchronous
Response needed now Yes No
Failure isolation Low — cascades High — producer continues
Temporal coupling Required Not required
Throughput Bounded by slowest service High; consumers scale independently
Example User login, payment confirmation Order processing, notifications, analytics

API Versioning & Evolution

As APIs change, clients depend on old contracts. Versioning lets you evolve APIs without breaking clients.

Strategy Example Pros Cons
Backward Compatibility Add optional fields; never remove No versioning overhead Limited flexibility
URL Path Versioning /api/v1/ vs /api/v2/ Explicit; easy to route Duplication; operational overhead
Deprecation Headers Deprecation: true, Sunset: Date Standards-based; gives clients notice Clients must read headers

Best practice: Default to backward compatibility (add optional fields). Only version when you must break clients.

Deep Dive: API Versioning & Evolution — Backward-compatible changes, deprecation strategies, multi-version support, monitoring version usage


Configuration Management

Configuration (DB URLs, API keys, feature flags) must be separate from code.

Aspect Best Practice
Secrets External secrets manager (AWS Secrets Manager, Vault); never in Git
Non-secret config Environment variables or Spring Cloud Config Server
Feature flags External service (LaunchDarkly, Split.io) for gradual rollout
Environment-specific Profiles: application.yml, application-prod.yml, application-dev.yml

Deep Dive: Configuration Management — Spring Cloud Config, environment profiles, secrets managers, feature flags