0% found this document useful (0 votes)
2 views38 pages

API Design Principles

The document outlines key API design principles, emphasizing consistency, resource-oriented design, proper HTTP status codes, and security measures. It contrasts REST and GraphQL architectures, highlighting their respective strengths and weaknesses in terms of data fetching, performance, and use cases. Additionally, it discusses the application of these principles in microservices architecture, detailing how REST and GraphQL can be implemented effectively.

Uploaded by

vinay
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views38 pages

API Design Principles

The document outlines key API design principles, emphasizing consistency, resource-oriented design, proper HTTP status codes, and security measures. It contrasts REST and GraphQL architectures, highlighting their respective strengths and weaknesses in terms of data fetching, performance, and use cases. Additionally, it discusses the application of these principles in microservices architecture, detailing how REST and GraphQL can be implemented effectively.

Uploaded by

vinay
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

1

API Design Principles are guidelines that help you build APIs that are scalable,
maintainable, secure, and easy to use. Since you’re preparing for system design and
AWS-style discussions, I’ll explain this in an interview-ready structured format.

Consistency

Consistency makes APIs predictable.

✔ Use consistent naming conventions

• Use nouns, not verbs


/getUsers
/users

• Use plural resource names


/orders
/customers/123/orders

✔ Standard HTTP methods

• GET → Fetch data


• POST → Create
• PUT → Full update
• PATCH → Partial update
• DELETE → Remove
Consistency reduces developer confusion.

Resource-Oriented Design (RESTful Thinking)

Design APIs around resources, not actions.


Example:
/orders
/orders/{orderId}
/orders/{orderId}/items
Think in terms of:
• Entities (User, Order, Product)
• Relationships
• Hierarchies

Proper HTTP Status Codes


2

Return meaningful responses.

Scenario Status Code

Success 200 OK

Created 201 Created

No Content 204

Bad Request 400

Unauthorized 401

Forbidden 403

Not Found 404

Server Error 500

Interview Tip: Don’t always return 200. It’s a common mistake.

Versioning

APIs evolve. Never break clients.


Common strategies:
• URI versioning → /v1/orders
• Header versioning
• Query param versioning
Best practice for interviews:
/api/v1/orders

Statelessness

Each request should contain everything needed.

✔ No server-side session storage


✔ Use JWT or tokens
✔ Supports horizontal scaling

This is critical in microservices architecture.

Pagination, Filtering, Sorting

Avoid returning huge datasets.


Pagination
3

GET /orders?page=1&limit=20
Filtering
GET /orders?status=shipped
Sorting
GET /orders?sort=createdAt_desc
Makes API scalable.

Idempotency

Important for distributed systems.


• GET, PUT, DELETE → Idempotent
• POST → Not naturally idempotent
To make POST safe:
• Use Idempotency-Key header
• Prevent duplicate payments/orders
Very important for payment APIs.

Security First

✔ HTTPS always

✔ Authentication (JWT, OAuth2)

✔ Authorization (RBAC/ABAC)

✔ Rate Limiting

✔ Input Validation

✔ Encryption for sensitive data

In AWS:
• API Gateway + IAM
• Cognito
• WAF

Clear Error Handling

Provide structured error responses.


Example:
4

{
"errorCode": "ORDER_NOT_FOUND",
"message": "The order with ID 123 does not exist",
"timestamp": "2026-02-12T10:00:00Z"
}
Never expose:
• Stack traces
• Internal DB errors

Documentation

An API without documentation is useless.


Use:
• OpenAPI (Swagger)
• API contracts
• Example requests/responses
Good docs = developer adoption.

Backward Compatibility

Never remove fields suddenly.


Instead:
• Deprecate
• Announce migration window
• Maintain old version

Performance & Efficiency

✔ Compression (gzip)
✔ Caching (ETag, Cache-Control)
✔ Minimize payload
✔ Async processing when needed

Example:
• Use 202 Accepted for async jobs.
5

Observability

Production-ready APIs need:


• Logging
• Metrics
• Tracing
• Correlation IDs
Especially important in microservices.

Interview Summary (30-Second Answer)

