UNPKG

@prismicio/client

Version:

The official JavaScript + TypeScript client library for Prismic

398 lines (349 loc) 10.8 kB
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. */ const PRISMIC_DEV_PARAM = "x-d" /** * The query parameter used to indicate the version of the client to the API. */ const PRISMIC_CLIENT_VERSION_PARAM = "x-c" /** * Create a union of the given object's values, and optionally specify which * keys to get the values from. * * Taken from the `type-fest` package. * * See: * https://github.com/sindresorhus/type-fest/blob/61c35052f09caa23de5eef96d95196375d8ed498/source/value-of.d.ts */ type ValueOf< ObjectType, ValueType extends keyof ObjectType = keyof ObjectType, > = ObjectType[ValueType] /** * An `orderings` parameter that orders the results by the specified field. * * {@link https://prismic.io/docs/rest-api-technical-reference#orderings} */ export interface Ordering { field: string direction?: "asc" | "desc" } /** * A `routes` parameter that determines how a document's URL field is resolved. * * {@link https://prismic.io/docs/route-resolver} * * @example With a document's UID field. * * ```ts * { * "type": "page", * "path": "/:uid" * } * ``` * * @example With a Content Relationship `parent` field. * * ```ts * { * "type": "page", * "path": "/:parent?/:uid", * "resolvers": { * "parent": "parent" * } * } * ``` */ export interface Route { /** * The custom type of the document. */ type: string /** * A specific UID to which this route definition is scoped. The route is only * defined for the document whose UID matches the given UID. */ uid?: string /** * A specific language to which this route definition is scoped. The route is * only defined for documents whose language matches the given language. */ lang?: string /** * The resolved path of the document with optional placeholders. */ path: string /** * An object that lists the API IDs of the Content Relationships in the route. */ resolvers?: Record<string, string> } /** * Parameters for the Prismic REST API V2. * * {@link https://prismic.io/docs/api} */ export interface QueryParams { /** * The secure token for accessing the API (only needed if your repository is * set to private). * * {@link https://prismic.io/docs/access-token} */ accessToken?: string /** * The `pageSize` parameter defines the maximum number of documents that the * API will return for your query. * * {@link https://prismic.io/docs/rest-api-technical-reference#pagesize} */ pageSize?: number /** * The `page` parameter defines the pagination for the result of your query. * * {@link https://prismic.io/docs/rest-api-technical-reference#page} */ page?: number /** * The `after` parameter can be used along with the orderings option. It will * remove all the documents except for those after the specified document in * the list. * * {@link https://prismic.io/docs/rest-api-technical-reference#after} */ after?: string /** * The `fetch` parameter is used to make queries faster by only retrieving the * specified field(s). * * {@link https://prismic.io/docs/rest-api-technical-reference#fetch} */ fetch?: string | string[] /** * The `fetchLinks` parameter allows you to retrieve a specific content field * from a linked document and add it to the document response object. * * {@link https://prismic.io/docs/rest-api-technical-reference#fetchlinks} */ fetchLinks?: string | string[] /** * The `graphQuery` parameter allows you to specify which fields to retrieve * and what content to retrieve from Linked Documents / Content * Relationships. * * {@link https://prismic.io/docs/graphquery-rest-api} */ graphQuery?: string /** * The `lang` option defines the language code for the results of your query. * * {@link https://prismic.io/docs/rest-api-technical-reference#lang} */ lang?: string /** * The `orderings` parameter orders the results by the specified field(s). You * can specify as many fields as you want. * * {@link https://prismic.io/docs/rest-api-technical-reference#orderings} * * @remarks * Strings and arrays of strings are deprecated as of * `@prismicio/client@7.0.0`. Please migrate to the more explicit array of * objects. * * @example * * ```typescript * buildQueryURL(endpoint, { * orderings: [ * { field: "my.product.price", direction: "desc" }, * { field: "my.product.title" }, * ], * }) * ``` */ // TODO: Update TSDoc with deprecated API removal in v8 orderings?: string | Ordering | (string | Ordering)[] /** * The `routes` option allows you to define how a document's `url` field is * resolved. * * {@link https://prismic.io/docs/route-resolver} */ routes?: Route | string | (Route | string)[] /** * The `brokenRoute` option allows you to define the route populated in the * `url` property for broken link or content relationship fields. A broken * link is a link or content relationship field whose linked document has been * unpublished or deleted. * * {@link https://prismic.io/docs/route-resolver} */ brokenRoute?: string } /** * Arguments for `buildQueryURL` to construct a Query URL. */ type BuildQueryURLParams = { /** * Ref used to query documents. * * {@link https://prismic.io/docs/api#refs-and-the-entry-api} */ ref: string /** * Ref used to populate integration fields with the latest content. * * {@link https://prismic.io/docs/integration-fields} */ integrationFieldsRef?: string /** * One or more filters to filter documents for the query. * * {@link https://prismic.io/docs/rest-api-technical-reference#q} */ filters?: string | string[] /** * @deprecated Renamed to `filters`. Ensure the value is an array of filters, * not a single, non-array filter. */ predicates?: string | string[] } /** * Parameters in this map have been renamed from the official Prismic REST API * V2 specification for better developer ergonomics. * * These parameters are renamed to their mapped value. */ const RENAMED_PARAMS = { accessToken: "access_token", } as const /** * A valid parameter name for the Prismic REST API V2. */ type ValidParamName = | Exclude< keyof QueryParams, keyof typeof RENAMED_PARAMS | keyof BuildQueryURLParams > | ValueOf<typeof RENAMED_PARAMS> /** * Converts an Ordering to a string that is compatible with Prismic's REST API. * If the value provided is already a string, no conversion is performed. * * @param ordering - Ordering to convert. * * @returns String representation of the Ordering. */ const castOrderingToString = (ordering: Ordering | string): string => { // TODO: Remove the following when `orderings` strings are no longer supported. if (typeof ordering === "string") { if (process.env.NODE_ENV === "development") { const [field, direction] = ordering.split(" ") const objectForm = direction === "desc" ? `{ field: "${field}", direction: "desc" }` : `{ field: "${field}" }` console.warn( `[@prismicio/client] A string value was provided to the \`orderings\` query parameter. Strings are deprecated. Please convert it to the object form: ${objectForm}. For more details, see ${devMsg( "orderings-must-be-an-array-of-objects", )}`, ) } return ordering } return ordering.direction === "desc" ? `${ordering.field} desc` : ordering.field } export type BuildQueryURLArgs = QueryParams & BuildQueryURLParams /** * Build a Prismic REST API V2 URL to request documents from a repository. The * paginated response for this URL includes documents matching the parameters. * * A ref is required to make a request. Request the `endpoint` URL to retrieve a * list of available refs. * * Type the JSON response with `Query`. * * {@link https://prismic.io/docs/api#refs-and-the-entry-api} * {@link https://prismic.io/docs/rest-api-technical-reference} * * @param endpoint - URL to the repository's REST API V2. * @param args - Arguments to filter and scope the query. * * @returns URL that can be used to request documents from the repository. */ export const buildQueryURL = ( endpoint: string, args: BuildQueryURLArgs, ): string => { const { filters, predicates, ...params } = args const url = new URL(`documents/search`, `${endpoint}/`) if (filters) { // TODO: Remove warning when we remove support for string `filters` values. if (process.env.NODE_ENV === "development" && !Array.isArray(filters)) { console.warn( `[@prismicio/client] A non-array value was provided to the \`filters\` query parameter (\`${filters}\`). Non-array values are deprecated. Please convert it to an array. For more details, see ${devMsg( "filters-must-be-an-array", )}`, ) } // TODO: Remove `castArray` when we remove support for string `filters` values. for (const filter of castArray(filters)) { url.searchParams.append("q", `[${filter}]`) } } // TODO: Remove when we remove support for deprecated `predicates` argument. if (predicates) { for (const predicate of castArray(predicates)) { url.searchParams.append("q", `[${predicate}]`) } } // Iterate over each parameter and add it to the URL. In some cases, the // parameter value needs to be transformed to fit the REST API. for (const k in params) { const name = (RENAMED_PARAMS[k as keyof typeof RENAMED_PARAMS] || k) as ValidParamName let value = params[k as keyof typeof params] if (name === "orderings") { const scopedValue = params[name] if (scopedValue != null) { // TODO: Remove the following warning when `orderings` strings are no longer supported. if ( process.env.NODE_ENV === "development" && typeof scopedValue === "string" ) { console.warn( `[@prismicio/client] A string value was provided to the \`orderings\` query parameter. Strings are deprecated. Please convert it to an array of objects. For more details, see ${devMsg( "orderings-must-be-an-array-of-objects", )}`, ) } const v = castArray(scopedValue) .map((ordering) => castOrderingToString(ordering)) .join(",") value = `[${v}]` } } else if (name === "routes") { if (typeof params[name] === "object") { value = JSON.stringify(castArray(params[name])) } } if (value != null) { url.searchParams.set( name, castArray<string | number | Route | Ordering>(value).join(","), ) } } 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() }