Bird
Raised Fist0

GraphQL vs REST - Trade-offs for Different Query Patterns

HLDmediumInterview freq: common
Choose your preparation mode4 modes available
🎯
GraphQL vs REST - Trade-offs for Different Query Patterns
45 min · senior
senior

You are designing the API layer for a 50M DAU social media startup that requires flexible data fetching patterns. The system must support complex nested queries, efficient caching, and maintain P99 latency under 200ms. Data must be encrypted in transit and at rest. Offline delivery and partial data sync are business priorities.

  • End-to-end encryption required for all API traffic
  • Support offline data delivery with partial sync
  • P99 API latency must be under 200ms at peak load
  • Support complex nested queries with variable data shapes
  • Efficient caching to reduce backend load
  • Graceful degradation for clients with limited bandwidth
📋
Guided Steps
1/5
Step 1
Choosing API style for flexible data fetching
Given the need for complex nested queries and variable data shapes, which API style would you choose and why?
💡 Hint
Consider how GraphQL allows clients to specify exactly what data they want versus REST’s fixed endpoints.
Choose GraphQL with Apollo Server for flexible nested queries and precise data fetching, enabling clients to request only needed fields and reduce over-fetching.
Mid: Names GraphQL and Apollo Server. Senior: Explains how GraphQL’s query language reduces payload size and backend load by avoiding multiple REST calls and over-fetching.
⚠️Common Wrong Answer
Use REST with many endpoints for nested data - leads to multiple round-trips and over-fetching, increasing latency and backend load.
Step 2
Handling caching and CDN integration
How would you implement caching for your chosen API style to meet P99 < 200ms latency and reduce backend load?
💡 Hint
Think about HTTP caching headers for REST and persisted queries or persisted cache keys for GraphQL.
Use CDN edge caching with Fastly for REST endpoints with Cache-Control headers; for GraphQL, implement persisted queries with Apollo Engine’s automatic persisted queries and CDN caching of query hashes.
Mid: Mentions CDN caching. Senior: Explains how persisted queries reduce cache key variability in GraphQL, enabling CDN caching similar to REST’s fixed URLs.
⚠️Common Wrong Answer
Ignore caching for GraphQL queries - leads to cache misses due to dynamic query shapes, increasing backend load and latency.
Step 3
Supporting offline delivery and partial sync
How would your API design support offline clients that need partial data sync and conflict resolution?
💡 Hint
Consider how REST and GraphQL handle incremental updates and client-driven sync strategies.
Implement GraphQL subscriptions with Apollo Client’s cache and delta sync support, combined with client-side normalized cache for offline mode; REST clients require custom endpoints and complex sync logic.
Mid: Mentions offline caching. Senior: Details how GraphQL subscriptions and normalized cache enable efficient partial sync and conflict resolution, reducing client complexity.
⚠️Common Wrong Answer
Use REST polling for offline sync - causes excessive network usage and poor user experience under limited bandwidth.
Step 4
Ensuring encryption and security compliance
How do you ensure end-to-end encryption and compliance with data security requirements in your API design?
💡 Hint
Think about TLS, field-level encryption, and authentication mechanisms.
Use TLS 1.3 for transport encryption, implement field-level encryption with AWS KMS for sensitive data in GraphQL resolvers, and OAuth 2.0 with JWT tokens for authentication and authorization.
Mid: Names TLS and OAuth. Senior: Explains field-level encryption in resolvers to protect sensitive data at rest and in transit, and token scopes for fine-grained access control.
⚠️Common Wrong Answer
Rely only on TLS without field-level encryption - risks data exposure if backend is compromised.
Step 5
Designing core API endpoints
Sketch 3 core endpoints for your API design supporting typical query patterns, including nested fetch, partial sync, and acknowledgments.
💡 Hint
For GraphQL, think query, mutation, and subscription; for REST, think resource GET, PATCH, and webhook or ACK endpoint.
GraphQL endpoints: (1) POST /graphql for queries and mutations, (2) WebSocket /subscriptions for real-time updates, (3) Mutation for client ACKs; REST endpoints: (1) GET /user/{id} with embedded resources, (2) PATCH /user/{id} for partial updates, (3) POST /ack for delivery confirmations.
Mid: Lists endpoints. Senior: Explains how each endpoint supports efficient data fetching, sync, and acknowledgments with minimal latency and bandwidth.
⚠️Common Wrong Answer
Design REST endpoints without support for partial updates or real-time subscriptions - leads to inefficient sync and poor UX.
🔌
API Design Challenge
Sketch 3 core API endpoints comparing GraphQL and REST approaches for common query patterns.
  • How does the client request nested or related data in each approach?
  • How does the client synchronize partial updates or offline changes?
  • How does the client acknowledge receipt or errors in data delivery?
