Practice/Meta/Design HTTP Resource Loader
Design HTTP Resource Loader
System DesignMust
Problem Statement
You need to design a robust HTTP networking library that runs inside client applications such as mobile apps and web browsers. This library will be the foundation for all network communication, handling everything from quick API calls to multi-gigabyte file downloads. Your design must work reliably across diverse network conditions (WiFi, cellular, offline) and on resource-constrained devices with limited memory, battery, and CPU.
The library should provide a clean API for developers while managing complex concerns internally: connection pooling, request prioritization, automatic retries, progress tracking, background downloads, and HTTP caching. Think of this as building the networking layer that powers apps like Instagram (loading feeds and downloading videos) or Spotify (streaming music with offline support). Your solution must balance developer ergonomics with production-grade reliability and mobile-specific optimizations.
Key Requirements
Functional
- Request Execution -- support all HTTP methods (GET, POST, PUT, DELETE) with custom headers, query parameters, request bodies, and configurable timeouts
- Large File Handling -- enable streaming downloads of multi-gigabyte files with pause/resume capability, background execution, and integrity verification
- Request Management -- provide cancellation, priority queuing, progress callbacks, and retry policies with exponential backoff
- Caching Layer -- implement HTTP caching semantics (ETag, Cache-Control, If-Modified-Since) with disk persistence and configurable policies
- Observability -- expose metrics for latency, success rates, retry counts, and cache hit ratios for debugging and monitoring
Non-Functional
- Scalability -- handle hundreds of concurrent requests per client device without degrading performance or exhausting resources
- Reliability -- achieve 99.9% success rate for requests under normal conditions with automatic retry and fallback mechanisms
- Latency -- complete typical API requests in under 500ms on good networks; optimize connection reuse and DNS resolution
- Consistency -- ensure idempotent operations for retries and prevent duplicate requests for non-idempotent operations
- Resource Efficiency -- minimize memory footprint (under 50MB for active transfers), battery consumption, and cellular data usage
What Interviewers Focus On
Based on real interview experiences, these are the areas interviewers probe most deeply:
1. Request Lifecycle and Scheduling
Understanding how your library manages the complete journey of a request from initiation to completion is critical. Mobile devices have limited concurrent connections (typically 6-8 per host), and naive implementations quickly lead to head-of-line blocking where low-priority requests delay critical UI operations.
Hints to consider:
- Design a priority queue system that allows UI-critical requests (user-initiated actions) to jump ahead of background tasks (prefetching, analytics)
- Implement per-host connection limits to comply with HTTP specifications and prevent socket exhaustion
- Consider how HTTP/2 multiplexing changes the scheduling strategy compared to HTTP/1.1
- Think about request coalescing where multiple identical pending requests can share a single network call
2. Large File Downloads and Resume Capability
Downloading multi-gigabyte files (videos, app updates, podcast episodes) presents unique challenges. Memory constraints mean you cannot buffer entire responses, and unreliable mobile networks require robust resume capabilities to avoid starting over after interruptions.
Hints to consider:
- Use HTTP Range requests (Range: bytes=500-999) to download files in chunks and resume from the last successful byte
- Stream response data directly to disk using temporary files, only promoting to the final location after integrity verification
- Store download metadata (URL, expected size, checksum, completed ranges) in a persistent database for cross-process resume
- Handle partial content responses (206 status) and fall back to full downloads when servers don't support ranges
- Implement chunk-level integrity checks using checksums to detect corruption early rather than after downloading gigabytes
3. Mobile-Specific Optimizations
Mobile environments impose constraints that desktop systems don't face: aggressive power management, metered connections, app suspension, and limited background execution time. Your design must work within these boundaries while maintaining good user experience.
Hints to consider:
- Detect network type (WiFi vs. cellular) and apply different policies: allow large downloads only on WiFi unless user explicitly opts in
- Integrate with platform background task APIs (iOS URLSession background configuration, Android WorkManager) to continue transfers when the app is suspended
- Implement connection pooling with keep-alive to reuse TLS sessions and reduce handshake overhead and battery drain
- Use adaptive timeouts based on observed network quality rather than static values
- Compress request/response bodies automatically and leverage HTTP compression (gzip, brotli) to reduce data transfer
4. Caching Strategy and Offline Support
An effective caching layer dramatically improves performance and user experience by reducing redundant network requests. However, cache invalidation and consistency are notoriously difficult, and mobile devices have limited storage.
Hints to consider:
- Implement a two-tier cache: fast in-memory LRU cache for hot data and larger disk-based cache for persistence
- Respect HTTP cache headers (Cache-Control, Expires, ETag) but allow application-level overrides for specific use cases
- Use conditional requests (If-None-Match, If-Modified-Since) to revalidate stale entries efficiently with 304 responses
- Implement cache size limits with LRU or LFU eviction policies, giving special treatment to user-initiated downloads
- Consider a separate offline mode where the library serves stale cached content when network is unavailable
5. Error Handling and Resilience
Networks fail constantly on mobile devices: tunnels, elevators, airplane mode, congested towers, and flaky WiFi. Your library must handle failures gracefully without overwhelming the backend or frustrating users.
Hints to consider:
- Implement exponential backoff with jitter for retries to avoid thundering herd problems during outages
- Distinguish between retryable errors (timeouts, 500s, network unreachable) and non-retryable errors (400, 401, 404)
- Use circuit breaker patterns to stop retrying failing endpoints temporarily and fail fast
- For non-idempotent operations (POST, PATCH), require explicit idempotency tokens to prevent duplicate transactions
- Respect server retry hints (Retry-After header, 429 rate limit responses) rather than blindly retrying