The mode defines the behavior of the proxy.

proxyOnce

The default proxyOnce mode is simpler; it always creates a new stub in front of the stub with the proxy response, relying on mountebank's first-match policy to automatically replay the saved response in the new stub the next time a request matches the predicates. Imagine the following stubs array, set by us when we create the imposter:

"stubs": [{
  "responses": [{
    "proxy": {
      "to": "http://origin-server.com",
      "mode": "proxyOnce",
      "predicateGenerators": [{ "matches": { "path": true } }]
    }
  }]
}]

When we issue an HTTP call to /test, the stub will proxy all of the request details to http://origin-server.com/test, and save off the response in a new stub in front of the stub with the proxy response:

"stubs": [
  {
    "predicates": [{ "deepEquals": { "path": "/test" } } ],
    "responses": [{
      "is": {
        "body": "Downstream service response",
        ...
      }
    }]
  },
  {
    "responses": [{
      "proxy": {
        "to": "http://localhost:2001",
        "mode": "proxyOnce",
        "predicateGenerators": [{ "matches": { "path": true } }]
      }
    }]
  }
]

Because of mountebank's first-match policy on stubs, the next time the imposter receives a request to /test, the saved predicates on the newly created stub will match, and the recorded response will be replayed. If the imposter receives a call to /different-path, then it will proxy again, creating a new stub, because the path is different.

proxyAlways

The proxyAlways mode saves stubs behind the proxy stub. This allows you to record a richer set of interactions with the origin server because it can record multiple responses for the same logical request (as defined by the predicates). The consequence is that it requires you to save off the imposter representation and remove or reorder the proxy stubs to replay those interactions. The easiest way to do that is with the mb replay command.

Let's say you had the following stubs array:

"stubs": [{
  "responses": [{
    "proxy": {
      "to": "http://origin-server.com",
      "mode": "proxyAlways",
      "predicateGenerators": [{ "matches": { "path": true } }]
    }
  }]
}]

Every time we send a request to /test, it will be proxied to http://origin-server.com/test. The first time we do that, just like the proxyOnce example, it will add a new stub. The difference is that the new stub will be created at the end of the array:

"stubs": [
  {
    "responses": [
      {
        "proxy": {
          "to": "http://origin-server.com",
          "mode": "proxyAlways",
          "predicateGenerators": [{ "matches": { "path": true } }]
        }
      }
    ]
  },
  {
    "predicates": [{ "deepEquals": { "path": "/test" } }],
    "responses": [{
      "is": {
        "body": "Request number 1",
        ...
      }
    }]
  }
]

Because the proxy occurs before the new stub, the next request will continue to use the proxy response. This allow us to capture multiple responses for the same logical request. If we once again send a request to the /test path, since a stub with the predicate already exists, the response will be added to the existing stub:

"stubs": [
  {
    "responses": [
      {
        "proxy": {
          "to": "http://origin-server.com",
          "mode": "proxyAlways",
          "predicateGenerators": [{ "matches": { "path": true } }]
        }
      }
    ]
  },
  {
    "predicates": [{ "deepEquals": { "path": "/test" } }],
    "responses": [
      {
        "is": {
          "body": "Request number 1",
          ...
        }
      },
      {
        "is": {
          "body": "Request number 2",
          ...
        }
      }
    ]
  }
]

This configuration allows you to capture as rich a set of data as your downstream system provides and play it back with the appropriate predicates. The only additional complexity with proxyAlways is that you have to explicitly switch to replay mode. Conceptually, replaying is as simple as removing the proxies. The easiest way to do that is by using the mb replay command, passing in the port if you're using a nonstandard port for running mb. If, for example, we had previously started mountebank on port 3535, we could switch to replay mode with the following call:

mb replay --port 3535

As always, there's more than one way to do it. You can instead use the API, retrieving all imposters with a call to GET /imposters?replayabe=true&removeProxies=true and sending the payload in a call PUT /imposters.

Now if we look at the imposter configuration, you'll notice that the proxy has been removed. Only the saved responses will be used.

"stubs": [
  {
    "predicates": [{ "deepEquals": { "path": "/test" } }],
    "responses": [
      {
        "is": {
          "body": "Request number 1",
          ...
        }
      },
      {
        "is": {
          "body": "Request number 2",
          ...
        }
      }
    ]
  }
]

proxyTransparent

The proxyTransparent mode does not save any responses and simply proxies the requests transparently.

Let's say you had the following stubs array:

"stubs": [{
  "responses": [{
    "proxy": {
      "to": "http://origin-server.com",
      "mode": "proxyTransparent"
    }
  }]
}]

Every time we send a request to /test, it will be proxied to http://origin-server.com/test. There will be no stub created off the back of the request.