Skip to content

Commit

Permalink
feat: add initial client
Browse files Browse the repository at this point in the history
  • Loading branch information
angeloashmore committed May 4, 2021
1 parent 8bd6754 commit ee886bd
Show file tree
Hide file tree
Showing 12 changed files with 946 additions and 11 deletions.
5 changes: 4 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
"newline-before-return": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{ "argsIgnorePattern": "^_" }
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"@typescript-eslint/member-delimiter-style": [
"error",
Expand Down
35 changes: 28 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"simple-git-hooks": "^2.4.1",
"siroc": "^0.9.2",
"ts-eager": "^1.1.3",
"type-fest": "^1.0.2",
"typescript": "^4.2.4"
},
"engines": {
Expand Down
211 changes: 211 additions & 0 deletions src/buildQueryURL.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import { IterableElement, ValueOf } from 'type-fest'

import { castArray } from './lib/castArray'

/**
* Parameters for the Prismic REST API V2.
*
* @see https://prismic.io/docs/technologies/introduction-to-the-content-query-api
*/
export interface QueryParams {
/**
* The secure token for accessing the API (only needed if your repository is set to private).
*
* @see https://user-guides.prismic.io/en/articles/1036153-generating-an-access-token
*/
accessToken?: string

/**
* The `pageSize` parameter defines the maximum number of documents that the API will return for your query.
*
* @see https://prismic.io/docs/technologies/search-parameters-reference-rest-api#pagesize
*/
pageSize?: number

/**
* The `page` parameter defines the pagination for the result of your query.
*
* @see https://prismic.io/docs/technologies/search-parameters-reference-rest-api#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.
*
* @see https://prismic.io/docs/technologies/search-parameters-reference-rest-api#after
*/
after?: string

/**
* The `fetch` parameter is used to make queries faster by only retrieving the specified field(s).
*
* @see https://prismic.io/docs/technologies/search-parameters-reference-rest-api#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.
*
* @see https://prismic.io/docs/technologies/search-parameters-reference-rest-api#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.
*
* @see https://prismic.io/docs/technologies/graphquery-rest-api
*/
graphQuery?: string

/**
* The `lang` option defines the language code for the results of your query.
*
* @see https://prismic.io/docs/technologies/search-parameters-reference-rest-api#lang
*/
lang?: string

/**
* The `orderings` parameter orders the results by the specified field(s). You can specify as many fields as you want.
*
* @see https://prismic.io/docs/technologies/search-parameters-reference-rest-api#orderings
*/
orderings?: Ordering | string | (Ordering | string)[]
}

/**
* Arguments for `buildQueryURL` to construct a Query URL.
*/
type BuildQueryURLParams = {
/**
* Ref used to query documents.
*
* @see https://prismic.io/docs/technologies/introduction-to-the-content-query-api#prismic-api-ref
*/
ref: string

/**
* One or more predicates to filter documents for the query.
*
* @see https://prismic.io/docs/technologies/query-predicates-reference-rest-api
*/
predicates?: string | string[]
}

/**
* An `orderings` parameter that orders the results by the specified field.
*
* @see https://prismic.io/docs/technologies/search-parameters-reference-rest-api#orderings
*/
type Ordering = {
field: string
direction?: 'asc' | 'desc'
}

/**
* 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

/**
* Parameter keys in this list are not actual Prismic REST API V2 parameters.
* They are used for other API inputs and functionality.
*
* These parameters are *not* included in URL builder products.
*
* This list should match parameters included in `BuildQueryURLParams`.
*/
const NON_PARAM_ARGS = ['ref', 'predicates'] as const

/**
* A valid parameter name for the Prismic REST API V2.
*/
type ValidParamName =
| Exclude<
keyof QueryParams,
keyof typeof RENAMED_PARAMS | IterableElement<typeof NON_PARAM_ARGS>
>
| 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 =>
typeof ordering === 'string'
? ordering
: [ordering.field, ordering.direction].join(' ')

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`.
*
* @see https://prismic.io/docs/technologies/introduction-to-the-content-query-api#prismic-api-ref
* @see https://prismic.io/docs/technologies/query-predicates-reference-rest-api
*
* @param endpoint Endpoint to the repository's REST API.
* @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 { ref, predicates, ...params } = args

const url = new URL(`documents/search`, `${endpoint}/`)
url.searchParams.set('ref', ref)

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: string | string[] | null | undefined

switch (name) {
case 'orderings': {
const scopedValue = params[name]

if (scopedValue) {
const v = castArray(scopedValue)
.map((ordering) => castOrderingToString(ordering))
.join(',')

value = `[${v}]`
}

break
}
}

if (value != null) {
url.searchParams.set(name, castArray(value).join(','))
}
}

return url.toString()
}

0 comments on commit ee886bd

Please sign in to comment.