📊
Scoring Rubric
▼ Show
Must Have - 60%
  • Clear explanation of GraphQL vs REST trade-offs for nested queries and over-fetching
  • Specific caching strategy naming Fastly CDN and Apollo persisted queries
  • Offline delivery support with GraphQL subscriptions and normalized cache
  • Security design with TLS 1.3 and field-level encryption using AWS KMS
  • API endpoints designed for query, mutation, subscription or REST GET, PATCH, POST
Good to Have - 30%
  • Discussion of latency impact of multiple REST calls vs single GraphQL query
  • Explanation of OAuth 2.0 JWT token scopes for fine-grained access control
  • Consideration of bandwidth constraints and graceful degradation
  • Mention of Apollo Engine for persisted queries and performance monitoring
Bonus - 10%
  • Insights on how persisted queries improve CDN cache hit ratio for GraphQL
  • Trade-offs of WebSocket subscriptions vs REST webhooks for real-time updates
Using REST with many nested endpoints causes multiple round-trips and high latency under 50M DAU load, leading to poor user experience and backend overload
Ignoring caching for GraphQL queries leads to cache misses due to dynamic query shapes, increasing backend load and latency
Using HTTP polling for offline sync causes excessive network usage and poor user experience under limited bandwidth, risking client battery drain and network congestion
✅
Model Answer
▼ Reveal

This design challenge compares GraphQL and REST trade-offs for a high-scale social media API requiring flexible nested queries, efficient caching, offline support, and strong security. GraphQL with Apollo Server is preferred for its precise data fetching and reduced over-fetching. Caching strategies leverage Fastly CDN and Apollo Engine persisted queries to meet latency targets. Offline delivery is supported via GraphQL subscriptions and normalized client cache. Security is ensured with TLS 1.3, AWS KMS field-level encryption, and OAuth 2.0 JWT tokens.

  • Use GraphQL with Apollo Server to enable flexible nested queries and reduce over-fetching compared to REST fixed endpoints
  • Implement CDN edge caching with Fastly using Cache-Control headers for REST and persisted queries with Apollo Engine for GraphQL to reduce backend load and meet P99 latency < 200ms
  • Support offline delivery and partial sync using GraphQL subscriptions and Apollo Client’s normalized cache to efficiently handle incremental updates and conflict resolution
  • Ensure end-to-end encryption with TLS 1.3 for transport and AWS KMS for field-level encryption within GraphQL resolvers to protect sensitive data at rest and in transit
  • Use OAuth 2.0 with JWT tokens including token scopes for fine-grained access control and secure API access
  • Design core API endpoints as follows: GraphQL POST /graphql for queries and mutations, WebSocket /subscriptions for real-time updates, mutation for client acknowledgments; REST GET /user/{id} with embedded resources, PATCH /user/{id} for partial updates, POST /ack for delivery confirmations
  • GraphQL with Apollo Server enables flexible nested queries reducing over-fetching and multiple round-trips
  • Fastly CDN edge caching with Cache-Control headers for REST and persisted queries for GraphQL reduces backend load and meets P99 latency
  • Apollo Client normalized cache and GraphQL subscriptions support offline delivery and partial sync with conflict resolution
  • TLS 1.3 for transport encryption combined with AWS KMS field-level encryption in GraphQL resolvers ensures data security compliance
  • OAuth 2.0 with JWT tokens provides fine-grained authentication and authorization for API access
  • REST endpoints require multiple fixed resource URLs causing over-fetching and higher latency compared to GraphQL’s single flexible endpoint
  • Persisted queries in Apollo Engine reduce cache key variability enabling CDN caching for GraphQL
  • WebSocket-based GraphQL subscriptions provide real-time updates with lower latency than REST polling or webhooks

Practice