If asked:
“What are key API design principles?”
You can say:
A well-designed API should be resource-oriented, consistent, stateless, properly versioned,
secure, idempotent where required, and should use correct HTTP status codes. It must
support pagination, filtering, and provide structured error responses. Additionally, it should be
backward-compatible, observable, and well documented for maintainability and scalability.
2222222222************************
Here’s a clear, interview-ready REST vs GraphQL design comparison — structured for
system design discussions.

Core Philosophy

REST GraphQL

Resource-based architecture Query-based architecture

Multiple endpoints Single endpoint

Fixed data structure Client defines response shape

REST: Server decides the data structure.


GraphQL: Client decides the data structure.

Endpoint Design

REST
GET /users
GET /users/123
GET /users/123/orders
6

Each resource has its own endpoint.


GraphQL
POST /graphql
Single endpoint. Client sends query:
query {
user(id: "123") {
name
orders {
id
amount
}
}
}

Overfetching vs Underfetching

REST Problem
If you call:
GET /users/123
You may get:
• id
• name
• email
• address
• createdAt
• metadata
But maybe you only needed name.
Or you may need:
• user data
• user orders
Which requires:
GET /users/123
GET /users/123/orders
7

→ Multiple calls (underfetching).

GraphQL Advantage
You ask exactly what you need:
query {
user(id: "123") {
name
orders {
id
}
}
}

✔ No overfetching
✔ No multiple network calls

Performance Considerations

Aspect REST GraphQL

Caching Easy (HTTP caching, CDN) Harder (POST-based queries)

Network calls Multiple calls possible Single call

Payload size Fixed response Flexible & optimized

Server complexity Simple More complex

Key Insight:
REST is easier to cache at CDN level.
GraphQL requires custom caching strategies.

Versioning

REST
Common:
/api/v1/users
/api/v2/users
Version in URL.
8

GraphQL
Typically:
• No versioning
• Add new fields
• Deprecate old fields
GraphQL evolves without breaking clients.

Error Handling

REST
Uses HTTP status codes:
• 200
• 400
• 404
• 500

GraphQL
Usually returns:
200 OK
With:
{
"data": {},
"errors": []
}
Errors handled in response body.

Learning Curve

REST GraphQL

Easy to start Steeper learning curve

Simple mental model Requires schema design

Widely adopted Growing adoption


9

When to Use REST

✔ Simple CRUD applications


✔ Public APIs
✔ Microservices communication
✔ Systems needing strong HTTP caching
✔ Server-to-server communication

Example:
• Payment processing API
• Order management backend
• Internal AWS microservices

When to Use GraphQL

✔ Mobile applications (avoid multiple calls)


✔ Complex UI with dynamic data needs
✔ Frontend-heavy applications
✔ When frontend teams need flexibility

Example:
• Social media app
• E-commerce frontend with dynamic UI
• Dashboard apps

System Design Perspective

REST works best when:


• System is microservice-based
• Resources are well defined
• Simpler infrastructure
• Need API Gateway + CDN caching
GraphQL works best when:
• Many related resources
• Client-specific data views
• Need aggregation layer (BFF pattern)
• Reducing round trips is critical
Often used as:
Client → GraphQL Layer → Microservices (REST)
10

GraphQL acts as an aggregation layer.

Trade-Off Summary

Dimension REST GraphQL

Simplicity High Medium

Flexibility Medium High

Caching Native HTTP Custom

Tooling Mature Mature but complex

Backend load Predictable Can be heavy

Schema contract Informal Strongly typed

Interview-Ready 45-Second Answer

If interviewer asks:
“When would you choose REST over GraphQL?”
You can say:
REST is ideal when you have well-defined resources, need strong HTTP semantics and
caching, and want simplicity in backend implementation. GraphQL is better when frontend
applications require flexible data fetching, need to avoid overfetching or multiple round trips,
and when building aggregation layers over multiple microservices. In large-scale systems,
GraphQL often acts as a BFF layer on top of REST microservices.
3333333333333333333333333333333333333333333333333333333
interview-ready REST vs GraphQL design comparison — structured for system design
discussions.

Core Philosophy

REST GraphQL

Resource-based architecture Query-based architecture

Multiple endpoints Single endpoint

Fixed data structure Client defines response shape

REST: Server decides the data structure.


GraphQL: Client decides the data structure.
11

Endpoint Design

