skip to content

In a Karate mock feature, what does karate.proceed('http://backend:8080') do to the incoming request, and what can the scenario still do to the reply that comes back?

level: middleimportance: should knowfreq 46%

answer

  1. a stand-in that can step aside
  2. the scenario is still running afterwards
  3. the real reply comes back editable
  4. no argument means the request's own host

basics

~20 s

karate.proceed forwards the request the mock is handling to the base URL you give it and brings the real reply back into the scenario, where it can still be changed before the caller ever sees it.

solid answer

~50 s

It turns that scenario into a forwarding proxy. Karate re-issues the current request — method, path, query parameters, headers and body — against the base URL you pass, and the real service's reply comes back into the still-running scenario rather than straight to the caller. That gives you a seam on both sides of a real call: change the request before it goes out, or shape the reply before it comes back. Called with **no argument** it targets the host named in the incoming request, which is what makes a Karate mock usable as a plain HTTP proxy. Because matching is per scenario and the first match wins, you can proceed on most routes and fake one or two in the same file. How you then override the reply differs between the Karate lines — see the version note.

code

gherkin · 13 lines
gherkin
Feature: payment gateway mock

Background:
  * def paymentServiceUrl = 'http://payments:8080'

Scenario: pathMatches('/payments/{id}/refund')
  # the real service cannot refund in a test environment
  * def responseStatus = 202
  * def response = { status: 'REFUND_QUEUED' }

Scenario: pathMatches('/payments')
  # everything else goes to the real thing
  * karate.proceed(paymentServiceUrl)

go deeper

for a junior

Recall that proceed forwards the current request to a real service and that the answer comes back into the scenario, not straight to the caller. With no argument it uses the request's own host.

for a middle

Explain the seam: the scenario is still running on both sides of the real call, so you can adjust the request going out and the reply coming back, and you can mix forwarded and faked routes in one file.

for a senior

Know the operational cost. A proceeding mock is a real client of a real service, so the suite loses hermeticity and inherits the upstream's failure modes — and on 2.x, passing the returned reply straight through disables your own status, header and delay overrides.

for a principal

Decide when interception earns its place at all. A gateway that forwards most traffic gives high fidelity and low isolation; a fully faked mock gives the opposite. That choice belongs with whoever owns the suite's flakiness budget.

## What the call actually does `karate.proceed()` is the step that turns a mock from a stand-in into an **interceptor**. It takes the request the mock is currently handling — method, path, query parameters, headers and body — and re-issues it against the base URL you hand it, using an HTTP client the mock owns. Hop-by-hop plumbing is dropped so the forwarded request can rebuild it honestly: the incoming `Content-Length` is not copied, because the outbound body sets its own. The reply from the real service then comes back **into the scenario**, and the scenario is still running. Nothing has been written to the original caller yet. That is the whole point: you get a seam on both sides of a real call. ## Called with no argument, it is a proxy Pass a base URL and the mock is a **rewriting gateway** — the caller talks to the mock, the mock talks to the real host. Pass nothing and Karate uses the host from the incoming request itself, which is what you want when the mock is configured as the client's HTTP proxy and the request already names its true destination. ## Selective interception is per scenario Because matching is scenario by scenario and the first match wins, the interesting configuration is a file where *some* routes proceed and others do not: ```gherkin Scenario: pathMatches('/payments') && methodIs('post') # this one we want to see, but not to change * karate.proceed(paymentServiceUrl) Scenario: pathMatches('/payments/{id}/refund') # this one the real service cannot do in a test environment * def responseStatus = 202 * def response = { status: 'REFUND_QUEUED' } ``` That shape — most traffic passes through, one or two routes are faked, and the fake lives next to the real route in the same file — is what people mean when they call a Karate mock an "API gateway". It also gives you a place to assert on traffic in flight, or to shape a reply the real service will not produce on demand: force a `503`, blank out a field, add latency. ## The call shape is version-scoped, and it changes what you can override This is the one detail that does not travel between the two Karate lines. | | Karate 1.x | Karate 2.x | |---|---|---| | how you write it | `* karate.proceed(url)` on its own | `* def response = karate.proceed(url)` | | what the call yields | nothing; it fills `response` and `responseHeaders` | the upstream reply, as an object | | overriding afterwards | set `responseStatus` / `responseDelay` as usual | assigning the object to `response` passes it through verbatim | On **1.x**, the forwarded reply lands in exactly the same variables an ordinary mock scenario would have set, so the normal assembly rules still apply and a following step can change anything. Karate's own proxy demo relies on this — it calls `karate.proceed(url)` and then adds `* def responseDelay = 3000` on the next line. On **2.x**, the call returns the reply and assigning it straight to `response` is a **pass-through**: status, headers and body all come from upstream, and `responseStatus`, `responseHeaders` and `responseDelay` are not consulted at all. To change something, keep the returned object under another name and assemble the reply from it: ```gherkin Scenario: pathMatches('/payments') * def upstream = karate.proceed(paymentServiceUrl) * def response = upstream.body * def responseStatus = upstream.status == 200 ? 200 : 503 * def responseDelay = 300 ``` ## What to watch for in practice - A proceeding mock makes **real network calls**, so it inherits the real service's latency, flakiness and auth requirements. A suite that was hermetic stops being hermetic the moment one scenario proceeds. - A route that proceeds is not recording anything by itself. If you want the traffic kept, that is something the scenario has to do explicitly around the call. - The request goes out with the caller's own headers, `Authorization` included. That is what makes the forwarded call behave like the real one, and it is also why a mock in this mode is handling live credentials — worth knowing before you point one at a shared environment. - Forwarding and faking in the same file is a maintenance advantage and a comprehension hazard: a reader has to check every scenario above the one they care about, because the first match wins and an earlier catch-all silences everything below it.

  • What does `karate.proceed()` with no argument target, and when would you use it?
    The host named in the incoming request itself, so no URL rewriting happens. That is the form you want when the mock is configured as the client's HTTP proxy rather than as its endpoint: the client still addresses the real service, the mock sits in the path, and each scenario decides whether to pass a request through or answer it.
  • What do you give up by having some scenarios proceed to a real service?
    Hermeticity. Any route that proceeds makes a real network call, so the suite inherits the upstream's latency, flakiness, auth and data state, and it can no longer run offline. That is usually a deliberate trade for a gateway or recording setup, but it should be a decision rather than a side effect of one convenient scenario.

saying these in an interview costs you the question

  • Thinks proceed only rewrites the URL and does not make a real call.
  • Believes the reply goes straight to the caller with no chance to change it.
  • Says a mock file must either forward everything or fake everything.
  • Assumes a proceeding scenario records the traffic it forwards.
  • Forgets that a scenario above the proceeding one can swallow the request first.