Skip to content

Commit da78f7e

Browse files
committed
fix: prefer forwarded swagger base url
1 parent 438f3b3 commit da78f7e

2 files changed

Lines changed: 41 additions & 2 deletions

File tree

src/docs/swagger.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,32 @@ type SwaggerRequestLike = {
1212
get(name: string): string | undefined;
1313
};
1414

15+
const getForwardedHeaderValue = (
16+
request: SwaggerRequestLike,
17+
name: string,
18+
): string | undefined => {
19+
const value = request.get(name)?.trim();
20+
21+
if (!value) {
22+
return undefined;
23+
}
24+
25+
return value.split(",")[0]?.trim() || undefined;
26+
};
27+
1528
export const resolveSwaggerBaseUrl = (
1629
request: SwaggerRequestLike,
1730
): string => {
18-
const host = request.get("host");
31+
const protocol =
32+
getForwardedHeaderValue(request, "x-forwarded-proto") ?? request.protocol;
33+
const host =
34+
getForwardedHeaderValue(request, "x-forwarded-host") ?? request.get("host");
1935

2036
if (!host) {
2137
return LOCAL_SWAGGER_SERVER.url;
2238
}
2339

24-
return `${request.protocol}://${host}`;
40+
return `${protocol}://${host}`;
2541
};
2642

2743
export const buildSwaggerSpec = (baseUrl: string = LOCAL_SWAGGER_SERVER.url) => {

tests/contracts/swagger.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,29 @@ describe("swagger spec", () => {
4343
expect(baseUrl).toBe("https://auth-api-production-a97b.up.railway.app");
4444
});
4545

46+
it("prefers forwarded host and proto when present", () => {
47+
const baseUrl = resolveSwaggerBaseUrl({
48+
protocol: "http",
49+
get(header: string) {
50+
if (header === "x-forwarded-proto") {
51+
return "https, http";
52+
}
53+
54+
if (header === "x-forwarded-host") {
55+
return "auth-api-production-a97b.up.railway.app, internal.railway";
56+
}
57+
58+
if (header === "host") {
59+
return "internal.railway";
60+
}
61+
62+
return undefined;
63+
},
64+
});
65+
66+
expect(baseUrl).toBe("https://auth-api-production-a97b.up.railway.app");
67+
});
68+
4669
it("falls back to the local server when the host header is unavailable", () => {
4770
const baseUrl = resolveSwaggerBaseUrl({
4871
protocol: "https",

0 commit comments

Comments
 (0)