REST
GET /users
GET /users/123
GET /users/123/orders
Each resource has its own endpoint.
GraphQL
POST /graphql
Single endpoint. Client sends query:
query {
user(id: "123") {
name
orders {
id
amount
}
}
}

Overfetching vs Underfetching

REST Problem
If you call:
GET /users/123
You may get:
• id
• name
• email
• address
• createdAt
• metadata
But maybe you only needed name.
Or you may need:
12

• user data
• user orders
Which requires:
GET /users/123
GET /users/123/orders
→ Multiple calls (underfetching).

GraphQL Advantage
You ask exactly what you need:
query {
user(id: "123") {
name
orders {
id
}
}
}

✔ No overfetching
✔ No multiple network calls

Performance Considerations

Aspect REST GraphQL

Caching Easy (HTTP caching, CDN) Harder (POST-based queries)

Network calls Multiple calls possible Single call

Payload size Fixed response Flexible & optimized

Server complexity Simple More complex

Key Insight:
REST is easier to cache at CDN level.
GraphQL requires custom caching strategies.

Versioning

REST
13

Common:
/api/v1/users
/api/v2/users
Version in URL.

GraphQL
Typically:
• No versioning
• Add new fields
• Deprecate old fields
GraphQL evolves without breaking clients.

Error Handling

REST
Uses HTTP status codes:
• 200
• 400
• 404
• 500

GraphQL
Usually returns:
200 OK
With:
{
"data": {},
"errors": []
}
Errors handled in response body.

Learning Curve
14

REST GraphQL

Easy to start Steeper learning curve

Simple mental model Requires schema design

Widely adopted Growing adoption

When to Use REST

✔ Simple CRUD applications


✔ Public APIs
✔ Microservices communication
✔ Systems needing strong HTTP caching
✔ Server-to-server communication

Example:
• Payment processing API
• Order management backend
• Internal AWS microservices

When to Use GraphQL

✔ Mobile applications (avoid multiple calls)


✔ Complex UI with dynamic data needs
✔ Frontend-heavy applications
✔ When frontend teams need flexibility

Example:
• Social media app
• E-commerce frontend with dynamic UI
• Dashboard apps

System Design Perspective

REST works best when:


• System is microservice-based
• Resources are well defined
• Simpler infrastructure
• Need API Gateway + CDN caching
GraphQL works best when:
15

• Many related resources


• Client-specific data views
• Need aggregation layer (BFF pattern)
• Reducing round trips is critical
Often used as:
Client → GraphQL Layer → Microservices (REST)
GraphQL acts as an aggregation layer.

Trade-Off Summary

Dimension REST GraphQL

Simplicity High Medium

Flexibility Medium High

Caching Native HTTP Custom

Tooling Mature Mature but complex

Backend load Predictable Can be heavy

Schema contract Informal Strongly typed

Interview-Ready 45-Second Answer

If interviewer asks:
“When would you choose REST over GraphQL?”
You can say:
REST is ideal when you have well-defined resources, need strong HTTP semantics and
caching, and want simplicity in backend implementation. GraphQL is better when frontend
applications require flexible data fetching, need to avoid overfetching or multiple round trips,
and when building aggregation layers over multiple microservices. In large-scale systems,
GraphQL often acts as a BFF layer on top of REST microservices.

If you'd like next, I can give:

• REST vs GraphQL in microservices architecture

• Performance pitfalls in GraphQL

• Designing a GraphQL API for an e-commerce system

• AWS implementation comparison


16

Tell me which direction you want to go.


REST vs GraphQL in microservices architecture
REST vs GraphQL in microservices architecture
Here’s a system-design level explanation of REST vs GraphQL in a microservices
architecture, structured the way you’d answer in an interview.

Where They Sit in Architecture

REST in Microservices (Most Common Pattern)

Client → API Gateway → Microservice A


→ Microservice B
→ Microservice C
Each microservice:
• Owns its database
• Exposes REST APIs
• Communicates via REST or messaging
Example:
• User Service → /users
• Order Service → /orders
• Payment Service → /payments
This is the classic distributed service model.

GraphQL in Microservices (Aggregation Layer Pattern)

Client → GraphQL Gateway (BFF Layer)