(1/5)
1. In a system trace, at Step 3 the Storage Estimator component calculates daily storage needs. If the average object size is 2MB and the system expects 500K new objects daily, what is the storage estimate at Step 3?
easy
A. Cannot estimate without knowing retention period
B. 1TB per day, calculated as 500K objects x 2MB each
C. 2TB per day, assuming 4MB average object size instead
D. 500GB per day, assuming 1MB average object size instead

Solution

  1. Step 1: Calculate daily storage

    Multiply 500,000 objects by 2MB each = 1,000,000 MB = 1TB per day.
  2. Step 2: Eliminate other options

    500GB per day, assuming 1MB average object size instead uses wrong object size; 2TB per day, assuming 4MB average object size instead doubles size incorrectly; Cannot estimate without knowing retention period ignores that retention affects total storage, not daily estimate.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    500K x 2MB = 1TB daily storage [check]
Hint: Daily storage = object count x average size [check]
Common Mistakes:
2. In a system using Zookeeper for leader election, at step 4 in the request trace, the follower node receives a notification that the leader's ephemeral node has disappeared. What state change does the follower node perform at this step?
easy
A. The follower node attempts to create a new ephemeral node to become leader
B. The follower node restarts its local cache without leader election
C. The follower node ignores the event and continues as follower
D. The follower node immediately assumes leadership without coordination

Solution

  1. Step 1: Understand Zookeeper ephemeral node disappearance

    Leader's ephemeral node disappearance signals leader failure.
  2. Step 2: Follower reaction

    Follower tries to create ephemeral node to become new leader; immediate assumption without coordination risks split-brain.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Follower creates ephemeral node -> attempts leadership [check]
Hint: Ephemeral node gone -> followers try to create leader node [check]
Common Mistakes:
3. Without the message queue (Kafka) in the architecture, what exactly breaks when Alice sends a message to Bob during a partial regional outage?
medium
A. Messages are buffered locally on Alice's client until Bob reconnects
B. Alice's message is immediately delivered but Bob's client shows duplicate messages
C. Alice's send blocks waiting for Bob's server response; if Bob's server crashes, the message is lost with no retry
D. The system automatically retries sending messages indefinitely without blocking

Solution

  1. Step 1: Understand Kafka's role in decoupling

    Kafka buffers messages asynchronously, preventing blocking and enabling retries during outages.
  2. Step 2: Analyze failure without Kafka

    Without Kafka, synchronous calls block sender until receiver responds; if receiver crashes, message is lost with no retry (B). However, buffering on client (C) is incorrect as buffering is server-side.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    No Kafka -> synchronous send blocks and message loss on receiver crash [check]
Hint: No Kafka -> send blocks, no retry, message lost on crash [check]
Common Mistakes:
4. At 10x scale, which component in a TCP-based chat system is most likely to fail first and why?
hard
A. The chat servers, because maintaining many TCP connections consumes memory and CPU per connection
B. The database, because increased writes cause locking and slow queries
C. The load balancer, because it cannot distribute TCP connections evenly
D. The network switches, because TCP traffic overwhelms routing tables

Solution

  1. Step 1: Identify stateful components at scale

    Chat servers maintain stateful TCP connections, each consuming resources like memory and CPU.
  2. Step 2: Analyze scaling impact

    At 10x scale, the number of concurrent TCP connections overwhelms server resources, causing failures before database or network components.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Stateful TCP connections -> chat servers bottleneck first [check]
Hint: Stateful TCP connections -> chat servers bottleneck first [check]
Common Mistakes:
5. At 10x scale, which component is most likely to fail first due to the exact lookup requirement, and why?
hard
A. The backend database, because it cannot handle the increased exact lookup queries without Bloom filter filtering
B. The network layer, because increased traffic from exact lookups saturates bandwidth
C. The Bloom filter component, because its false positive rate grows linearly with scale, causing excessive backend queries
D. The cache layer, because it cannot store all keys for exact lookups at 10x scale

Solution

  1. Step 1: Understand Bloom filter scaling behavior

    Bloom filter false positive rate increases with scale unless filter size grows proportionally, causing more backend queries.
  2. Step 2: Analyze component failure likelihood

    Backend (A) fails eventually but Bloom filter inefficiency causes overload first. Network (C) and cache (D) are bottlenecks but secondary to Bloom filter false positive explosion.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Bloom filter false positives grow with scale, triggering backend overload first [check]
Hint: Bloom filter false positives grow with scale, overload backend first [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard