Skip to content

Commit

Permalink
[PSC-1988] Enable spot mock to have a 404 fallback proxy (#2066)
Browse files Browse the repository at this point in the history
In order to make the mock server more useful in the case where you have
multiple different upstream servers on the same hostname, this PR adds a
new optional fallback proxy to `spot mock`, which is used instead of
instantly 404'ing the received request if the request does not match any
of the given contracts. If provided, instead of 404'ing, it will send
the request through to the fallback proxy.
  • Loading branch information
timdawborn authored Oct 5, 2023
1 parent a251931 commit d132f81
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 10 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,12 +283,15 @@ ARGUMENTS
SPOT_CONTRACT path to Spot contract
OPTIONS
-h, --help show CLI help
-p, --port=port (required) [default: 3010] Port on which to run the mock server
--pathPrefix=pathPrefix Prefix to prepend to each endpoint path
-h, --help show CLI help
-p, --port=port (required) [default: 3010] Port on which to run the mock server
--pathPrefix=pathPrefix Prefix to prepend to each endpoint path
--proxyBaseUrl=proxyBaseUrl If set, the server will act as a proxy and fetch data from the given remote server
instead of mocking it
--proxyBaseUrl=proxyBaseUrl If set, the server will act as a proxy and fetch data from the given
remote server instead of mocking it
--proxyFallbackBaseUrl=proxyFallbackBaseUrl Like proxyBaseUrl, except used when the requested API does not match
defined SPOT contract. If unset, 404 will always be returned.
EXAMPLE
$ spot mock api.ts
Expand Down
10 changes: 8 additions & 2 deletions cli/src/commands/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export default class Mock extends Command {
description:
"If set, the server will act as a proxy and fetch data from the given remote server instead of mocking it"
}),
proxyFallbackBaseUrl: flags.string({
description:
"Like proxyBaseUrl, except used when the requested API does not match defined SPOT contract. If unset, 404 will always be returned."
}),
port: flags.integer({
char: "p",
description: "Port on which to run the mock server",
Expand All @@ -42,15 +46,17 @@ export default class Mock extends Command {
async run(): Promise<void> {
const {
args,
flags: { port, pathPrefix, proxyBaseUrl = "" }
flags: { port, pathPrefix, proxyBaseUrl, proxyFallbackBaseUrl = "" }
} = this.parse(Mock);
try {
const proxyConfig = inferProxyConfig(proxyBaseUrl);
const proxyConfig = inferProxyConfig(proxyBaseUrl || "");
const proxyFallbackConfig = inferProxyConfig(proxyFallbackBaseUrl || "");
const contract = parse(args[ARG_API]);
await runMockServer(contract, {
port,
pathPrefix: pathPrefix ?? "",
proxyConfig,
proxyFallbackConfig,
logger: this
}).defer();
this.log(`Mock server is running on port ${port}.`);
Expand Down
37 changes: 37 additions & 0 deletions lib/src/mock-server/server.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ describe("Server", () => {
};
const proxyBaseUrl = buildProxyBaseUrl(proxyConfig);

const fallbackProxyConfig: ProxyConfig = {
isHttps: false,
host: "example.com",
port: 80,
path: ""
};
const proxyFallbackBaseUrl = buildProxyBaseUrl(fallbackProxyConfig);

afterEach(() => {
nock.cleanAll();
});
Expand Down Expand Up @@ -167,5 +175,34 @@ describe("Server", () => {
expect(typeof response.body.name).toBe(TypeKind.STRING);
});
});

it("Requests that do not match a contract return 404 without a fallback proxy", async () => {
const { app } = runMockServer(contract, {
logger: mockLogger,
pathPrefix: "/api",
port: 8085
});

await request(app)
.get("/")
.then(response => {
expect(response.statusCode).toBe(404);
});
});

it("Requests that do not match a contract to proxy the request with a fallback proxy", async () => {
const { app } = runMockServer(contract, {
logger: mockLogger,
pathPrefix: "/api",
port: 8085,
proxyFallbackConfig: fallbackProxyConfig
});

await request(app)
.get("/")
.then(response => {
expect(response.statusCode).toBe(200);
});
});
});
});
16 changes: 13 additions & 3 deletions lib/src/mock-server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ export function runMockServer(
port,
pathPrefix,
proxyConfig,
proxyFallbackConfig,
logger
}: {
port: number;
pathPrefix: string;
proxyConfig?: ProxyConfig | null;
proxyFallbackConfig?: ProxyConfig | null;
logger: Logger;
}
) {
Expand Down Expand Up @@ -74,9 +76,17 @@ export function runMockServer(
}
}

logger.error(`No match for request ${req.method} at ${req.path}.`);
resp.status(404);
resp.send();
logger.log(`No match for request ${req.method} at ${req.path}.`);
if (proxyFallbackConfig) {
return proxyRequest({
incomingRequest: req,
response: resp,
proxyConfig: proxyFallbackConfig
});
} else {
resp.status(404);
resp.send();
}
});
return {
app,
Expand Down

0 comments on commit d132f81

Please sign in to comment.