User Service (REST)
Order Service (REST)
Payment Service (REST)
GraphQL acts as:
• A single entry point
• An orchestrator/aggregator
• A Backend-for-Frontend (BFF)
Microservices often still use REST internally.
17

Key Architectural Differences

Aspect REST Microservices GraphQL Microservices

API Exposure Each service exposed One unified endpoint

Client Calls Multiple calls possible Single query

Aggregation Client handles Server handles

Coupling Loosely coupled Slight coupling at GraphQL layer

Caching Easy via HTTP/CDN More complex

Complexity Lower Higher

Data Fetching Scenario (Important for Interviews)

Scenario:
Frontend needs:
• User profile
• User orders
• Payment status

REST Approach

Client makes multiple requests:


GET /users/123
GET /orders?userId=123
GET /payments?userId=123
Problems:
• Multiple round trips
• Client-side stitching
• Overfetching possible

GraphQL Approach

Single query:
query {
user(id: "123") {
18

name
orders {
id
amount
}
payments {
status
}
}
}
GraphQL gateway:
• Calls User service
• Calls Order service
• Calls Payment service
• Merges response

✔ Single client call


✔ Reduced round trips

Service-to-Service Communication

Important distinction:

Even when using GraphQL externally,


Internally, services usually talk via:

• REST
• gRPC
• Async messaging (Kafka/SQS)
GraphQL is typically not used for service-to-service communication.

Scaling Considerations

REST Microservices Scaling


Each service:
• Independently scalable
• Clear ownership
19

• Predictable load
Very cloud-native friendly.

GraphQL Gateway Scaling


GraphQL layer:
• Becomes aggregation bottleneck
• Needs:
o Caching
o Batching (DataLoader pattern)
o Query depth limiting
o Rate limiting
If poorly designed:
• N+1 query problem
• Expensive nested queries
• Heavy DB load

Caching Differences

REST
• HTTP caching
• CDN friendly
• ETags
• Cache-Control headers
Very straightforward.

GraphQL
• Queries are POST-based
• Harder to cache at CDN
• Need:
o Persisted queries
o Custom caching layer
o Response-level caching
20

Organizational Perspective

REST Works Best When:


• Many independent teams
• Services independently deployed
• Backend complexity must remain simple
• Public APIs exposed
Common in:
• Banking systems
• Payment systems
• Enterprise backends

GraphQL Works Best When:


• Frontend-heavy product
• Multiple clients (Web + Mobile)
• Rapid UI iteration
• Need flexible data views
Common in:
• E-commerce
• Social media apps
• SaaS dashboards

Hybrid Pattern (Most Realistic Architecture)

Most companies use:


Client → GraphQL (BFF Layer)

REST Microservices

Databases
This gives:
• Frontend flexibility
• Backend service isolation
• Team independence
21

• Clean domain separation

Drawbacks Comparison

REST Drawbacks
• Overfetching
• Multiple network calls
• Client-side aggregation complexity
GraphQL Drawbacks
• Gateway complexity
• Harder observability
• Harder caching
• Query performance risk
• Increased coupling at aggregation layer

Interview-Ready 60-Second Answer

If interviewer asks:
“How does REST compare to GraphQL in microservices?”
You can say:
In microservices architecture, REST is typically used for service-to-service communication
because it keeps services loosely coupled, independently scalable, and easy to cache using
HTTP semantics. GraphQL is often introduced as a gateway or BFF layer to aggregate data
from multiple REST microservices and provide a flexible interface to frontend clients. REST
simplifies backend ownership and scaling, while GraphQL simplifies client data fetching and
reduces round trips. In large-scale systems, a hybrid model is commonly used, where
GraphQL handles client aggregation and REST powers internal service communication.

44444444444444444444444444444

API Design for Microservices – Interview Answer

If the interviewer asks:


“How do you design APIs for a microservices architecture?”
You can structure your answer like this:

Service Ownership & Domain-Driven Design

First, I design APIs around business domains, not technical layers.


22

• Each microservice owns:


o Its data
o Its business logic
o Its API contract
Example:
• User Service → /users
• Order Service → /orders
• Payment Service → /payments
This ensures:
• Loose coupling
• Independent deployments
• Clear service boundaries

Resource-Oriented REST Design

For microservices, I prefer RESTful APIs internally.


Principles:
• Use nouns, not verbs
/orders
/createOrder

• Standard HTTP methods (GET, POST, PUT, DELETE)


• Proper status codes
Example:
GET /orders/{id}
POST /orders
PATCH /orders/{id}
Consistency is critical when multiple teams build services.

Stateless APIs

Each request must be self-contained.


• No server-side sessions
• Use JWT or OAuth tokens
• Makes horizontal scaling easy
23

This is important in Kubernetes or AWS auto-scaling environments.

API Gateway Pattern

Clients should not directly call individual microservices.


Instead:
Client → API Gateway → Microservices
Gateway handles:
• Authentication
• Rate limiting
• Routing
• Logging
• Throttling
• SSL termination
This keeps services clean and focused.

Inter-Service Communication

For synchronous calls:


• REST or gRPC
For asynchronous communication:
• Kafka / SQS / SNS / event-driven approach
Rule of thumb:
• Use async messaging for decoupling
• Avoid long dependency chains

Versioning & Backward Compatibility

Microservices evolve independently.


Strategies:
• /api/v1/orders
• Additive changes only
• Deprecation policy
Never break existing consumers.
24

Idempotency & Reliability

Important in distributed systems.


• Make PUT & DELETE idempotent
• Use Idempotency-Key for POST (e.g., payments)
• Handle retries safely
Prevents duplicate transactions.

Pagination, Filtering, Sorting

Avoid large payloads:


GET /orders?page=1&limit=20
GET /orders?status=shipped
Prevents performance bottlenecks.

Security Best Practices

• HTTPS everywhere
• Token-based authentication (JWT / OAuth)
• RBAC authorization
• Input validation
• Rate limiting
• API throttling
In AWS:
• API Gateway + Cognito + IAM + WAF

Observability & Monitoring

Microservices require visibility.


Include:
• Correlation IDs
• Structured logging
• Metrics
• Distributed tracing (e.g., X-Ray)
Helps debug cross-service flows.
25

Architecture Summary

A clean microservices API design looks like:


Client

API Gateway

Microservices (REST)

Databases (per service)
Optional:
• Event bus for async communication.

60-Second Interview Summary (High-Impact Answer)

You can conclude with:


When designing APIs for microservices, I focus on domain-driven boundaries so each
service owns its data and API contract. I design resource-oriented, stateless REST APIs with
proper versioning, idempotency, and structured error handling. An API Gateway handles
cross-cutting concerns like authentication and rate limiting. For communication, I prefer
synchronous REST or gRPC where needed and asynchronous messaging for loose
coupling. Finally, I ensure backward compatibility, observability, and scalability as first-class
design principles.
5555555555555555555555555555555555555555555555555555555555555555

🏗 Advanced API Design for Microservices (Senior-Level Answer)

Start With Domain Boundaries (DDD + Bounded Context)

At senior level, you don’t start with endpoints.


You start with:
• Clear bounded contexts
• Data ownership
• Isolation strategy
• Team autonomy
Example domains:
• Identity
• Catalog
• Pricing
26

• Cart
• Order
• Payment
• Inventory
• Fulfillment
• Notifications
Each service:
• Owns its database
• Owns its API contract
• Has independent CI/CD pipeline
Goal:
High cohesion within service, low coupling between services.

API Exposure Strategy

External vs Internal APIs


I separate:

External API Layer (North-South)

• API Gateway
• GraphQL BFF (optional)
• Rate limiting
• Auth
• WAF
• Monetization
• Request validation

Internal Service APIs (East-West)

• REST or gRPC
• Service mesh (mTLS)
• Strict SLAs
• Circuit breakers

API Contract Design Principles

At senior level, you must talk about contracts.


27

API as a Product
• Backward compatibility guaranteed
• Semantic versioning
• Contract-first development (OpenAPI / Protobuf)
• Consumer-driven contracts (CDC testing)
I avoid breaking changes:
• Only additive changes
• Deprecation strategy with sunset headers

Idempotency & Distributed Reliability

Critical in payments and orders.


Example: Order Creation
Instead of:
POST /orders
We enforce:
• Idempotency-Key header
• Retry-safe design
• At-least-once delivery tolerance
Why?
Because in distributed systems:
• Network failures
• Client retries
• Duplicate submissions
• Partial timeouts
Without idempotency → duplicate payments.

Event-Driven API Strategy

Senior-level systems avoid deep synchronous chains.

Bad:
Order → Payment → Inventory → Shipping (sync chain)

✔ Better:

• OrderCreated event
28

• PaymentProcessed event
• InventoryReserved event
• Saga orchestration
Patterns used:
• Saga (orchestration or choreography)
• Outbox pattern
• Event sourcing (optional)
APIs should reflect eventual consistency realities.

Data Ownership & Avoiding Distributed Joins

Common mistake:
Service A calls B calls C to assemble response.
Senior solution:
• API composition layer (BFF)
• Precomputed read models
• CQRS pattern
• Caching layer
Never allow:
Cross-database joins across services.

Scalability Design

Design APIs assuming:


• Millions of users
• Flash sales
• Traffic spikes
Techniques:

Rate Limiting

Protect payment & order APIs.

Bulkheads

Isolate failures (cart failure should not break product browsing).

Circuit Breakers

Prevent cascading failures.


29

Read/Write Separation

Catalog reads cached aggressively.

Pagination + Cursor-based pagination

For large datasets.

Security & Compliance (Senior Depth)

For payment systems:


• PCI compliance
• Encryption at rest & in transit
• Field-level encryption
• Tokenization of card data
• mTLS internally
• Fine-grained authorization (RBAC/ABAC)
• Audit trails
Also:
• Do not expose internal IDs
• Use opaque identifiers (UUID)

Observability & Operational Maturity

At scale, debugging is harder than coding.


Every API must include:
• Correlation ID
• Structured logs
• Metrics (p95, p99 latency)
• Distributed tracing
• Error budget tracking
• SLIs/SLOs
APIs must be observable first-class citizens.

Multi-Region & High Availability

Senior-level thinking includes:


• Active-active setup
30

• Region-based routing
• Idempotency across regions
• Data replication strategy
• Eventual consistency handling
Payment APIs especially must handle region failover without double charging.

Performance & Cost Awareness

I design APIs minimizing:


• Chattiness
• Payload size
• Deep nesting
• N+1 issues
Introduce:
• Response shaping
• Compression
• Async processing (202 Accepted for long tasks)
• CDN caching for public APIs

Evolution Strategy

Large systems survive years.


I plan for:
• Contract testing in CI
• Schema registry for events
• Backward-compatible changes only
• Deprecation workflows
• API lifecycle governance

Failure Modeling (This Impresses Interviewers)

I ask:
What happens if:
• Payment succeeds but inventory fails?
• Order service crashes mid-transaction?
31

• Kafka message is delivered twice?


• Service times out but still processes request?
Senior-level answer:
Design for partial failure, retries, and eventual consistency.

2-Minute Senior-Level Interview Answer

If asked:
“How would you design APIs for a large-scale e-commerce payment system?”
You can say:
At a senior level, I design APIs around domain-driven boundaries ensuring each
microservice owns its data and contract. External APIs are exposed through a gateway or
BFF layer, while internal communication uses REST or gRPC secured via mTLS. I enforce
contract-first development, backward compatibility, and consumer-driven contract testing.
For critical workflows like order and payment processing, I ensure idempotency and
implement Saga patterns to handle distributed consistency. I avoid synchronous call chains
by using event-driven communication and the Outbox pattern. Security, observability, rate
limiting, and circuit breakers are built in from day one. Finally, I design for multi-region
resilience, failure tolerance, and operational maturity, ensuring the system remains scalable,
evolvable, and compliant over time.
666666666666666666666666666666666666666666666666666

AWS-Focused Microservices API Design (Senior-Level)

When designing APIs for microservices on AWS, I focus on:


1. Scalability
2. Resilience
3. Security
4. Loose coupling
5. Observability
6. Cost optimization
7. Evolution over time
Let’s walk through it layer by layer.

High-Level Architecture on AWS

Typical AWS microservices API architecture:


Client (Web/Mobile)
|
32

Amazon CloudFront
|
Amazon API Gateway
|
VPC (Private Subnets)
|
┌───────────────┬───────────────┬───────────────┐
| Order Service | Payment Svc | Inventory Svc |
| (ECS/Lambda) | (ECS/Lambda) | (ECS/Lambda) |
└───────────────┴───────────────┴───────────────┘
|
RDS / DynamoDB
|
EventBridge / SNS / SQS

