Skip to content
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
8 changes: 2 additions & 6 deletions lib/http-axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import axios, {
import { Readable } from "node:stream";
import { HTTPError, ReadError, RequestError } from "./exceptions.js";
import { USER_AGENT } from "./version.js";
import { createURLSearchParams } from "./utils.js";

interface httpClientConfig extends Partial<AxiosRequestConfig> {
baseURL?: string;
Expand Down Expand Up @@ -86,12 +87,7 @@ export default class HTTPClient {
}

public async postForm<T>(url: string, body?: any): Promise<T> {
const params = new URLSearchParams();
for (const key in body) {
if (body.hasOwnProperty(key)) {
params.append(key, body[key]);
}
}
const params = body ? createURLSearchParams(body) : new URLSearchParams();
const res = await this.instance.post(url, params.toString(), {
headers: { "Content-Type": "application/x-www-form-urlencoded" },
});
Expand Down
18 changes: 5 additions & 13 deletions lib/http-fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Buffer } from "node:buffer";
import { Readable } from "node:stream";
import { HTTPFetchError } from "./exceptions.js";
import { USER_AGENT } from "./version.js";
import { createURLSearchParams } from "./utils.js";

export interface FetchRequestConfig {
headers?: Record<string, string>;
Expand Down Expand Up @@ -63,12 +64,7 @@ export default class HTTPFetchClient {
public async get<T>(url: string, params?: any): Promise<Response> {
const requestUrl = new URL(url, this.baseURL);
if (params) {
const searchParams = new URLSearchParams();
for (const key in params) {
if (params.hasOwnProperty(key)) {
searchParams.append(key, params[key]);
}
}
const searchParams = createURLSearchParams(params);
requestUrl.search = searchParams.toString();
}
const response = await fetch(requestUrl, {
Expand Down Expand Up @@ -118,12 +114,7 @@ export default class HTTPFetchClient {

public async postForm(url: string, body?: any): Promise<Response> {
const requestUrl = new URL(url, this.baseURL);
const params = new URLSearchParams();
for (const key in body) {
if (body.hasOwnProperty(key)) {
params.append(key, body[key]);
}
}
const params = body ? createURLSearchParams(body) : new URLSearchParams();
const response = await fetch(requestUrl, {
method: "POST",
headers: {
Expand Down Expand Up @@ -186,7 +177,8 @@ export default class HTTPFetchClient {
public async delete(url: string, params?: any): Promise<Response> {
const requestUrl = new URL(url, this.baseURL);
if (params) {
requestUrl.search = new URLSearchParams(params).toString();
const searchParams = createURLSearchParams(params);
requestUrl.search = searchParams.toString();
}
const response = await fetch(requestUrl, {
method: "DELETE",
Expand Down
12 changes: 12 additions & 0 deletions lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ function toArrayBuffer(input: Uint8Array | Buffer): ArrayBuffer {
return arrayBuffer;
}

export function createURLSearchParams(
params: Record<string, unknown>,
): URLSearchParams {
const searchParams = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (value != null) {
searchParams.append(key, String(value));
}
}
return searchParams;
}

export function createMultipartFormData(
this: FormData | void,
formBody: Record<string, any>,
Expand Down
67 changes: 66 additions & 1 deletion test/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ensureJSON } from "../lib/utils.js";
import { ensureJSON, createURLSearchParams } from "../lib/utils.js";
import { JSONParseError } from "../lib/exceptions.js";
import { equal, ok } from "node:assert";

Expand All @@ -19,4 +19,69 @@ describe("utils", () => {
}
});
});

describe("createURLSearchParams", () => {
it("creates URLSearchParams from object with string values", () => {
const params = { key1: "value1", key2: "value2" };
const result = createURLSearchParams(params);
equal(result.get("key1"), "value1");
equal(result.get("key2"), "value2");
});

it("converts number values to strings", () => {
const params = { num: 123, float: 45.67 };
const result = createURLSearchParams(params);
equal(result.get("num"), "123");
equal(result.get("float"), "45.67");
});

it("converts boolean values to strings", () => {
const params = { bool1: true, bool2: false };
const result = createURLSearchParams(params);
equal(result.get("bool1"), "true");
equal(result.get("bool2"), "false");
});

it("filters out null values", () => {
const params = { key1: "value1", key2: null, key3: "value3" };
const result = createURLSearchParams(params);
equal(result.get("key1"), "value1");
equal(result.get("key2"), null);
equal(result.get("key3"), "value3");
});

it("filters out undefined values", () => {
const params = { key1: "value1", key2: undefined, key3: "value3" };
const result = createURLSearchParams(params);
equal(result.get("key1"), "value1");
equal(result.get("key2"), null);
equal(result.get("key3"), "value3");
});

it("handles empty object", () => {
const params = {};
const result = createURLSearchParams(params);
equal(result.toString(), "");
});

it("handles mixed types and null/undefined", () => {
const params = {
str: "test",
num: 42,
bool: true,
nullVal: null,
undefinedVal: undefined,
zero: 0,
emptyStr: "",
};
const result = createURLSearchParams(params);
equal(result.get("str"), "test");
equal(result.get("num"), "42");
equal(result.get("bool"), "true");
equal(result.get("zero"), "0");
equal(result.get("emptyStr"), "");
equal(result.get("nullVal"), null);
equal(result.get("undefinedVal"), null);
});
});
});