Skip to content

Commit 3fd7e57

Browse files
committed
Encode the request body if Content-Type set
1 parent 7d6e896 commit 3fd7e57

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

docs/openapi-fetch/api.md

+16
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,22 @@ or when instantiating the client.
192192

193193
:::
194194

195+
### URL-encoded body
196+
197+
To send a body request in `application/x-www-form-urlencoded` format, which is commonly used to transmit key-value pairs in APIs like OAuth 2.0, pass the appropriate header and body as an object. `openapi-fetch` will automatically encode the body to the correct format.
198+
199+
```ts
200+
const { data, error } = await client.POST("/tokens", {
201+
body: {
202+
clientId: "someClientId",
203+
clientSecret: "someClientSecret",
204+
},
205+
headers: {
206+
"Content-Type": "application/x-www-form-encoded",
207+
},
208+
});
209+
```
210+
195211
## Path serialization
196212

197213
openapi-fetch supports path serialization as [outlined in the 3.1 spec](https://swagger.io/docs/specification/serialization/#path). This happens automatically, based on the specific format in your OpenAPI schema:

packages/openapi-fetch/src/index.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export default function createClient(clientOptions) {
7272
});
7373
}
7474

75-
const serializedBody = body === undefined ? undefined : bodySerializer(body);
75+
const serializedBody = body === undefined ? undefined : bodySerializer(body, headers);
7676

7777
const defaultHeaders =
7878
// with no body, we should not to set Content-Type
@@ -568,10 +568,19 @@ export function defaultPathSerializer(pathname, pathParams) {
568568
* Serialize body object to string
569569
* @type {import("./index.js").defaultBodySerializer}
570570
*/
571-
export function defaultBodySerializer(body) {
571+
export function defaultBodySerializer(body, headers) {
572572
if (body instanceof FormData) {
573573
return body;
574574
}
575+
if (headers) {
576+
const contentType =
577+
headers.get instanceof Function
578+
? (headers.get("Content-Type") ?? headers.get("content-type"))
579+
: (headers["Content-Type"] ?? headers["content-type"]);
580+
if (contentType === "application/x-www-form-urlencoded") {
581+
return new URLSearchParams(body).toString();
582+
}
583+
}
575584
return JSON.stringify(body);
576585
}
577586

packages/openapi-fetch/test/common/request.test.ts

+13
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,19 @@ describe("request", () => {
265265
expect(bodyUsed).toBe(true);
266266
expect(bodyText).toBe("0");
267267
});
268+
269+
test("`application/x-www-form-urlencoded` body", async () => {
270+
const { bodyUsed, bodyText } = await fireRequestAndGetBodyInformation({
271+
method: "POST",
272+
fetchOptions: {
273+
body: { key1: "value1", key2: "value2" },
274+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
275+
},
276+
});
277+
278+
expect(bodyUsed).toBe(true);
279+
expect(bodyText).toBe("key1=value1&key2=value2");
280+
});
268281
});
269282

270283
test("cookie header is preserved", async () => {

0 commit comments

Comments
 (0)