A practical curl interview question on tracing and reducing redundant HTTP requests: instrumenting a curl-based client, finding duplicate calls, and cutting request volume. Includes a full worked solution.
Using curl and lightweight instrumentation, identify how many HTTP requests a client makes during a workflow and which endpoints are called. Add logging of request IDs and correlation IDs, detect redundant or repeated requests, and modify the client to batch, cache, or debounce calls to reduce unnecessary traffic. Explain how you would verify correctness, measure improvement, and prevent regressions with tests and metrics.
Quick Answer: A practical curl interview question on tracing and reducing redundant HTTP requests: instrumenting a curl-based client, finding duplicate calls, and cutting request volume. Includes a full worked solution.
Instrument and Optimize a Client's HTTP Requests for a Workflow
You are pair-programming with the interviewer. You have a client (a script or
application) that drives a defined workflow against an HTTP API — for example:
authenticate, list resources, fetch details for some of them, then perform an
action. The client makes its calls with curl (or an equivalent HTTP layer you
can wrap), and there is a suspicion that it issues far more requests than the
workflow actually needs, wasting time and traffic. Nobody currently knows how
many requests a single run makes or which endpoints they hit.
You can run the client locally and you are free to modify its code. Constrain
yourself to curl plus lightweight in-code instrumentation — no heavyweight
proxies, no packet capture.
Your job, across the parts below, is to: measure the current request behavior,
make every request traceable, detect redundant calls, cut the unnecessary ones,
and then prove the change is correct and protect it from regressing.
Constraints & Assumptions
You may modify the client's HTTP layer but treat the
server API as fixed
—
you cannot change endpoint contracts (though you should ask whether batch or
conditional-request support exists).
Tooling is limited to
curl
and lightweight code instrumentation; no
external proxy/sniffer.
"Workflow" = one end-to-end run of the client (e.g., login → list → fetch
details → act). Optimizations must preserve the workflow's observable outcome.
Assume the workflow is run repeatedly (CI and/or by users), so improvements
and regression guards should be repeatable, not one-off measurements.
Clarifying Questions to Ask
A candidate should scope the whole problem before writing code by asking:
What does one "workflow" consist of end-to-end, and which steps are expected
to be read-only (idempotent
GET
) versus state-changing?
Does the server support conditional requests (
ETag
/
Last-Modified
), batch
endpoints, or pagination — i.e., which optimizations are even available?
Are any calls triggered by user/UI events (type-ahead, double-clicks) versus
fixed program flow? This determines whether debounce/coalescing applies.
Does the server emit or echo a request/correlation ID, or must the client own
ID generation? Can we join client logs to server logs?
What's "correct"? Is functional equivalence defined by the final state/output,
or must the exact sequence of side-effecting calls be preserved?
Part 1 — Baseline measurement
Instrument the client so a single workflow run records every HTTP request:
method, URL/path (with query), status code, latency, response size, and the
relevant response headers. Produce a count of total requests and a breakdown by
endpoint.
What This Part Should Cover
A single choke-point wrapper rather than scattered, inconsistent logging.
A structured, machine-parseable log record per request with the fields that
later parts need (method, path, query, status, latency, size).
Aggregation: total count and a per-endpoint breakdown from the captured data.
Part 2 — Traceability
Make requests correlatable: attach a per-request Request-ID and a
per-workflow Correlation-ID, send both as HTTP headers, and include both in
every log line.
What This Part Should Cover
Correct scoping: one Correlation-ID per workflow, a unique Request-ID per call.
Propagation as headers (e.g.,
X-Correlation-Id
/
X-Request-Id
)
and
in
structured logs so client logs can be grouped and joined to server logs.
Hygiene: resetting the Correlation-ID per workflow, not leaking IDs across
runs, no PII in IDs.
Part 3 — Redundancy detection
Using the instrumented logs, identify repeated and wasteful requests within a
workflow — same method + URL + query (and body where it matters) — and name
the patterns behind them.
What This Part Should Cover
A concrete method to surface duplicates from the structured logs (grouping by
correlation ID, counting
(method, url)
and
(method, path)
).
Judgment about which repeats are genuinely redundant versus legitimately
distinct (e.g., paging, deliberate polling).
Part 4 — Optimizations
Modify the client to cut the unnecessary calls you found, choosing the right
technique(s) per pattern: caching (in-memory TTL and/or ETag/If-None-Match
conditional requests), in-flight de-duplication (coalescing identical concurrent
calls), debounce/throttle for event-driven calls, and batching where the API
supports it.
What This Part Should Cover
A principled mapping from each detected pattern to an appropriate fix, not a
single blunt instrument.
Safety: only idempotent reads cached/coalesced; correct cache key including
auth/locale; correct
304 Not Modified
handling; non-idempotent writes
excluded (or guarded with idempotency keys).
Sensible composition/order of the layers (instrument → dedupe → cache →
debounce/batch) and tunable parameters (TTL, debounce window, batch flush).
Part 5 — Validation and metrics
Explain how you verify the optimized client is still correct and how you
quantify the improvement, then how you stop it from regressing.
What This Part Should Cover
Correctness: functional equivalence (golden/snapshot of final output or
state), header-presence assertions, and conditional-request (
304
) semantics.
Quantified improvement: before/after request count (total and per endpoint),
latency percentiles, payload size, cache-hit and duplicate rates.
Regression prevention: targeted unit tests (cache keying/TTL, in-flight
coalescing, debounce) plus an integration test with a request-recording stub,
and per-workflow budgets enforced in CI.
What a Strong Answer Covers
Across all parts, a strong candidate shows the discipline of measure → change →
re-measure, never optimizing before baselining:
One instrumentation choke-point that serves measurement, tracing, detection,
and the metrics in Part 5 — the parts reinforce each other rather than being
five disconnected scripts.
Correctness preserved as the top constraint: idempotency awareness gates every
optimization, and equivalence is asserted, not assumed.
Tradeoff reasoning: TTL/staleness vs. freshness, debounce latency vs. request
savings, batch latency vs. throughput, complexity vs. benefit.
A repeatable, automatable loop (budgets in CI) so the win is durable.
Follow-up Questions
Your in-memory cache works for one client run. How would the design change for
a long-lived client or multiple client instances (e.g., shared cache,
invalidation, stampede protection)?
One of the "redundant"
GET
s is actually intentional polling for a status
change. How do you tell that apart from a true redundancy, and how would your
detection avoid flagging it?
A batched write partially fails (op 3 of 5 errors). How do you map results and
errors back to callers, and what does the client guarantee about ordering and
atomicity?
How would you safely apply in-flight de-duplication or caching to a
non-idempotent
POST
without changing server behavior?