APIs, Service Communication and IntegrationIntroductionServerless applications and microservices rarely operate as isolated functions. A useful system is assembled from independently deployable components that exchange commands, queries, events, files, and results. The interfaces between those components therefore become architectural boundaries. Poorly designed interfaces create coupling, cascading failures, security weaknesses, and costly migration problems; well-designed interfaces support independent evolution, observability, resilience, and team autonomy. This chapter examines the principal interface styles used in contemporary distributed systems: REST, GraphQL, gRPC, and asynchronous messaging. It then considers the platform capabilities and design disciplines that make these interfaces reliable in production, including API gateways, service discovery, contracts, versioning, circuit breakers, retries, and anti-corruption layers. The emphasis is not on a particular cloud vendor. Instead, the chapter develops transferable design reasoning applicable to managed API gateways, serverless functions, containerized microservices, message brokers, event buses, and service meshes. Learning ObjectivesBy the end of this chapter, a learner should be able to: - Select REST, GraphQL, gRPC, or asynchronous communication for a given integration problem.
- Design resource-oriented, query-oriented, procedure-oriented, and event-oriented interfaces.
- Explain the responsibilities and limitations of an API gateway and service discovery mechanism.
- Apply contract design, compatibility rules, versioning strategies, and schema governance.
- Design safe timeout, retry, circuit-breaker, and idempotency policies.
- Use an anti-corruption layer to protect a domain model from an external or legacy system.
- Evaluate integration designs for reliability, security, observability, cost, and maintainability.
1. Interfaces as Architectural ContractsAn API is more than a URL or method signature. It is a published agreement concerning: - Syntax: paths, methods, message formats, field names, and data types.
- Semantics: what a request means and what a response guarantees.
- Protocol behaviour: status codes, deadlines, retries, ordering, and pagination.
- Non-functional properties: authentication, rate limits, latency expectations, availability, and data protection.
- Evolution rules: which changes remain compatible and how breaking changes are introduced.
A service boundary should expose a capability rather than its internal database structure. For example, an order service may expose “place order” and “retrieve order status,” while concealing whether orders are stored in a relational database, document store, or event log. A useful distinction is between control-plane and data-plane communication. Control-plane interfaces manage configuration, deployment, identity, or routing. Data-plane interfaces carry business traffic. A service registry is primarily control-plane infrastructure, whereas a payment API is a data-plane interface. Synchronous and asynchronous interactionIn synchronous communication, the caller waits for a response during the same interaction. This is straightforward for queries and immediate validation, but it creates temporal coupling: both systems must be reachable at the same time. In asynchronous communication, the sender submits a message or event and does not require the receiver to respond immediately. The receiver may process it later, possibly after a temporary outage. This reduces temporal coupling but introduces eventual consistency, duplicate delivery, ordering, replay, and monitoring concerns. Neither style is universally superior. A user-facing request may synchronously validate an order and asynchronously initiate fulfilment. A single business workflow can therefore use several interface styles. 2. REST InterfacesRepresentational State Transfer (REST) is an architectural style based on resources, representations, uniform interface constraints, and stateless interactions. HTTP APIs commonly described as RESTful normally use: GET to retrieve a representation;POST to create a subordinate resource or trigger an operation;PUT to replace a resource at a known identifier;PATCH to apply a partial modification;DELETE to remove a resource.
A typical resource model might contain: GET /customers/42
GET /customers/42/orders?status=open&page=2
POST /customers/42/orders
PATCH /orders/981
DELETE /orders/981/items/7 The HTTP method and response status should communicate semantics. 200 OK commonly indicates a successful response, 201 Created a newly created resource, 202 Accepted acceptance for asynchronous processing, 204 No Content success without a response body, 400 Bad Request invalid syntax or input, 401 Unauthorized missing or invalid authentication, 403 Forbidden insufficient permission, 404 Not Found an unavailable resource, 409 Conflict a state conflict, 429 Too Many Requests throttling, and 5xx a server-side failure. REST design principlesResource orientation. Model business concepts rather than implementation functions. /orders/981 is generally more stable than /runOrderLookup. Statelessness. Each request should contain the context necessary for processing. Statelessness does not mean that the system has no stored state; it means that the server does not rely on hidden conversational state associated with a particular client session. Consistent representations. JSON is common, but media types should be selected deliberately. Dates, monetary values, identifiers, and nullability must have documented representations. Pagination and filtering. Large collections should not be returned without bounds. Cursor pagination is often more stable than page-number pagination when records are inserted during traversal. A response should communicate the next cursor and any applicable limits. Idempotency. An operation is idempotent when repeating it produces the same intended resource state as performing it once. GET, PUT, and DELETE are defined as idempotent by HTTP semantics, although implementation defects can violate that expectation. POST is not inherently idempotent. For a payment or order submission, an idempotency key can allow a server to recognise safe client retries. Strengths and limitationsREST is broadly interoperable, debuggable with ordinary HTTP tools, and well suited to public APIs and CRUD-like resources. Its weaknesses include over-fetching or under-fetching, limited native support for streaming, and ambiguity when a business action does not map naturally to a resource. REST also does not automatically define a complete schema or behavioural contract; tools such as OpenAPI can provide that discipline. 3. GraphQL InterfacesGraphQL exposes a typed schema through which a client specifies the fields it needs. A query might request a customer and selected order attributes in one operation. The server validates the query against the schema and resolves fields, potentially from several services. GraphQL commonly includes: - Queries for reads;
- Mutations for state-changing operations;
- Subscriptions for selected real-time use cases;
- Types and fields that define the schema;
- Resolvers that obtain or compute field values.
GraphQL is especially useful when many clients require different views of related data, such as web, mobile, and partner applications. It can reduce repeated client-server round trips and avoid forcing every client to accept the same fixed response shape. However, the apparent simplicity of one endpoint can conceal substantial complexity. A query may cause many backend calls, including the “N+1” problem in which one request for a list causes one additional query per item. Batching and caching mechanisms such as data loaders can mitigate this. Query depth, complexity, response size, and resolver time should be controlled to prevent accidental or malicious resource exhaustion. GraphQL schema evolution normally favours additive change. New fields can be added while old fields are deprecated and eventually removed according to a published policy. Changing the meaning or type of an existing field is potentially breaking. Authorization must be applied at field and resolver boundaries where necessary; authenticating the request alone does not prove that the caller may access every returned field. GraphQL is not automatically a microservice architecture. It is often used as an aggregation or experience layer over REST, gRPC, databases, or events. The graph should expose domain capabilities without becoming an uncontrolled mirror of internal schemas. 4. gRPC and Protocol-Oriented CommunicationgRPC is a remote procedure call framework commonly using Protocol Buffers (Protobuf) for interface definitions and HTTP/2 for transport. A service contract declares methods and typed messages; code can then be generated for several programming languages. For example, a contract may define an operation equivalent to GetOrder, accepting an order identifier and returning an order message. gRPC supports unary calls, server streaming, client streaming, and bidirectional streaming. Why use gRPC?gRPC is effective for internal service-to-service communication where strongly typed contracts, compact binary messages, generated clients, deadlines, and streaming are valuable. It can reduce boilerplate and detect many interface errors during compilation or contract validation. Its limitations include weaker browser-native accessibility than HTTP/JSON APIs, greater tooling requirements for casual consumers, and the need to manage generated-code compatibility. A public API may therefore use REST or GraphQL at the edge and gRPC internally. Protobuf evolution requires care. Existing field numbers should not be reused for a different meaning. New fields should generally be optional from the perspective of old consumers, and consumers should tolerate unknown fields. Removing a field is safe only when all relevant consumers have stopped using it and the field number is reserved against accidental reuse. 5. Asynchronous Interfaces and Event-Driven IntegrationAn asynchronous interface communicates through queues, topics, streams, or event buses. A command asks a particular consumer or service to perform work; an event records that something has happened and may have multiple subscribers. Examples include: Command: ReserveInventory { orderId, items }
Event: OrderPlaced { orderId, customerId, occurredAt }Commands are normally directed and may be rejected. Events should describe completed facts and should not require consumers to know the producer’s internal implementation. Delivery semanticsMessaging systems commonly provide: - At-most-once: a message is not redelivered, but loss is possible.
- At-least-once: redelivery is possible, so consumers must tolerate duplicates.
- Effectively-once business processing: achieved through idempotency, deduplication, transactional boundaries, or carefully designed state transitions; it should not be assumed merely because a broker advertises a delivery feature.
A consumer can implement idempotency by storing a processed message identifier with the resulting business state. This record must be managed consistently with the business update; otherwise a crash between the two writes can still cause incorrect behaviour. Ordering, retries, and dead lettersOrdering is usually guaranteed only within a defined scope, such as a partition or message group. If order matters, the partitioning key must preserve the relevant sequence, and consumers must handle late or duplicated messages. Failed messages may be retried with delay and eventually routed to a dead-letter queue. Dead letters are not a substitute for diagnosis: they require alerting, inspection, safe replay, and a decision about whether the underlying defect has been corrected. The transactional outbox pattern addresses a common failure: a service commits a database change but crashes before publishing the corresponding event. The service writes the business change and an outbox record in one database transaction. A relay later publishes the outbox record and marks it delivered. Consumers still need idempotency because publication or acknowledgement can be repeated. 6. API Gateways and Service DiscoveryAn API gateway is an edge component that can provide routing, TLS termination, authentication integration, rate limiting, request transformation, WAF controls, observability, and aggregation. It is not a replacement for service-level authorization or sound domain boundaries. A gateway should remain operationally simple. Excessive business logic creates a central bottleneck and makes independent deployment difficult. Domain-specific orchestration generally belongs in a dedicated application service or backend-for-frontend rather than in generic gateway configuration. Service discovery allows a client or intermediary to locate service instances. In client-side discovery, the client consults a registry and selects an instance. In server-side discovery, a load balancer or proxy consults the registry. Modern platforms may provide discovery through DNS, a control plane, a service mesh, or platform-native service names. Discovery systems must handle stale registrations, health checks, zone or region preference, load distribution, and security identity. A discovered address is not automatically trustworthy; transport encryption and service authentication remain necessary. 7. Contracts, Compatibility, and VersioningA contract should specify request and response schemas, error formats, authentication, limits, side effects, consistency expectations, and examples. OpenAPI is common for HTTP APIs; Protobuf definitions serve a similar role for gRPC; GraphQL schemas define types and operations; event schemas define message evolution rules. Consumer-driven contractsIn a consumer-driven contract approach, consumers express the parts of a provider’s interface they rely upon. Automated provider verification detects incompatible changes before deployment. This complements, rather than replaces, unit, integration, security, and end-to-end tests. Compatibility rulesA change is generally backward compatible when existing consumers continue to function without modification. Examples include adding an optional response field, adding a new endpoint, or adding an event consumer. Potentially breaking changes include removing a field, changing its meaning or type, making an optional input mandatory, changing error semantics, or altering authorization requirements. Compatibility also has direction. A new consumer reading an old provider may require forward compatibility, while an old consumer reading a new provider requires backward compatibility. Schema registries and automated compatibility checks help make these distinctions explicit. Versioning strategiesCommon strategies include: | Strategy | Example | Benefit | Risk |
|---|
| URI versioning | /v2/orders | Visible and simple | Duplicate routes and migration burden | | Header or media type | Accept: application/vnd.example.v2+json | Keeps resource URI stable | Less visible to casual tools | | Query parameter | /orders?version=2 | Easy to introduce | Can become inconsistent | | Additive evolution | One stable schema with deprecation | Reduces parallel versions | Requires strong governance |
Version only when compatibility cannot be maintained. A version is a product and operational commitment: it requires documentation, testing, traffic measurement, deprecation communication, and a removal plan. 8. Resilience: Timeouts, Retries, Circuit Breakers, and IdempotencyDistributed calls fail through delay as well as explicit errors. Every synchronous call should have a deadline. A timeout should be derived from the user or workflow latency budget, downstream service behaviour, and acceptable queueing—not selected arbitrarily. Retries are appropriate for transient failures such as a connection reset or service-unavailable response, but dangerous for validation errors, authorization failures, and non-idempotent operations. Use bounded retries, exponential backoff, and jitter. If the initial delay is d, the backoff multiplier is r, and attempt number is n, an uncapped delay can be represented as: tn = d × rn−1 Here, tn is the delay before attempt n, d and r are positive, and a maximum delay should normally cap the result. Jitter adds controlled randomness so that many clients do not retry simultaneously. Retries consume capacity; a service under stress can therefore be damaged by well-intentioned clients retrying aggressively. A circuit breaker monitors failures or slow calls. In the closed state, calls flow normally. When a failure threshold is reached, it opens and rejects calls quickly. After a cool-down period, it enters half-open, allowing a limited probe. Success closes the circuit; failure opens it again. A breaker should distinguish failures that indicate downstream unavailability from expected business rejections. Bulkheads isolate resources, such as connection pools or concurrency limits, so that one dependency cannot consume all capacity. Load shedding and graceful degradation can preserve critical functions during overload. 9. Anti-Corruption LayersAn anti-corruption layer (ACL) is a translation boundary that prevents an external model from distorting the receiving domain model. It is especially valuable when integrating a legacy system, acquired business, vendor platform, or service with incompatible terminology. Suppose a legacy system calls a customer a “debtor,” represents money as an integer in minor units, and uses status codes A, H, and C. The modern domain may use Customer, a typed Money value, and explicit lifecycle states. An ACL maps requests and responses between these models, translates errors, normalizes units, and isolates protocol details. The ACL can be implemented as an adapter, façade, translator, dedicated integration service, or message-mapping component. It should not silently hide important semantic differences. Mapping failures, unknown codes, and data loss must be observable and governed. The trade-off is additional code and operational complexity. An ACL is justified when the protected domain is strategically important, the external model is unstable or unsuitable, or replacing the dependency is not immediately feasible. It is not a reason to create needless translation layers between two already compatible services. 10. Security, Governance, and ObservabilityAPI security begins with a threat model. Important controls include TLS, strong service identity, authorization based on least privilege, input validation, output filtering, rate limits, secret rotation, audit logging, and protection against replay where appropriate. Authentication identifies a caller; authorization determines what that caller may do. OAuth 2.0 and OpenID Connect are common in user-facing ecosystems, while workload identity, mutual TLS, signed tokens, or cloud-native identity systems may be used between services. Tokens should have limited scope and lifetime, and sensitive data should not be placed casually in logs. Governance includes data residency, retention, privacy rights, consent, regulatory reporting, and contractual obligations. An API that exposes personal data should define purpose, minimization, access controls, deletion behaviour, and auditability. Observability should connect gateway requests, service calls, and asynchronous messages using correlation or trace identifiers. Useful signals include latency distributions, error rates, saturation, retry counts, queue age, dead-letter volume, circuit state, and contract violations. A single average latency can conceal severe tail latency; percentile measurements such as p95 or p99 are usually more informative for user experience. 11. Applied Case: A Serverless Retail Order PlatformThe following is an illustrative case. Background and problemA retailer operates a web shop, mobile application, warehouse system, payment provider, and notification service. The initial design sends every request through a single function that synchronously calls all systems. During promotions, payment delays cause request timeouts, duplicate order attempts, and excessive load on the warehouse API. The warehouse system also uses terminology and status codes that do not match the retailer’s domain. AnalysisThe system has temporal coupling, a large failure radius, and no reliable distinction between an accepted order and a fulfilled order. Retrying the entire function can repeat payment or inventory actions. The legacy warehouse model is leaking into customer-facing responses. Finally, clients receive inconsistent error formats because each function handles errors differently. Approach and solutionAn API gateway exposes a stable REST interface: POST /orders
GET /orders/{orderId}The order service validates the request, records the order with an idempotency key, and returns 202 Accepted when fulfilment is asynchronous. It publishes an OrderPlaced event through an outbox mechanism. Payment and inventory consumers process the event independently and publish success or failure events. The order projection updates the customer-visible status. A backend-for-frontend exposes a GraphQL view for the mobile application, allowing it to request order status, selected delivery information, and payment state without receiving internal fields. Internal service calls use gRPC where typed contracts and deadlines are useful. The warehouse integration is protected by an ACL that maps modern order states to legacy codes and converts legacy errors into domain errors. The gateway enforces authentication, request limits, and a common error envelope. Each downstream call has a deadline. Transient provider failures use bounded exponential backoff with jitter; payment commands use idempotency keys. A circuit breaker prevents repeated calls to an unavailable warehouse endpoint. Dead-letter messages trigger an operational alert and a controlled replay process. OutcomeThe customer receives a prompt acceptance response without waiting for every downstream system. Payment and inventory can recover independently, duplicate requests do not create duplicate orders, and the warehouse vocabulary remains outside the core domain. Operational teams can observe queue age, fulfilment delay, provider failures, and message replay. Learning points- Interface style should follow interaction requirements rather than fashion.
- Asynchronous acceptance requires explicit status modelling and customer communication.
- Idempotency is essential when retries and at-least-once delivery coexist.
- An API gateway centralizes cross-cutting edge concerns but should not become a business monolith.
- An ACL protects domain language and makes replacement of a legacy dependency more feasible.
12. Design Method and Best PracticesA disciplined integration design can follow these steps: - Identify the business capability and owning service.
- Define consumers, trust boundaries, data classification, and latency expectations.
- Choose synchronous or asynchronous interaction based on coupling, user experience, and consistency needs.
- Select REST, GraphQL, gRPC, or messaging according to consumer diversity, typing, streaming, and exposure requirements.
- Specify schemas, semantics, errors, deadlines, side effects, and compatibility rules.
- Decide where authentication, authorization, rate limits, transformation, and aggregation belong.
- Define idempotency, retry, circuit-breaker, bulkhead, and dead-letter behaviour before implementation.
- Add contract tests, observability, threat analysis, and failure-injection tests.
- Document ownership, service-level expectations, deprecation policy, and operational runbooks.
- Review the design for unnecessary coupling, data duplication, hidden transactions, and uncontrolled gateway logic.
A mature architecture also tests partial failure deliberately. Simulate timeouts, duplicate messages, delayed events, unavailable registries, malformed payloads, expired credentials, and incompatible schema changes. Reliability is a property demonstrated under failure, not merely inferred from a successful normal-path test. Chapter SummaryAPIs define more than message syntax: they establish semantic, operational, security, and evolution contracts. REST provides broadly accessible resource-oriented HTTP interfaces; GraphQL provides typed, client-shaped queries; gRPC supports efficient, strongly typed internal procedures and streaming; asynchronous messaging reduces temporal coupling while requiring explicit handling of duplicates, ordering, replay, and eventual consistency. API gateways are useful for edge concerns such as routing, authentication integration, throttling, and observability, while service discovery locates healthy service instances. Contracts, consumer-driven testing, compatibility rules, and deliberate versioning support independent evolution. Timeouts, bounded retries with backoff and jitter, circuit breakers, bulkheads, and idempotency reduce failure propagation. Anti-corruption layers isolate incompatible external models from a domain’s language and rules. Secure identity, least privilege, privacy governance, traceability, and failure testing are essential to production integration. Key TermsAPI: A contract through which software components communicate. REST: An architectural style using resources and a uniform interface, commonly over HTTP. GraphQL: A typed query language and runtime in which clients request selected fields. gRPC: A remote procedure call framework commonly using Protobuf and HTTP/2. Protobuf: A compact schema and serialization format used frequently with gRPC. Synchronous communication: Interaction in which the caller waits for a response. Asynchronous communication: Interaction in which work may be processed after the sender continues. Command: A message requesting a particular action. Event: A record that something has occurred. API gateway: An edge component providing routing and cross-cutting controls. Service discovery: The process of locating service instances. Contract: A documented agreement covering interface structure and behaviour. Idempotency: The property that repetition has the same intended effect as one execution. Circuit breaker: A resilience mechanism that temporarily blocks calls to a failing dependency. Exponential backoff: Increasing retry delays according to a multiplier. Jitter: Deliberate variation added to timing to avoid synchronized retries. Dead-letter queue: A destination for messages that cannot be successfully processed. Anti-corruption layer: A translation boundary protecting one domain from another model. Eventual consistency: A condition in which replicas or services converge after a delay. Review QuestionsShort Answer Questions- What is the difference between a command and an event?
- Why is idempotency important when retries are used?
- State two responsibilities commonly assigned to an API gateway.
- What problem does an anti-corruption layer solve?
- Why should a circuit breaker have a half-open state?
Long Answer Questions- Compare REST, GraphQL, and gRPC in terms of consumers, contracts, performance, evolution, and appropriate use cases.
- Explain how an asynchronous order workflow can improve resilience while introducing eventual consistency.
- Discuss backward-compatible and breaking API changes, and propose a versioning policy for a public API.
- Describe a complete retry and timeout policy for a service calling a payment provider.
- Explain the role of service discovery, health checking, identity, and load balancing in a microservices platform.
Analytical / Application Questions- A mobile client needs three different views of customer data, while internal services require strongly typed streaming and deadlines. Design an interface architecture and justify where GraphQL and gRPC should be used.
- A message consumer updates inventory and occasionally receives the same event twice. Design an idempotency and recovery strategy, including storage, acknowledgement, and dead-letter handling.
- A legacy warehouse API returns opaque status codes and has frequent timeouts. Propose an integration architecture using an anti-corruption layer, circuit breaker, asynchronous processing, observability, and a migration plan.
Multiple Choice Questions with AnswersQuestion 1Which interface style allows a client to specify the fields it wants returned? A. REST B. GraphQL C. gRPC D. SMTP Correct Answer: B. GraphQL Question 2Which HTTP status most appropriately indicates that an asynchronous request has been accepted for processing? A. 201 Created B. 202 Accepted C. 204 No Content D. 304 Not Modified Correct Answer: B. 202 Accepted Question 3What is the primary purpose of an idempotency key for an order submission? A. To encrypt the request body B. To select a service instance C. To prevent repeated retries from creating duplicate effects D. To increase message size Correct Answer: C. To prevent repeated retries from creating duplicate effects Question 4Which mechanism temporarily rejects calls to a failing dependency? A. Circuit breaker B. Schema registry C. API version D. Cursor pagination Correct Answer: A. Circuit breaker Question 5In an event-driven system, what is a dead-letter queue mainly used for? A. Caching successful responses B. Holding messages that repeatedly fail processing C. Registering service instances D. Storing API documentation Correct Answer: B. Holding messages that repeatedly fail processing Question 6Which change is generally backward compatible for an API response? A. Removing a field used by clients B. Changing a field from a number to an object C. Adding an optional response field D. Changing the meaning of an existing status Correct Answer: C. Adding an optional response field Question 7What does an anti-corruption layer primarily do? A. Replaces all authentication mechanisms B. Translates and isolates incompatible domain models C. Guarantees exactly-once delivery D. Eliminates the need for monitoring Correct Answer: B. Translates and isolates incompatible domain models Question 8Why is jitter added to retry backoff? A. To make payloads smaller B. To synchronize all clients C. To reduce synchronized retry bursts D. To remove the need for timeouts Correct Answer: C. To reduce synchronized retry bursts Question 9Which communication property is most associated with asynchronous messaging? A. Temporal decoupling B. Guaranteed immediate response C. No need for duplicate handling D. Automatic strong consistency Correct Answer: A. Temporal decoupling Question 10Which technology is commonly associated with strongly typed service definitions and generated clients? A. gRPC with Protocol Buffers B. Plain HTML C. DNS alone D. CSV files Correct Answer: A. gRPC with Protocol Buffers
|