Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encode the request body if Content-Type header is x-www-form-urlencoded #2096

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/openapi-fetch/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,22 @@ or when instantiating the client.

:::

### URL-encoded body

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.

```ts
const { data, error } = await client.POST("/tokens", {
body: {
clientId: "someClientId",
clientSecret: "someClientSecret",
},
headers: {
"Content-Type": "application/x-www-form-encoded",
},
});
```

## Path serialization

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:
Expand Down
13 changes: 11 additions & 2 deletions packages/openapi-fetch/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default function createClient(clientOptions) {
});
}

const serializedBody = body === undefined ? undefined : bodySerializer(body);
const serializedBody = body === undefined ? undefined : bodySerializer(body, headers);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So these are the headers unique to this request (probably could be named better). Below on line 92, we merge all the headers together. We should probably move that up, adn pass that in here to bodySerializer. That way it takes into account headers that users have set in their createClient() call, and it handles the normalization for you so it’s always a Header type (and you aren’t dealing with what the user passed in)


const defaultHeaders =
// with no body, we should not to set Content-Type
Expand Down Expand Up @@ -568,10 +568,19 @@ export function defaultPathSerializer(pathname, pathParams) {
* Serialize body object to string
* @type {import("./index.js").defaultBodySerializer}
*/
export function defaultBodySerializer(body) {
export function defaultBodySerializer(body, headers) {
if (body instanceof FormData) {
return body;
}
if (headers) {
const contentType =
headers.get instanceof Function
? (headers.get("Content-Type") ?? headers.get("content-type"))
: (headers["Content-Type"] ?? headers["content-type"]);
if (contentType === "application/x-www-form-urlencoded") {
return new URLSearchParams(body).toString();
}
}
return JSON.stringify(body);
}

Expand Down
13 changes: 13 additions & 0 deletions packages/openapi-fetch/test/common/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,19 @@ describe("request", () => {
expect(bodyUsed).toBe(true);
expect(bodyText).toBe("0");
});

test("`application/x-www-form-urlencoded` body", async () => {
const { bodyUsed, bodyText } = await fireRequestAndGetBodyInformation({
method: "POST",
fetchOptions: {
body: { key1: "value1", key2: "value2" },
headers: { "Content-Type": "application/x-www-form-urlencoded" },
},
});

expect(bodyUsed).toBe(true);
expect(bodyText).toBe("key1=value1&key2=value2");
});
});

test("cookie header is preserved", async () => {
Expand Down
Loading