Skip to content

Commit ada40f5

Browse files
authored
fix: properly serialize url search params (#59)
* fix: properly serialize url search params * chore: remove unnecessary awaits * chore: add tests * refactir: expand array values into multiple query params
1 parent de3d192 commit ada40f5

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

packages/better-fetch/src/test/fetch.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,4 +533,39 @@ describe("url", () => {
533533
});
534534
expect(url.toString()).toBe("http://localhost:4001/param/%23test/item%201");
535535
});
536+
537+
it("should expand array values into multiple query parameters", () => {
538+
const url = getURL("/test", {
539+
query: {
540+
filterValue: ["admin", "user"],
541+
},
542+
baseURL: "http://localhost:4000",
543+
});
544+
545+
expect(url.toString()).toBe(
546+
"http://localhost:4000/test?filterValue=admin&filterValue=user",
547+
);
548+
});
549+
550+
it("should preserve objects as JSON strings", () => {
551+
const url = getURL("/test", {
552+
query: {
553+
options: { page: 1, limit: 10 },
554+
},
555+
baseURL: "http://localhost:4000",
556+
});
557+
558+
expect(url.toString()).toBe(
559+
"http://localhost:4000/test?options=%7B%22page%22%3A1%2C%22limit%22%3A10%7D",
560+
);
561+
});
562+
563+
it("should leave strings untouched", () => {
564+
const url = getURL("/test", {
565+
query: { foo: "bar" },
566+
baseURL: "http://localhost:4000",
567+
});
568+
569+
expect(url.toString()).toBe("http://localhost:4000/test?foo=bar");
570+
});
536571
});

packages/better-fetch/src/url.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { methods } from "./create-fetch";
2-
import { BetterFetchOption } from "./types";
2+
import type { BetterFetchOption } from "./types";
33

44
/**
55
* Normalize URL
66
*/
77
export function getURL(url: string, option?: BetterFetchOption) {
8-
let { baseURL, params, query } = option || {
8+
const { baseURL, params, query } = option || {
99
query: {},
1010
params: {},
1111
baseURL: "",
@@ -29,7 +29,18 @@ export function getURL(url: string, option?: BetterFetchOption) {
2929
const queryParams = new URLSearchParams(urlQuery);
3030
for (const [key, value] of Object.entries(query || {})) {
3131
if (value == null) continue;
32-
queryParams.set(key, String(value));
32+
let serializedValue;
33+
if (typeof value === "string") {
34+
serializedValue = value;
35+
} else if (Array.isArray(value)) {
36+
for (const val of value) {
37+
queryParams.append(key, val);
38+
}
39+
continue;
40+
} else {
41+
serializedValue = JSON.stringify(value);
42+
}
43+
queryParams.set(key, serializedValue);
3344
}
3445
if (params) {
3546
if (Array.isArray(params)) {
@@ -49,7 +60,9 @@ export function getURL(url: string, option?: BetterFetchOption) {
4960
if (path.startsWith("/")) path = path.slice(1);
5061
let queryParamString = queryParams.toString();
5162
queryParamString =
52-
queryParamString.length > 0 ? `?${queryParamString}`.replace(/\+/g, "%20") : "";
63+
queryParamString.length > 0
64+
? `?${queryParamString}`.replace(/\+/g, "%20")
65+
: "";
5366
if (!basePath.startsWith("http")) {
5467
return `${basePath}${path}${queryParamString}`;
5568
}

0 commit comments

Comments
 (0)