From b3c33315c0981573c29002e1929f83465916779d Mon Sep 17 00:00:00 2001 From: Tom Wayson Date: Mon, 3 Aug 2020 14:29:23 -0700 Subject: [PATCH] feat(url utils): add a utility fn to build URLs from a host, path, and queryParams AFFECTS PACKAGES: @esri/hub-common @esri/hub-content --- packages/common/src/urls/build-url.ts | 30 +++++++++++++++++++++ packages/common/src/urls/index.ts | 1 + packages/common/test/urls/build-url.test.ts | 27 +++++++++++++++++++ packages/content/src/content.ts | 17 +++++------- 4 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 packages/common/src/urls/build-url.ts create mode 100644 packages/common/test/urls/build-url.test.ts diff --git a/packages/common/src/urls/build-url.ts b/packages/common/src/urls/build-url.ts new file mode 100644 index 00000000000..8d0ae8887f9 --- /dev/null +++ b/packages/common/src/urls/build-url.ts @@ -0,0 +1,30 @@ +interface IQueryParams { + [key: string]: string; +} + +/** + * @private + */ +export function buildUrl(params: { + host: string; + path: string; + query?: IQueryParams; +}): string { + const { host, path, query } = params; + const baseUrl = host.endsWith("/") ? host : `${host}/`; + const url = new URL(path, baseUrl); + url.search = buildQueryString(query); + return url.toString(); +} + +function buildQueryString(params: IQueryParams = {}): string { + const queryParams = Object.keys(params) + .filter(key => { + return params[key] !== undefined; + }) + .reduce((acc: any, key: string) => { + acc[key] = params[key]; + return acc; + }, {}); + return new URLSearchParams(queryParams).toString(); +} diff --git a/packages/common/src/urls/index.ts b/packages/common/src/urls/index.ts index 433d677de5c..fc0024cf853 100644 --- a/packages/common/src/urls/index.ts +++ b/packages/common/src/urls/index.ts @@ -1,3 +1,4 @@ +export * from "./build-url"; export * from "./get-hub-locale-asset-url"; export * from "./get-portal-api-url"; export * from "./get-portal-url"; diff --git a/packages/common/test/urls/build-url.test.ts b/packages/common/test/urls/build-url.test.ts new file mode 100644 index 00000000000..502cdd9085a --- /dev/null +++ b/packages/common/test/urls/build-url.test.ts @@ -0,0 +1,27 @@ +import { buildUrl } from "../../src"; + +describe("urls", () => { + describe("buildUrl", () => { + it("should build url without query params", done => { + const result = buildUrl({ host: "https://test.com", path: "/foo/bar" }); + expect(result).toEqual("https://test.com/foo/bar"); + done(); + }); + + it("should build url with query params", done => { + const result = buildUrl({ + host: "https://test.com", + path: "/foo/bar", + query: { hello: "world" } + }); + expect(result).toEqual("https://test.com/foo/bar?hello=world"); + done(); + }); + + it("should build url when host ends with slash", done => { + const result = buildUrl({ host: "https://test.com/", path: "/foo/bar" }); + expect(result).toEqual("https://test.com/foo/bar"); + done(); + }); + }); +}); diff --git a/packages/content/src/content.ts b/packages/content/src/content.ts index d40c519b32d..260c6ef0e6f 100644 --- a/packages/content/src/content.ts +++ b/packages/content/src/content.ts @@ -10,17 +10,12 @@ import { IHubGeography, IHubRequestOptions, IBBox, + buildUrl, getType, getCategory, getItemThumbnailUrl } from "@esri/hub-common"; -function buildUrl(base: string, path: string): string { - const baseUrl = base.endsWith("/") ? base : `${base}/`; - const url = new URL(path, baseUrl); - return url.toString(); -} - // TODO: make this real; use request() under the hood? export function hubRequest(url: string, requestOptions?: IHubRequestOptions) { return fetch(url, { @@ -51,10 +46,12 @@ function getContentFromHub( id: string, requestOptions?: IHubRequestOptions ): Promise { - const url = buildUrl( - requestOptions && requestOptions.hubApiUrl, - `/datasets/${id}` - ); + const host = requestOptions && requestOptions.hubApiUrl; + // TODO: what if no host? reject? + const url = buildUrl({ + host, + path: `/datasets/${id}` + }); return hubRequest(url, requestOptions).then(resp => { const dataset = resp && resp.data && resp.data[0]; return datasetToContent(dataset, requestOptions.portalSelf);