diff --git a/src/__tests__/providerCatalog.spec.ts b/src/__tests__/providerCatalog.spec.ts index c2927772..6c8666a8 100644 --- a/src/__tests__/providerCatalog.spec.ts +++ b/src/__tests__/providerCatalog.spec.ts @@ -164,6 +164,42 @@ describe("GET /:provider", () => { }); }); }); + + describe(`given the provider has a collection`, () => { + it("has a child link for that collection without query parameters", async function () { + sandbox + .stub(Provider, "getProviders") + .resolves([null, [{ "provider-id": "TEST", "short-name": "TEST" }]]); + + const mockCollections = generateSTACCollections(1); + sandbox.stub(Collections, "getCollectionIds").resolves({ + count: mockCollections.length, + cursor: "foundCursor", + items: mockCollections.map((coll) => ({ + id: `${coll.id}`, + title: coll.title ?? faker.random.words(4), + })), + }); + + const { body: catalog } = await request(stacApp).get("/stac/TEST?param=value"); + + const children = catalog.links.filter((l: Link) => l.rel === "child"); + expect(children).to.have.length(mockCollections.length); + + mockCollections.forEach((collection) => { + const childLink = children.find((l: Link) => l.href.endsWith(collection.id)); + + expect(childLink, JSON.stringify(children, null, 2)).to.have.property( + "type", + "application/json" + ); + expect(childLink.href, JSON.stringify(childLink, null, 2)).to.not.contain("?param=value"); + expect(childLink.href, JSON.stringify(childLink, null, 2)).to.match( + /^https?:\/\/.*TEST\/collections/ + ); + }); + }); + }); }); describe("given CMR providers endpoint responds with an error", () => { diff --git a/src/__tests__/rootCatalog.spec.ts b/src/__tests__/rootCatalog.spec.ts index 090c3acb..61a1c87c 100644 --- a/src/__tests__/rootCatalog.spec.ts +++ b/src/__tests__/rootCatalog.spec.ts @@ -55,7 +55,7 @@ describe("GET /stac", () => { }); describe("given CMR responds with providers", () => { - before(() => { + beforeEach(() => { sandbox .stub(Providers, "getProviders") .resolves([null, [{ "provider-id": "TEST", "short-name": "TEST" }]]); @@ -76,6 +76,23 @@ describe("GET /stac", () => { expect(providerLink.title).to.equal(provider["provider-id"]); }); }); + + it("should have an entry for each provider in the links without query parameters", async () => { + const { statusCode, body } = await request(app).get("/stac?param=value"); + + expect(statusCode).to.equal(200); + const [, expectedProviders] = cmrProvidersResponse; + + expectedProviders!.forEach((provider) => { + const providerLink = body.links.find((l: Link) => l.href.includes(provider["provider-id"])); + + expect(providerLink.href).to.match(/^(http)s?:\/\/.*\w+/); + expect(providerLink.href).to.not.contain("?param=value"); + expect(providerLink.rel).to.equal("child"); + expect(providerLink.type).to.equal("application/json"); + expect(providerLink.title).to.equal(provider["provider-id"]); + }); + }); }); describe("given CMR providers endpoint responds with an error", () => { diff --git a/src/routes/browse.ts b/src/routes/browse.ts index 2ebb7d4f..8ccdad23 100644 --- a/src/routes/browse.ts +++ b/src/routes/browse.ts @@ -5,7 +5,7 @@ import { Links } from "../@types/StacCatalog"; import { getCollections } from "../domains/collections"; import { buildQuery, stringifyQuery } from "../domains/stac"; import { ItemNotFound } from "../models/errors"; -import { mergeMaybe, stacContext } from "../utils"; +import { getBaseUrl, mergeMaybe, stacContext } from "../utils"; const collectionLinks = (req: Request, nextCursor?: string | null): Links => { const { stacRoot, self, path } = stacContext(req); @@ -64,13 +64,10 @@ export const collectionsHandler = async (req: Request, res: Response): Promise { collection.links.push({ rel: "self", - href: `${baseUrl}/${encodeURIComponent(collection.id)}`, + href: `${getBaseUrl(self)}/${encodeURIComponent(collection.id)}`, type: "application/json", }); collection.links.push({ @@ -92,7 +89,7 @@ export const collectionsHandler = async (req: Request, res: Response): Promise { const selfLinks = generateSelfLinks(req); const childLinks = (collections ?? []).map(({ id, title }) => ({ rel: "child", - href: `${self}/collections/${encodeURIComponent(id)}`, + href: `${getBaseUrl(self)}/collections/${encodeURIComponent(id)}`, title, type: "application/json", })); diff --git a/src/routes/rootCatalog.ts b/src/routes/rootCatalog.ts index 5151d346..8a6d4405 100644 --- a/src/routes/rootCatalog.ts +++ b/src/routes/rootCatalog.ts @@ -3,7 +3,7 @@ import { Link, STACCatalog } from "../@types/StacCatalog"; import { conformance } from "../domains/providers"; import { Provider } from "../models/CmrModels"; -import { stacContext } from "../utils"; +import { getBaseUrl, stacContext } from "../utils"; const STAC_VERSION = process.env.STAC_VERSION ?? "1.0.0"; @@ -45,7 +45,7 @@ const providerLinks = (req: Request, providers: Provider[]): Link[] => { rel: "child", title, type: "application/json", - href: `${self}/${providerId}`, + href: `${getBaseUrl(self)}/${providerId}`, })); }; diff --git a/src/utils/index.ts b/src/utils/index.ts index a86fd5c1..18af1324 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -174,3 +174,11 @@ export const generatePossibleCollectionIds = (id: string, separator: string, rep return tokensCopy.join(separator); }); + +/** + * Returns the base URL + * This is used to remove Query Parameters that may have been added to the URL. + */ +export const getBaseUrl = (url: string) => { + return url.replace(/\?.*$/, ""); +};