Files
payloadcms/test/helpers/NextRESTClient.ts
2024-02-19 10:03:35 -05:00

191 lines
5.3 KiB
TypeScript

import type { Where } from 'payload/types'
import type { ParsedQs } from 'qs'
import QueryString from 'qs'
import type { SanitizedConfig } from '../../packages/payload/src/config/types'
import { GRAPHQL_POST as createGraphqlPOST } from '../../packages/next/src/routes/graphql'
import {
DELETE as createDELETE,
GET as createGET,
PATCH as createPATCH,
POST as createPOST,
} from '../../packages/next/src/routes/rest'
import { devUser } from '../credentials'
type ValidPath = `/${string}`
type RequestOptions = {
auth?: boolean
file?: boolean
query?: {
depth?: number
fallbackLocale?: string
limit?: number
locale?: string
page?: number
sort?: string
where?: Where
}
}
function generateQueryString(query: RequestOptions['query'], params: ParsedQs): string {
return QueryString.stringify(
{
...(params || {}),
...(query || {}),
},
{
addQueryPrefix: true,
},
)
}
export class NextRESTClient {
private _DELETE: (request: Request, args: { params: { slug: string[] } }) => Promise<Response>
private _GET: (request: Request, args: { params: { slug: string[] } }) => Promise<Response>
private _GRAPHQL_POST: (request: Request) => Promise<Response>
private _PATCH: (request: Request, args: { params: { slug: string[] } }) => Promise<Response>
private _POST: (request: Request, args: { params: { slug: string[] } }) => Promise<Response>
private readonly config: SanitizedConfig
private token: string
serverURL: string = 'http://localhost:3000'
constructor(config: SanitizedConfig) {
this.config = config
if (config?.serverURL) this.serverURL = config.serverURL
this._GET = createGET(config)
this._POST = createPOST(config)
this._DELETE = createDELETE(config)
this._PATCH = createPATCH(config)
this._GRAPHQL_POST = createGraphqlPOST(config)
}
private buildHeaders(options: RequestInit & RequestOptions): Headers {
const defaultHeaders = {
'Content-Type': 'application/json',
}
const headers = new Headers({
...(options?.file ? {} : defaultHeaders),
...(options?.headers || {}),
})
if (options.auth !== false && this.token) {
headers.set('Authorization', `JWT ${this.token}`)
}
return headers
}
private generateRequestParts(path: ValidPath): {
params?: ParsedQs
slug: string[]
url: string
} {
const [slugs, params] = path.slice(1).split('?')
const url = `${this.serverURL}${this.config.routes.api}/${slugs}`
return {
url,
slug: slugs.split('/'),
params: params ? QueryString.parse(params) : undefined,
}
}
async DELETE(path: ValidPath, options: RequestInit & RequestOptions = {}): Promise<Response> {
const { url, slug, params } = this.generateRequestParts(path)
const { query, ...rest } = options || {}
const queryParams = generateQueryString(query, params)
const request = new Request(`${url}${queryParams}`, {
...rest,
method: 'DELETE',
headers: this.buildHeaders(options),
})
return this._DELETE(request, { params: { slug } })
}
async GET(
path: ValidPath,
options: Omit<RequestInit, 'body'> & RequestOptions = {},
): Promise<Response> {
const { url, slug, params } = this.generateRequestParts(path)
const { query, ...rest } = options || {}
const queryParams = generateQueryString(query, params)
const request = new Request(`${url}${queryParams}`, {
...rest,
method: 'GET',
headers: this.buildHeaders(options),
})
return this._GET(request, { params: { slug } })
}
async GRAPHQL_POST(options: RequestInit & RequestOptions): Promise<Response> {
const { query, ...rest } = options
const queryParams = generateQueryString(query, {})
const request = new Request(
`${this.serverURL}${this.config.routes.api}${this.config.routes.graphQL}${queryParams}`,
{
...rest,
method: 'POST',
headers: this.buildHeaders(options),
},
)
return this._GRAPHQL_POST(request)
}
async PATCH(path: ValidPath, options: RequestInit & RequestOptions): Promise<Response> {
const { url, slug, params } = this.generateRequestParts(path)
const { query, ...rest } = options
const queryParams = generateQueryString(query, params)
const request = new Request(`${url}${queryParams}`, {
...rest,
method: 'PATCH',
headers: this.buildHeaders(options),
})
return this._PATCH(request, { params: { slug } })
}
async POST(path: ValidPath, options: RequestInit & { file?: boolean } = {}): Promise<Response> {
const { url, slug, params } = this.generateRequestParts(path)
const queryParams = generateQueryString({}, params)
const request = new Request(`${url}${queryParams}`, {
...options,
method: 'POST',
headers: this.buildHeaders(options),
})
return this._POST(request, { params: { slug } })
}
async login({
slug,
credentials,
}: {
credentials?: {
email: string
password: string
}
slug: string
}): Promise<string> {
this.token = await this.POST(`/${slug}/login`, {
body: JSON.stringify(
credentials ? { ...credentials } : { email: devUser.email, password: devUser.password },
),
})
.then((res) => res.json())
.then((data) => data.token)
return this.token
}
}