API Gateway Design Strategy

Why API Gateway?


It provides:
• Centralized entry point
• Authentication & authorization
• Rate limiting
• Request validation
• Throttling
• Caching
• WAF integration
Production Setup:
• Edge-optimized API Gateway for global APIs
• Private API Gateway for internal services
• Integrated with:
o Lambda
o ECS via ALB
o Step Functions
33

Best Practice:
• Keep it lightweight — no business logic inside API Gateway.
• Use it for policy enforcement only.

Authentication & Authorization (AWS Native)

For public APIs:


• Amazon Cognito (OIDC + OAuth2)
• JWT-based authorization
For service-to-service:
• IAM roles
• mTLS via App Mesh (optional)
• AWS STS temporary credentials
Fine-Grained Access:
• API Gateway authorizers
• IAM policies
• Resource-level permissions
Senior insight:
Always enforce Zero Trust — never assume internal network is trusted.

Compute Layer Choices

Option AWS Lambda (Serverless)

Best for:
• Event-driven APIs
• Variable traffic
• Rapid scaling
Pros:
• Auto-scaling
• No server management
• Cost-efficient for burst traffic
Cons:
• Cold starts
• Long-running tasks limitations
34

Option ECS Fargate

Best for:
• Long-running services
• Heavy workloads
• Predictable performance
Pros:
• Full container control
• No EC2 management
• Better for complex microservices

Option EKS

Best for:
• Large-scale Kubernetes-based ecosystems

API Data Layer Design

DynamoDB (Preferred for Microservices)


• Single-table design per service
• Partition key per access pattern
• Avoid cross-service joins
• Enable auto-scaling
RDS
• Use when:
o Strong relational integrity required
• Prefer:
o Aurora Serverless v2
o Multi-AZ for HA
Golden Rule:
Each microservice owns its own database.

Synchronous vs Asynchronous APIs on AWS

Synchronous (REST via API Gateway)


35

Example:
POST /orders
Order service:
• Validates input
• Writes to DB
• Publishes event

Asynchronous (Event-Driven)
Use:
• EventBridge (preferred for choreography)
• SNS + SQS
• SQS FIFO (when ordering required)
Flow:
OrderCreatedEvent → EventBridge
→ Payment Service
→ Inventory Service
Why EventBridge?
• Built-in schema registry
• Decoupling
• Filtering rules
Senior tip:
Use events for cross-service communication; REST only for client communication.

Idempotency in AWS APIs

Critical for financial or order APIs.


Implementation:
• Client sends Idempotency-Key
• Store key in:
o DynamoDB with TTL
• Use conditional writes
DynamoDB Example:
PutItem with ConditionExpression
36

attribute_not_exists(idempotencyKey)
Prevents:
• Duplicate orders
• Double charges

Distributed Transactions (Saga on AWS)

Avoid 2-phase commit.


Use:
• Step Functions (Orchestration Saga)
OR
• EventBridge (Choreography Saga)
Example Orchestration:
Step Functions flow:
1. Create Order
2. Reserve Inventory
3. Charge Payment
4. If fail → Compensating step
Benefits:
• Visual workflow
• Built-in retries
• Error handling

Observability & Monitoring

Use:
• CloudWatch Logs
• CloudWatch Metrics
• AWS X-Ray (distributed tracing)
• OpenTelemetry
• CloudWatch Alarms
• AWS Distro for OpenTelemetry
Include:
• Correlation IDs
37

• Structured JSON logs


• Custom metrics
Monitor:
• P95 latency
• Error rate
• Throttling rate
• DLQ depth

Throttling & Protection

Use:
• API Gateway throttling
• Usage plans
• AWS WAF
• Shield (DDoS protection)
• Rate limits per API key
Protect downstream:
• SQS buffer
• Circuit breaker (Resilience4j)
• Auto scaling policies

CI/CD & API Governance

Use:
• AWS CodePipeline
• CodeBuild
• CDK / CloudFormation / Terraform
API management best practices:
• OpenAPI stored in repo
• Contract testing
• Canary deployments
• Blue/Green with CodeDeploy
• API version lifecycle
38

Scaling Considerations

