Robust Networking, REST, And Concurrency Control
Asked of: Software Engineer
Last updated

What's being tested
This area tests whether a Software Engineer can build APIs and networked components that behave correctly under retries, partial failures, concurrent writes, malformed input, and changing scale. Apple interviewers are probing for practical distributed-systems judgment: not just “can you write the happy path,” but can you preserve correctness when clients disconnect, requests are duplicated, two users update the same resource, or a backend times out after committing. Strong answers combine clean API design, explicit failure semantics, bounded resource usage, and testability.
Core knowledge
-
TCP stream framing is mandatory because sockets deliver bytes, not messages. A robust reader needs a delimiter protocol, fixed-length header, or length-prefixed frame; it must handle partial reads, coalesced messages, EOF, malformed lengths, and maximum frame sizes.
-
Internal buffering separates network reads from message parsing. Keep a mutable byte buffer, append chunks from
recv, parse complete frames, and retain leftovers. Complexity should be over bytes read; avoid repeated slicing that turns parsing into . -
Timeouts and cancellation are correctness features, not polish. Use connect, read, write, and overall request deadlines; distinguish timeout from EOF and protocol errors. Server-side handlers should honor client cancellation to avoid wasted work and stale writes.
-
REST idempotency means repeated identical requests have the same intended effect.
GET,PUT, andDELETEare naturally idempotent when modeled well;POSTusually needs an idempotency key, commonly stored with request hash, status, response body, and expiration. -
Optimistic concurrency control uses a resource version,
updated_at, monotonically increasingversion, orETag. Clients sendIf-Match: <etag>; the server updates withWHERE id = ? AND version = ?, returning412 Precondition Failedor409 Conflictif stale. -
Pessimistic locking can be appropriate for scarce, high-value state, but it reduces throughput and risks deadlocks. Prefer short database transactions, deterministic lock ordering, and lock timeouts; avoid holding locks while calling external services.
-
Retry safety requires classifying failures. Retry
429,503, connection resets, and timeouts with exponential backoff and jitter, e.g. ; do not blindly retry non-idempotent mutations. -
Error contracts should be stable and machine-readable. Use appropriate HTTP statuses:
400validation,401unauthenticated,403unauthorized,404not found,409conflict,412precondition failed,422semantic validation,429rate limited,5xxserver failure. -
Authentication and authorization are separate checks.
JWT, session tokens, or mTLS prove identity; authorization verifies the caller can perform the action on that resource. Enforce authorization server-side even if the client hides unavailable actions. -
Rate limiting protects shared services from overload and abuse. Common algorithms include token bucket, leaky bucket, and fixed/sliding windows. Return
429withRetry-After; choose limits per user, device, IP, API key, or resource depending on abuse mode. -
Snapshot semantics require a clear read model. A snapshotable key-value store can use copy-on-write maps, immutable persistent data structures, or multi-version concurrency control; reads at snapshot
sshould see the latest version for each key. -
Python concurrency has subtle guarantees.
dictandlistoperations may be individually safe from interpreter crashes under theGIL, but compound operations like “check then insert” are not atomic. Usethreading.Lock,asyncio.Lock, queues, or single-writer ownership.
Worked example
For Implement a robust REST API method, a strong candidate should first clarify the resource, mutation semantics, caller identity, and whether duplicate submissions are possible: “Is this create, update, or money-moving? Do clients retry after timeouts? Do we need exactly-once effect or just idempotent observable behavior?” Then declare assumptions, such as using Postgres, JSON over HTTP, authenticated users, and a versioned row model. Organize the answer around four pillars: API contract, validation/authz, concurrency/idempotency, and failure handling/testing.
For a create-like POST, use an Idempotency-Key header scoped to user and endpoint; store the request hash and final response in an idempotency_requests table with a unique constraint on (user_id, key). If the same key arrives with a different request hash, return 409 Conflict; if the original is still processing, either wait briefly or return 409/202 depending on product semantics. For update-like methods, prefer PUT /resource/{id} or PATCH /resource/{id} with ETag and If-Match, implemented via an atomic conditional update.
Flag the key tradeoff explicitly: storing full responses makes retries simple and consistent, but increases storage and requires TTL cleanup; recomputing responses saves space but risks drifting behavior if state changes. Testing should include duplicate request races, stale version updates, auth failures, validation failures, database transaction rollback, and retry-after-commit scenarios. Close by saying that with more time, you would add observability: structured logs with request IDs, metrics for 409/412/429, latency percentiles like p95 and p99, and alerts on idempotency-store failures.
A second angle
For Implement a robust socket message reader, the same reliability mindset applies, but the API boundary is lower-level: the danger is assuming one recv equals one logical message. The candidate should define the wire protocol first, usually a length-prefixed frame with a fixed-size header and a maximum allowed body size. Concurrency control shifts from HTTP row versions to buffer ownership: one reader should own the socket buffer, parse complete frames, and hand immutable messages to worker threads or an event loop. Failure semantics must be precise: EOF with an empty buffer is clean close, EOF mid-frame is a protocol error, oversized length is rejection, and timeout is distinct from malformed input. Testing should simulate fragmented headers, multiple messages in one read, zero-byte reads, slowloris behavior, and malicious length values.
Common pitfalls
Pitfall: Treating retries as a transport concern only.
A tempting answer is “the client can retry on timeout,” but this can double-charge, create duplicate rows, or overwrite newer data. A better answer names which operations are safe to retry, adds idempotency keys or conditional updates, and defines what the server returns for duplicate in-flight or completed requests.
Pitfall: Hand-waving “use locks” without specifying scope.
Locks can protect in-memory structures inside one process, but they do not solve races across multiple app servers. For REST methods backed by a database, use unique constraints, transactions, row versions, and conditional writes; for in-process buffers, use ownership or explicit mutexes with minimal critical sections.
Pitfall: Over-indexing on the happy-path object model.
Candidates often design elegant endpoints but omit size limits, malformed input handling, EOF behavior, authorization, rate limits, and observability. Apple-style systems questions reward engineers who state invariants and failure modes: maximum payload, timeout policy, error mapping, transaction boundary, and tests for adversarial cases.
Connections
Interviewers may pivot from here into distributed transactions, eventual consistency, database isolation levels, or cache invalidation. They may also ask for implementation-level details in Python, Swift, Java, or Go, especially around thread safety, async I/O, and memory usage under high concurrency.
Further reading
-
Designing Data-Intensive Applications — Martin Kleppmann’s practical treatment of replication, transactions, consistency, and fault tolerance.
-
RFC 9110: HTTP Semantics — authoritative reference for HTTP methods, status codes, conditional requests, and semantics.
-
Stripe API Idempotency — clear production pattern for safely retrying mutation requests.
Featured in interview prep guides
Practice questions
- Implement a robust socket message readerApple · Software Engineer · Technical Screen · medium
- Migrate a monolithic wallet to microservicesApple · Software Engineer · Technical Screen · hard
- Design a snapshotable key-value storeApple · Software Engineer · Technical Screen · Medium
- Explain Python lists, dicts, and concurrencyApple · Software Engineer · Technical Screen · Medium
- Implement a robust REST API methodApple · Software Engineer · Technical Screen · hard
Related concepts
- Real-Time Systems, WebSockets, and Long-Lived Connections
- Fault Tolerance, Idempotency, And Concurrency ControlSystem Design
- Java, Concurrency, And Framework InternalsSoftware Engineering Fundamentals
- High-Throughput Streams, Jobs, And ObservabilitySystem Design
- RESTful API And HTTP Service DesignSoftware Engineering Fundamentals
- Concurrency Control And Thread SafetySystem Design