Skip to content

Commit

Permalink
refactor: inject query parameters directly
Browse files Browse the repository at this point in the history
  • Loading branch information
lihbr committed Sep 5, 2024
1 parent 667699f commit 4ff2bde
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 64 deletions.
26 changes: 10 additions & 16 deletions src/buildQueryURL.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { castArray } from "./lib/castArray"
import { devMsg } from "./lib/devMsg"

import { version } from "../package.json"

/**
* The query parameter used to indicate if the client is in development mode to
* the API.
*/
export const PRISMIC_DEV_PARAM = "x-d"
const PRISMIC_DEV_PARAM = "x-d"

/**
* The query parameter used to indicate the version of the client to the API.
*/
export const PRISMIC_CLIENT_VERSION_PARAM = "x-c"
const PRISMIC_CLIENT_VERSION_PARAM = "x-c"

/**
* Create a union of the given object's values, and optionally specify which
Expand Down Expand Up @@ -203,20 +205,6 @@ export interface QueryParams {
* {@link https://prismic.io/docs/route-resolver}
*/
brokenRoute?: string

/**
* Whether or not the client is running in a development environment.
*
* @internal
*/
[PRISMIC_DEV_PARAM]?: number

/**
* The client version used to make the request.
*
* @internal
*/
[PRISMIC_CLIENT_VERSION_PARAM]?: string
}

/**
Expand Down Expand Up @@ -399,5 +387,11 @@ export const buildQueryURL = (
}
}

url.searchParams.set(PRISMIC_CLIENT_VERSION_PARAM, `js-${version}`)

if (process.env.NODE_ENV === "development") {
url.searchParams.set(PRISMIC_DEV_PARAM, "1")
}

return url.toString()
}
25 changes: 1 addition & 24 deletions src/createClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,11 @@ import { RefExpiredError } from "./errors/RefExpiredError"
import { RefNotFoundError } from "./errors/RefNotFoundError"
import { RepositoryNotFoundError } from "./errors/RepositoryNotFoundError"

import { version } from "../package.json"

import type { LinkResolverFunction } from "./helpers/asLink"
import { asLink } from "./helpers/asLink"

import type { BuildQueryURLArgs } from "./buildQueryURL"
import {
PRISMIC_CLIENT_VERSION_PARAM,
PRISMIC_DEV_PARAM,
buildQueryURL,
} from "./buildQueryURL"
import { buildQueryURL } from "./buildQueryURL"
import { filter } from "./filter"
import { getRepositoryEndpoint } from "./getRepositoryEndpoint"
import { getRepositoryName } from "./getRepositoryName"
Expand Down Expand Up @@ -466,22 +460,6 @@ export class Client<TDocuments extends PrismicDocument = PrismicDocument> {

fetchOptions?: RequestInitLike

/**
* Internal parameters that will be sent with each query.
*/
private internalDefaultParams: Omit<
BuildQueryURLArgs,
"ref" | "integrationFieldsRef" | "accessToken" | "routes"
> =
process.env.NODE_ENV === "development"
? {
[PRISMIC_DEV_PARAM]: 1,
[PRISMIC_CLIENT_VERSION_PARAM]: version,
}
: {
[PRISMIC_CLIENT_VERSION_PARAM]: version,
}

/**
* Default parameters that will be sent with each query. These parameters can
* be overridden on each query if needed.
Expand Down Expand Up @@ -1437,7 +1415,6 @@ export class Client<TDocuments extends PrismicDocument = PrismicDocument> {
undefined

return buildQueryURL(this.endpoint, {
...this.internalDefaultParams,
...this.defaultParams,
...params,
ref,
Expand Down
55 changes: 39 additions & 16 deletions test/buildQueryURL.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { expect, it, vi } from "vitest"

import { version } from "../package.json"

import * as prismic from "../src"

const endpoint = prismic.getRepositoryEndpoint("qwerty")
const xClientVersionParam = `&x-c=js-${version}`

it("includes ref", () => {
expect(prismic.buildQueryURL(endpoint, { ref: "ref" })).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref${xClientVersionParam}`,
)
})

Expand All @@ -19,7 +22,7 @@ it("supports single filter", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?q=[[has(my.document.title)]]&ref=ref",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?q=[[has(my.document.title)]]&ref=ref${xClientVersionParam}`,
)

// TODO: Remove when we remove support for deprecated `predicates` argument.
Expand All @@ -31,7 +34,7 @@ it("supports single filter", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?q=[[has(my.document.title)]]&ref=ref",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?q=[[has(my.document.title)]]&ref=ref${xClientVersionParam}`,
)
})

Expand All @@ -47,7 +50,7 @@ it("supports multiple filters", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?q=[[has(my.document.title)]]&q=[[has(my.document.subtitle)]]&ref=ref",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?q=[[has(my.document.title)]]&q=[[has(my.document.subtitle)]]&ref=ref${xClientVersionParam}`,
)

// TODO: Remove when we remove support for deprecated `predicates` argument.
Expand All @@ -62,7 +65,7 @@ it("supports multiple filters", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?q=[[has(my.document.title)]]&q=[[has(my.document.subtitle)]]&ref=ref",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?q=[[has(my.document.title)]]&q=[[has(my.document.subtitle)]]&ref=ref${xClientVersionParam}`,
)
})

Expand All @@ -85,7 +88,7 @@ it("supports params", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&access_token=accessToken&pageSize=1&page=1&after=after&fetch=fetch&fetchLinks=fetchLinks&graphQuery=graphQuery&lang=lang&orderings=[orderings]&routes=routes&brokenRoute=brokenRoute",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&access_token=accessToken&pageSize=1&page=1&after=after&fetch=fetch&fetchLinks=fetchLinks&graphQuery=graphQuery&lang=lang&orderings=[orderings]&routes=routes&brokenRoute=brokenRoute${xClientVersionParam}`,
)
})

Expand All @@ -105,7 +108,9 @@ it("ignores nullish params", () => {
orderings: undefined,
}),
),
).toBe("https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref")
).toBe(
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref${xClientVersionParam}`,
)
})

it("supports array fetch param", () => {
Expand All @@ -117,7 +122,7 @@ it("supports array fetch param", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&fetch=title,subtitle",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&fetch=title,subtitle${xClientVersionParam}`,
)
})

Expand All @@ -130,7 +135,7 @@ it("supports array fetchLinks param", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&fetchLinks=page.link,page.second_link",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&fetchLinks=page.link,page.second_link${xClientVersionParam}`,
)
})

Expand All @@ -144,7 +149,7 @@ it("supports empty orderings param", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&orderings=[]",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&orderings=[]${xClientVersionParam}`,
)

expect(
Expand All @@ -155,7 +160,7 @@ it("supports empty orderings param", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&orderings=[]",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&orderings=[]${xClientVersionParam}`,
)
})

Expand All @@ -169,7 +174,7 @@ it("supports array orderings param", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&orderings=[page.title,page.subtitle]",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&orderings=[page.title,page.subtitle]${xClientVersionParam}`,
)
})

Expand All @@ -183,7 +188,7 @@ it("supports setting direction of ordering param", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&orderings=[page.title,page.subtitle]",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&orderings=[page.title,page.subtitle]${xClientVersionParam}`,
)

expect(
Expand All @@ -198,7 +203,7 @@ it("supports setting direction of ordering param", () => {
}),
),
).toBe(
"https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&orderings=[page.title+desc,page.subtitle+desc]",
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&orderings=[page.title+desc,page.subtitle+desc]${xClientVersionParam}`,
)
})

Expand All @@ -219,7 +224,7 @@ it("supports single item routes param", () => {
).toBe(
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&routes=[${JSON.stringify(
route,
)}]`,
)}]${xClientVersionParam}`,
)
})

Expand Down Expand Up @@ -247,10 +252,28 @@ it("supports array routes param", () => {
).toBe(
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref&routes=${JSON.stringify(
routes,
)}`,
)}${xClientVersionParam}`,
)
})

it("forwards `x-c` header in production", () => {
expect(prismic.buildQueryURL(endpoint, { ref: "ref" })).toBe(
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref${xClientVersionParam}`,
)
})

it("forwards `x-c` and `x-d` headers in development", () => {
const originalEnv = { ...process.env }

process.env.NODE_ENV = "development"

expect(prismic.buildQueryURL(endpoint, { ref: "ref" })).toBe(
`https://qwerty.cdn.prismic.io/api/v2/documents/search?ref=ref${xClientVersionParam}&x-d=1`,
)

process.env = originalEnv
})

it("warns if NODE_ENV is development and a string is provided to `orderings`", () => {
const originalEnv = { ...process.env }

Expand Down
49 changes: 41 additions & 8 deletions test/client-buildQueryURL.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import { createTestClient } from "./__testutils__/createClient"
import { getMasterRef } from "./__testutils__/getMasterRef"
import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"

import { version } from "../package.json"

import type * as prismic from "../src"

const xClientVersion = `js-${version}`

it("builds a query URL using the master ref", async (ctx) => {
const repositoryResponse = ctx.mock.api.repository()
const ref = getMasterRef(repositoryResponse)
Expand All @@ -21,10 +25,9 @@ it("builds a query URL using the master ref", async (ctx) => {

const expectedSearchParams = new URLSearchParams({
ref,
"x-c": xClientVersion,
})
url.searchParams.delete("integrationFieldsRef")
url.searchParams.delete("x-c")
url.searchParams.delete("x-d")
url.searchParams.sort()
expectedSearchParams.sort()

Expand All @@ -33,6 +36,39 @@ it("builds a query URL using the master ref", async (ctx) => {
expect(url.searchParams.toString()).toBe(expectedSearchParams.toString())
})

it("builds a query URL using the master ref in development mode", async (ctx) => {
const originalEnv = { ...process.env }

process.env.NODE_ENV = "development"

const repositoryResponse = ctx.mock.api.repository()
const ref = getMasterRef(repositoryResponse)

mockPrismicRestAPIV2({
repositoryResponse,
ctx,
})

const client = createTestClient()
const res = await client.buildQueryURL()
const url = new URL(res)

const expectedSearchParams = new URLSearchParams({
ref,
"x-c": xClientVersion,
"x-d": "1",
})
url.searchParams.delete("integrationFieldsRef")
url.searchParams.sort()
expectedSearchParams.sort()

expect(url.host).toBe(new URL(client.endpoint).host)
expect(url.pathname).toBe("/api/v2/documents/search")
expect(url.searchParams.toString()).toBe(expectedSearchParams.toString())

process.env = originalEnv
})

it("includes params if provided", async (ctx) => {
const params: prismic.BuildQueryURLArgs = {
accessToken: "custom-accessToken",
Expand All @@ -51,11 +87,10 @@ it("includes params if provided", async (ctx) => {
lang: params.lang?.toString() ?? "",
// TODO: Remove when Authorization header support works in browsers with CORS.
access_token: params.accessToken ?? "",
"x-c": xClientVersion,
})

url.searchParams.delete("integrationFieldsRef")
url.searchParams.delete("x-c")
url.searchParams.delete("x-d")
url.searchParams.sort()
expectedSearchParams.sort()

Expand All @@ -82,11 +117,10 @@ it("includes default params if provided", async (ctx) => {
lang: clientConfig.defaultParams?.lang?.toString() ?? "",
// TODO: Remove when Authorization header support works in browsers with CORS.
access_token: clientConfig.accessToken ?? "",
"x-c": xClientVersion,
})

url.searchParams.delete("integrationFieldsRef")
url.searchParams.delete("x-c")
url.searchParams.delete("x-d")
url.searchParams.sort()
expectedSearchParams.sort()

Expand Down Expand Up @@ -117,11 +151,10 @@ it("merges params and default params if provided", async (ctx) => {
page: clientConfig.defaultParams?.page?.toString() ?? "",
// TODO: Remove when Authorization header support works in browsers with CORS.
access_token: clientConfig.accessToken ?? "",
"x-c": xClientVersion,
})

url.searchParams.delete("integrationFieldsRef")
url.searchParams.delete("x-c")
url.searchParams.delete("x-d")
url.searchParams.sort()
expectedSearchParams.sort()

Expand Down

0 comments on commit 4ff2bde

Please sign in to comment.