Horizontal scaling:
• Lambda concurrency
• ECS auto scaling
• DynamoDB auto scaling
Decoupling:
• SQS buffers to smooth spikes
Multi-region:
• Route53 latency routing
• DynamoDB Global Tables
• Active-active APIs

🏗 Multi-Account Strategy (Enterprise)

Use AWS Organizations:


• Dev Account
• QA Account
• Prod Account
• Shared Services Account
API exposure:
• Cross-account IAM roles
• PrivateLink for internal APIs

Interview-Ready Closing Statement

“In AWS-based microservices API design, I use API Gateway as a secure entry point, deploy
services on Lambda or ECS based on workload characteristics, enforce authentication using
Cognito or IAM, and ensure loose coupling through EventBridge or SQS. Each service owns
its data in DynamoDB or Aurora, and I implement idempotency, saga patterns, structured
observability with X-Ray, and CI/CD via infrastructure as code. The design prioritizes
scalability, security, and failure isolation while maintaining long-term evolvability.”

Common questions

Powered by AI

GraphQL should be recommended over REST in scenarios where the application has complex UI with dynamic data needs, when avoiding multiple network calls is necessary, and when the frontend team requires flexibility in data fetching. This is often the case in mobile applications, social media apps, or any frontend-heavy applications where overfetching of data can be minimized and network efficiency is paramount .

A senior-level API designer might choose event-driven communication over synchronous calls to avoid the pitfalls of long dependency chains, which can lead to delays and increased system fragility if one service fails. Event-driven architecture, using patterns like Saga or event sourcing, allows services to remain loosely coupled and handle failures more gracefully, enabling better scalability, reliability, and performance in distributed systems .

Idempotency ensures that API requests, such as PUT and DELETE, can be performed multiple times without additional effects, which is vital in microservices to handle retries and prevent duplicate transactions. Reliability is further enhanced by employing mechanisms like Idempotency-Key for POST requests and ensuring that microservices can gracefully handle failures and retries, thus maintaining data integrity and system stability .

GraphQL handles API evolution by allowing clients to request specific fields, meaning new fields can be added without affecting existing queries. This makes versioning less necessary compared to REST, where versioning is often managed through URL changes, requiring clients to upgrade explicitly. GraphQL's approach allows for non-breaking changes, thus improving backward compatibility and reducing the need for client updates upon backend changes .

The primary challenges in designing high-availability APIs for multi-region deployment include ensuring consistency across regions, managing idempotency in failover scenarios, and handling data replication. Solutions involve implementing an active-active setup for failover resilience, leveraging region-based routing, and adopting strategies like eventual consistency and data replication techniques to maintain service availability and data integrity across regions .

A BFF pattern acts as an intermediary between the frontend client and backend microservices, using GraphQL as a single entry point for aggregating data from multiple REST services. This pattern provides advantages such as optimizing network usage, simplifying frontend development by reducing the need for multiple API calls, and customizing data responses to meet client-specific needs without affecting backend service implementations .

REST is based on a resource-based architecture with multiple endpoints, while GraphQL uses a query-based architecture with a single endpoint. REST requires the server to decide the data structure, often leading to overfetching or underfetching, requiring multiple network calls to fetch related resources. In contrast, GraphQL allows the client to define the exact shape of the response, thus optimizing data fetching by eliminating overfetching and reducing network calls to a single query .

Observability in API design is crucial for understanding and troubleshooting distributed systems, especially in microservices, where services are independently deployed and scaled. It involves incorporating practices such as structured logging, distributed tracing, and metric collection to monitor API performance, detect issues, and trace transactions across services, ensuring efficient diagnosis and resolution of problems .

REST APIs can leverage native HTTP caching mechanisms and CDN support, making it easier to implement efficient caching strategies. GraphQL, on the other hand, being POST-based, makes caching more complex, requiring custom strategies to handle cache retrieval and invalidation effectively. This difference affects how each API manages request efficiency and performance, with REST generally offering more straightforward caching solutions .

REST APIs contribute to microservices communication by promoting loosely coupled systems where each service exposes its API, allowing services to operate independently. GraphQL, while providing a single entry point, introduces slight coupling at the GraphQL layer by aggregating data from multiple services. This aggregation can lead to increased complexity and tighter coupling between data sources if not managed carefully .

You might also like