diff --git a/.changeset/wet-days-crash.md b/.changeset/wet-days-crash.md new file mode 100644 index 000000000..73b6df6c6 --- /dev/null +++ b/.changeset/wet-days-crash.md @@ -0,0 +1,5 @@ +--- +"openapi-fetch": patch +--- + +Fix: encode primitive path parameters diff --git a/packages/openapi-fetch/src/index.js b/packages/openapi-fetch/src/index.js index e0cb43cb0..34cece9f3 100644 --- a/packages/openapi-fetch/src/index.js +++ b/packages/openapi-fetch/src/index.js @@ -397,7 +397,7 @@ export function defaultPathSerializer(pathname, pathParams) { nextURL = nextURL.replace(match, `;${serializePrimitiveParam(name, value)}`); continue; } - nextURL = nextURL.replace(match, style === "label" ? `.${value}` : value); + nextURL = nextURL.replace(match, style === "label" ? `.${encodeURIComponent(value)}` : encodeURIComponent(value)); } return nextURL; } diff --git a/packages/openapi-fetch/test/index.test.ts b/packages/openapi-fetch/test/index.test.ts index f49979740..78d1c20e5 100644 --- a/packages/openapi-fetch/test/index.test.ts +++ b/packages/openapi-fetch/test/index.test.ts @@ -206,6 +206,42 @@ describe("client", () => { ); }); + it("escapes reserved characters in path segment", async () => { + const client = createClient({ baseUrl }); + const { getRequestUrl } = useMockRequestHandler({ + baseUrl, + method: "get", + path: "/blogposts/*", + }); + + await client.GET("/blogposts/{post_id}", { + params: { path: { post_id: ";/?:@&=+$,# " } }, + }); + + // expect post_id to be encoded properly + const url = getRequestUrl(); + expect(url.pathname).toBe("/blogposts/%3B%2F%3F%3A%40%26%3D%2B%24%2C%23%20"); + }); + + it("does not escape allowed characters in path segment", async () => { + const client = createClient({ baseUrl }); + const { getRequestUrl } = useMockRequestHandler({ + baseUrl, + method: "get", + path: "/blogposts/*", + }); + + const postId = "aAzZ09-_.!~*'()"; + + await client.GET("/blogposts/{post_id}", { + params: { path: { post_id: postId } }, + }); + + // expect post_id to stay unchanged + const url = getRequestUrl(); + expect(url.pathname).toBe(`/blogposts/${postId}`); + }); + it("allows UTF-8 characters", async () => { const client = createClient({ baseUrl }); const { getRequestUrl } = useMockRequestHandler({ @@ -215,13 +251,12 @@ describe("client", () => { }); await client.GET("/blogposts/{post_id}", { - params: { path: { post_id: "post?id = 🥴" } }, + params: { path: { post_id: "🥴" } }, }); // expect post_id to be encoded properly const url = getRequestUrl(); - expect(url.searchParams.get("id ")).toBe(" 🥴"); - expect(url.pathname + url.search).toBe("/blogposts/post?id%20=%20%F0%9F%A5%B4"); + expect(url.pathname).toBe("/blogposts/%F0%9F%A5%B4"); }); });