In Mountebank, what does injectHeaders do to a request passing through a proxy?
answer
- it rewrites only the outbound request
- an object on the proxy response
- matching already happened on the original
- credentials the client must not hold
- sets a header rather than merging one
basics
~20 sMountebank's injectHeaders adds headers to the request the proxy sends upstream, not to the one the client sent. It carries credentials or negotiation the code under test cannot supply, and it never affects matching or the reply the client receives.
solid answer
~40 s`injectHeaders` is an object on a Mountebank `proxy` response. Every pair in it is applied to the request Mountebank forwards to the address in `to`, immediately before it leaves, so it changes what the real translation-glossary service receives and nothing else. The client's own request is untouched, the stub's `predicates` and any `predicateGenerators` still see the original, and the reply comes back to the caller unchanged. The usual reasons are credentials the code under test must not hold, such as an `X-Glossary-Api-Key`; a tenant or account header only the harness knows; and forcing negotiation like `Accept-Language` so proxied replies stay stable whatever machine runs the suite. Treat it as setting a header rather than merging with one the client already sent, and keep a real key out of a committed imposter file.
code
json · 14 lines{
"responses": [
{
"proxy": {
"to": "https://glossary.example.com",
"mode": "proxyTransparent",
"injectHeaders": {
"X-Glossary-Api-Key": "replaced-at-startup",
"Accept-Language": "en-GB"
}
}
}
]
}go deeper
Know that Mountebank's injectHeaders sits on a proxy response and adds headers to the request going out to the real service, not to the request your code sent.
Explain the ordering: predicates run on the original request, injectHeaders applies afterwards on the way out, and nothing it adds is visible to the client or to the reply.
Show you use it to keep an upstream credential at the proxy instead of in the code under test, and that you know a committed imposter file is not a place for the real value.
Own the policy question: which headers a shared proxy is allowed to inject, how those values reach it without landing in a repository, and what identifies your suite's traffic in a third party's logs.
## What `injectHeaders` is `injectHeaders` is an object on a Mountebank `proxy` response. Every key/value pair in it is applied to the request Mountebank sends to the address in `to`, just before that request goes out. It is a rewrite of the **outbound** request only: the request the client sent is untouched, the `predicates` that chose this Mountebank stub already ran against the original, and the reply that comes back is handed to the client unchanged. That distinction is the whole of the field. A Mountebank `proxy` response has three concerns and one field for each: - `to` — where the forwarded request goes. - `mode` — what the imposter does with the reply (`proxyOnce`, `proxyAlways`, `proxyTransparent`). - `injectHeaders` — what the forwarded request looks like when it arrives. ## Why a pass-through proxy needs it In selective pass-through the imposter stands between the code under test and the real translation-glossary service, and those two ends often need different requests. - **Credentials the test must not hold.** The glossary service wants an `X-Glossary-Api-Key`; the code under test is pointed at the imposter and sends none. Injecting the key at the proxy keeps it in one place, out of the client's configuration and out of every test that talks to the imposter. - **Headers the origin requires and the client cannot know.** A shared upstream may key on an account or tenant header that only the harness has. - **Negotiation a fixture depends on.** Forcing `Accept-Language: en-GB` on the way out means proxied glossary terms come back in one language, whatever locale the machine running the suite happens to have. - **Separating your traffic upstream.** A header naming the suite makes proxied calls identifiable in the real service's own logs, which matters when a broad proxy is quietly sending production-shaped traffic somewhere. ## What it does not do 1. It does not affect matching. A Mountebank stub's `predicates`, and predicates built by `predicateGenerators`, see the request as the client sent it. Injecting a header does not make a stub whose predicate names that header start matching. 2. It does not change the response. Nothing in `injectHeaders` reaches the client; to change the reply you need Mountebank's `is` response or its `decorate` behavior. 3. It does not rewrite the path or the query. `injectHeaders` adds headers and nothing else, so a proxy that must reach a different path upstream needs a different `to` or a different stub. 4. It is not a place for a real secret in a committed file. A value written into an imposter's JSON is as public as that file is, so a definition living in a repository should have its key substituted in when the imposter is assembled rather than carried inline. ## Collisions and ordering Treat `injectHeaders` as setting the header on the outbound request rather than merging with one the client already sent under the same name. If both ends genuinely need to contribute a value, use a distinct header name for the injected one. An imposter that depends on a merge rule is an imposter that breaks the day a client library starts sending a default it did not send before, and that failure surfaces as a confusing upstream rejection rather than as a test error. ## The contrast worth knowing In WireMock the same on-the-way-through rewrite is `withAdditionalRequestHeader(` on a proxy response, alongside `withProxyUrlPrefixToRemove(` for trimming a path prefix before the request is forwarded. ## Where it fits in the arrangement A working Mountebank pass-through imposter reads as three decisions in one file: - the specific stubs, whose `predicates` name the glossary paths you are faking and whose `is` responses hold the canned entries; - the broad `proxy` stub with no predicates of its own, which therefore takes everything the specific stubs did not answer; - inside that proxy, `to` for the real service, `mode` for whether the pass-through stays a pass-through, and `injectHeaders` for the difference between the request your code makes and the request the real glossary service will accept. Getting `injectHeaders` right is what lets the second and third of those stay honest. Without it, teams usually solve the credential problem by handing the code under test the real upstream key and pointing it at the imposter anyway, which puts a production secret into every test environment to satisfy a header the imposter could have added itself.
- Can Mountebank's injectHeaders make a stub whose predicate names that header start matching?No. Predicate evaluation happens on the request as the client sent it, and by the time `injectHeaders` runs the proxy stub has already been chosen. The same holds for `predicateGenerators`: a saved stub is keyed on the original request, not the injected one. If a test needs that header present for matching, the client under test has to send it.
- How do you keep a real upstream key out of a committed Mountebank imposter file?Keep a placeholder in the committed definition and substitute the real value when the imposter is created, so the secret comes from the environment the suite runs in. The alternative people reach for - handing the key to the code under test - is worse, because it spreads a production credential across every test environment instead of confining it to the proxy.
It is the forwarding desk franking an envelope before it goes out: the sender never applied that mark, the recipient sees only the stamped version, and the address on the front is unchanged.
saying these in an interview costs you the question
- Thinking injectHeaders changes headers the client sees
- Expecting injected headers to influence predicate matching
- Using injectHeaders to rewrite a path or query string
- Committing a real upstream API key inside the imposter JSON
- Assuming it merges with a header the client already sent