Skip to content

Instantly share code, notes, and snippets.

@jrobinsonc
Last active February 8, 2025 06:41
Show Gist options
  • Save jrobinsonc/04d88b126a8d0845b506a214cc1d8b07 to your computer and use it in GitHub Desktop.
Save jrobinsonc/04d88b126a8d0845b506a214cc1d8b07 to your computer and use it in GitHub Desktop.
/**
* Constructs a URL by appending query parameters to a given path.
*
* @template TVariables - The shape of the params.
*
* @param path - Path.
* @param params - Optional. Params to be added as query parameters to the URL.
*
* @returns The constructed URL.
*/
function buildUrl<
TVariables extends Record<string, unknown> = Record<string, unknown>
>(path: string, params?: TVariables): string {
if (params === undefined || Object.keys(params).length === 0) {
return path;
}
const match: RegExpMatchArray | null = path.match(
/^(?<path>[^?]*)(?:\?(?<queryString>.*))?$/
);
if (match === null) {
throw new Error("Error parsing the given path");
}
const queryString = new URLSearchParams(match.groups?.queryString);
Object.entries(params).forEach(([key, value]) => {
if (Array.isArray(value)) {
if (queryString.has(key)) {
queryString.delete(key);
}
value.forEach((item: unknown): void => {
queryString.append(`${key}[]`, String(item));
});
} else {
queryString.set(key, String(value));
}
});
return `${match.groups?.path}?${queryString.toString()}`;
}
console.log(
buildUrl("/products?id=3", { id: 1, format: true }) ===
"/products?id=1&format=true"
);
console.log(
decodeURIComponent(
buildUrl("/products?id=3", { id: [1, 2], format: true })
) === "/products?id[]=1&id[]=2&format=true"
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment