Add option to match relative URLs without computing isIndirectPathRequest()
See original GitHub issueThe following commit prevents us from upgrading: https://github.com/httptoolkit/mockttp/commit/ef2e0a88574afa8fb37dac834dcecc67e8a21426
This may be a breaking change if you are sending requests to a Mockttp server directly, using a hostname for the server that isn’t ‘localhost’ or one of its ip addresses. That traffic will now be treated as having an absolute URL.
We will be able to get around the issue, but I thought that describing our use case could help you if you wanted to change the design.
Our use case is system testing of an app
container which sometimes makes requests to an external_webservice
.
Our tests are run by another container named tester
, which makes requests to the app
container and checks the response. We have been using mockttp to mock external_webservice
. A typical test inside tester
would be:
describe('The APP container on /route1', () => {
before(async () => {
await mockServer.start(process.env.MOCK_PORT);
await mockServer.get('/external_api').thenReply(200, "something that external_webservice should respond");
});
after(async () => {
await mockServer.stop();
});
it('always calls the external_api and returns OK', async () => {
const response = await request(`${process.env.APP_URL}/route1`);
expect(response).to.equal('OK');
const externalRequests = await mockServer.getSeenRequests();
expect(externalRequests.length).to.equal(1);
});
}
Our containers run with docker-compose, with something like this;
app:
environment:
EXTERNAL_API_URL: http://tester:7500/external_api
tester:
environment:
MOCK_PORT: 7500
As you can see, the host that mockttp will receive is tester
not localhost
.
After upgrading, this is the error message:
No rules were found matching this request.
This request was: GET request to http://tester:7500/external_api with headers: ...
The configured rules are:
Match requests making GETs for /external_api, and then respond with status 200 and body "something that external_webservice should respond".
You can fix this by adding a rule to match this request, for example:
mockServer.get("/external_api").thenReply(200, "your response");
Note that the suggestion is incorrect, because this is precisely the route that we specified.
We can get around the issue in multiple ways. But maybe mockttp could be improved in one of the following ways:
- add a
disableProxy
option toMockttpOptions
- add a
noHostChecking
option toMockttpOptions
- create a
mockServer.proxyUrl
, which would be different frommockServer.url
(maybe appending a fingerprint like/.well-kown/mockttp-proxy
)
Issue Analytics
- State:
- Created 4 years ago
- Comments:12 (7 by maintainers)
Top GitHub Comments
This has now been released as v0.17.0, so I’ll close this.
Thanks again for the report, discussion & testing, this was really useful! Let me know if you have any more issues in future.
Interesting! That’s very useful, thanks, I wasn’t sure whether this case was one that anybody would hit - clearly it is 😃.
In the short term, you should be able to match this request by changing your rule to use the absolute form:
Does that work for you?
You could inject
tester:7500
through an env var if you’d prefer, or alternatively make this independent of host entirely with a regex (get(/https?:\/\/[^\/]+\/external_api/)
).In the medium term, I agree this makes that case difficult, and it is a case I’d like to support properly. That said, I’m cautious of solving it with new configuration options or by separating the proxied & direct request cases unnecessarily, since they’re fundamentally very similar, and it’s occasionally even useful to do both at the same time.
There’s an argument to be made that the issue here is simply in how path matching works perhaps? This could be changed so that absolute URL matchers check the host, whilst any relative URLs only check the path etc, and match for all hosts.
That would mean the host information is still available for matching when that’s useful, but the simpler option still works too, which seems fairly intuitive to me.
Given that, both
get('http://tester:7500/external_api')
andget('/external_api')
would match. Currently only the former does, and previously only the latter.What do you think?