chore: api handler adjustments

This commit is contained in:
Jarrod Flesch
2024-02-02 15:23:21 -05:00
parent 147def5059
commit 35b16d421e
29 changed files with 68 additions and 86 deletions

View File

@@ -5,7 +5,7 @@ import { isNumber } from 'payload/utilities'
import { generatePayloadCookie } from '../../utilities/cookies'
export const login = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const result = await loginOperation({

View File

@@ -5,7 +5,7 @@ import { generatePayloadCookie } from '../../utilities/cookies'
import { PayloadRequest } from 'payload/types'
export const resetPassword = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const result = await resetPasswordOperation({

View File

@@ -6,7 +6,7 @@ import { isNumber } from 'payload/utilities'
import { createOperation } from 'payload/operations'
export const create = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const autosave = searchParams.get('autosave') === 'true'
const draft = searchParams.get('draft') === 'true'
const depth = searchParams.get('depth')

View File

@@ -6,7 +6,7 @@ import { getTranslation } from '@payloadcms/translations'
import { deleteOperation } from 'payload/operations'
export const deleteDoc = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const where = searchParams.get('where')

View File

@@ -11,7 +11,7 @@ export const deleteByID = async ({
req: PayloadRequest
id: string
}): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const doc = await deleteByIDOperation({
id,

View File

@@ -6,7 +6,7 @@ import { isNumber } from 'payload/utilities'
import { findOperation } from 'payload/operations'
export const find = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const limit = searchParams.get('limit')

View File

@@ -11,7 +11,7 @@ export const findByID = async ({
req: PayloadRequest
id: string
}): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const result = await findByIDOperation({

View File

@@ -11,7 +11,7 @@ export const findVersionByID = async ({
req: PayloadRequest
id: string
}): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const result = await findVersionByIDOperation({

View File

@@ -11,7 +11,7 @@ export const findVersions = async ({
req: PayloadRequest
id: string
}): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const page = searchParams.get('page')
const depth = searchParams.get('depth')
const limit = searchParams.get('limit')

View File

@@ -11,7 +11,7 @@ export const restoreVersion = async ({
req: PayloadRequest
id: string
}): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const result = await restoreVersionOperation({

View File

@@ -7,7 +7,7 @@ import { updateOperation } from 'payload/operations'
import { getTranslation } from '@payloadcms/translations'
export const update = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const where = searchParams.get('where')

View File

@@ -12,7 +12,7 @@ export const updateByID = async ({
req: PayloadRequest
id: string
}): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const autosave = searchParams.get('autosave') === 'true'
const draft = searchParams.get('draft') === 'true'

View File

@@ -12,7 +12,7 @@ export const findOne = async ({
req: PayloadRequest
globalConfig: SanitizedGlobalConfig
}): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const result = await findOneOperation({

View File

@@ -14,7 +14,7 @@ export const findVersionByID = async ({
globalConfig: SanitizedGlobalConfig
id: string
}): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const result = await findVersionByIDOperationGlobal({

View File

@@ -12,7 +12,7 @@ export const findVersions = async ({
req: PayloadRequest
globalConfig: SanitizedGlobalConfig
}): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const page = searchParams.get('page')
const limit = searchParams.get('limit')
const depth = searchParams.get('depth')

View File

@@ -14,7 +14,7 @@ export const restoreVersion = async ({
globalConfig: SanitizedGlobalConfig
id: string
}): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const doc = await restoreVersionOperationGlobal({

View File

@@ -12,7 +12,7 @@ export const update = async ({
req: PayloadRequest
globalConfig: SanitizedGlobalConfig
}): Promise<Response> => {
const { searchParams } = new URL(req.url)
const { searchParams } = req
const depth = searchParams.get('depth')
const draft = searchParams.get('draft') === 'true'
const autosave = searchParams.get('autosave') === 'true'

View File

@@ -92,17 +92,15 @@ const endpoints = {
const handleCustomEndpoints = ({
entitySlug,
endpoints,
originalRequest,
payloadRequest,
}: {
entitySlug?: string
endpoints: Endpoint[]
originalRequest: Request
payloadRequest: PayloadRequest
}): Promise<Response> => {
}): Promise<Response> | Response => {
if (endpoints && endpoints.length > 0) {
let handlerParams = {}
const { pathname } = new URL(payloadRequest.url)
const { pathname } = payloadRequest
const pathPrefix =
payloadRequest.payload.config.routes.api + (entitySlug ? `/${entitySlug}` : '')
@@ -121,8 +119,8 @@ const handleCustomEndpoints = ({
if (customEndpoint) {
return customEndpoint.handler({
req: customEndpoint.root && originalRequest ? originalRequest : payloadRequest,
params: handlerParams,
req: payloadRequest,
routeParams: handlerParams,
})
}
}
@@ -134,7 +132,6 @@ export const GET = async (
request: Request,
{ params: { slug } }: { params: { slug: string[] } },
) => {
const originalRequest = request.clone()
const [slug1, slug2, slug3, slug4] = slug
try {
@@ -150,7 +147,6 @@ export const GET = async (
const customEndpointResponse = await handleCustomEndpoints({
entitySlug: slug1,
payloadRequest: req,
originalRequest,
endpoints: req.collection.config?.endpoints || [],
})
if (customEndpointResponse) return customEndpointResponse
@@ -186,7 +182,6 @@ export const GET = async (
const customEndpointResponse = await handleCustomEndpoints({
entitySlug: `${slug1}/${slug2}`,
payloadRequest: req,
originalRequest,
endpoints: globalConfig?.endpoints || [],
})
if (customEndpointResponse) return customEndpointResponse
@@ -210,7 +205,6 @@ export const GET = async (
// root routes
const customEndpointResponse = await handleCustomEndpoints({
payloadRequest: req,
originalRequest,
endpoints: req.payload.config.endpoints,
})
if (customEndpointResponse) return customEndpointResponse
@@ -230,7 +224,6 @@ export const POST = async (
request: Request,
{ params: { slug } }: { params: { slug: string[] } },
) => {
const originalRequest = request.clone()
const [slug1, slug2, slug3, slug4] = slug
try {
@@ -240,7 +233,6 @@ export const POST = async (
const customEndpointResponse = await handleCustomEndpoints({
entitySlug: slug1,
payloadRequest: req,
originalRequest,
endpoints: req.collection.config?.endpoints || [],
})
if (customEndpointResponse) return customEndpointResponse
@@ -276,7 +268,6 @@ export const POST = async (
const customEndpointResponse = await handleCustomEndpoints({
entitySlug: `${slug1}/${slug2}`,
payloadRequest: req,
originalRequest,
endpoints: globalConfig?.endpoints || [],
})
if (customEndpointResponse) return customEndpointResponse
@@ -299,7 +290,6 @@ export const POST = async (
// root routes
const customEndpointResponse = await handleCustomEndpoints({
payloadRequest: req,
originalRequest,
endpoints: req.payload.config.endpoints,
})
if (customEndpointResponse) return customEndpointResponse
@@ -313,7 +303,6 @@ export const DELETE = async (
request: Request,
{ params: { slug } }: { params: { slug: string[] } },
) => {
const originalRequest = request.clone()
const [slug1, slug2] = slug
try {
@@ -329,7 +318,6 @@ export const DELETE = async (
const customEndpointResponse = await handleCustomEndpoints({
entitySlug: slug1,
payloadRequest: req,
originalRequest,
endpoints: req.collection.config?.endpoints || [],
})
if (customEndpointResponse) return customEndpointResponse
@@ -348,7 +336,6 @@ export const DELETE = async (
// root routes
const customEndpointResponse = await handleCustomEndpoints({
payloadRequest: req,
originalRequest,
endpoints: req.payload.config.endpoints,
})
if (customEndpointResponse) return customEndpointResponse
@@ -362,7 +349,6 @@ export const PATCH = async (
request: Request,
{ params: { slug } }: { params: { slug: string[] } },
) => {
const originalRequest = request.clone()
const [slug1, slug2] = slug
try {
@@ -378,7 +364,6 @@ export const PATCH = async (
const customEndpointResponse = await handleCustomEndpoints({
entitySlug: slug1,
payloadRequest: req,
originalRequest,
endpoints: req.collection.config?.endpoints || [],
})
if (customEndpointResponse) return customEndpointResponse
@@ -397,7 +382,6 @@ export const PATCH = async (
// root routes
const customEndpointResponse = await handleCustomEndpoints({
payloadRequest: req,
originalRequest,
endpoints: req.payload.config.endpoints,
})
if (customEndpointResponse) return customEndpointResponse

View File

@@ -82,6 +82,8 @@ export const createPayloadRequest = async ({
transactionID: undefined,
payloadDataLoader: undefined,
payloadUploadSizes: {},
searchParams,
pathname,
}
const req: PayloadRequest = Object.assign(request, customRequest)

View File

@@ -1,7 +1,5 @@
import type { NextFunction, Response } from 'express'
import { URL } from 'url'
import type { SanitizedCollectionConfig } from '../collections/config/types'
import type { PayloadRequest } from '../types'
import type { Where } from '../types'
@@ -17,7 +15,7 @@ const getExecuteStaticAccess =
}
try {
const { pathname } = new URL(req.url)
const { pathname } = req
if (pathname) {
const accessResult = await executeAccess({ req }, config.access.read)

View File

@@ -1,5 +1,4 @@
import jwt from 'jsonwebtoken'
import { URL } from 'url'
import type { Collection } from '../../collections/config/types'
import type { PayloadRequest } from '../../types'
@@ -28,8 +27,8 @@ export const meOperation = async ({
}
if (req.user) {
const parsedURL = new URL(req.url)
const isGraphQL = parsedURL.pathname === `/api${req.payload.config.routes.graphQL}`
const { pathname } = req
const isGraphQL = pathname === `/api${req.payload.config.routes.graphQL}`
const user = (await req.payload.findByID({
id: req.user.id,

View File

@@ -435,7 +435,7 @@ export interface SanitizedCollectionConfig
'auth' | 'endpoints' | 'fields' | 'upload' | 'versions'
> {
auth: Auth
endpoints: Omit<Endpoint, 'root'>[] | false
endpoints: Endpoint[] | false
fields: Field[]
upload: Upload
versions: SanitizedCollectionVersions

View File

@@ -197,13 +197,15 @@ export type Access<T = any, U = any> = (
) => AccessResult | Promise<AccessResult>
/** Equivalent to express middleware, but with an enhanced request object */
export type PayloadHandler<T = PayloadRequest | Request> = ({
params,
export type PayloadHandler = ({
req,
routeParams,
}: {
params: Record<string, unknown>
req: T
}) => Promise<Response>
req: PayloadRequest
routeParams: {
[key: string]: string
}
}) => Promise<Response> | Response
/**
* Docs: https://payloadcms.com/docs/rest-api/overview#custom-endpoints
@@ -211,7 +213,12 @@ export type PayloadHandler<T = PayloadRequest | Request> = ({
export type Endpoint = {
/** Extension point to add your custom data. */
custom?: Record<string, any>
handler: PayloadHandler<PayloadRequest>
/**
* Middleware that will be called when the path/method matches
*
* Compatible with Web Request/Response Model
*/
handler: PayloadHandler
/** HTTP method (or "all") */
method: 'connect' | 'delete' | 'get' | 'head' | 'options' | 'patch' | 'post' | 'put'
/**
@@ -220,34 +227,14 @@ export type Endpoint = {
* Compatible with the Express router
*/
path: string
} & (
| {
/**
* Middleware that will be called when the path/method matches
*
* Compatible with Express middleware
*/
handler: PayloadHandler<PayloadRequest>
/**
* Set to `true` to disable the Payload middleware for this endpoint
* @default false
*/
root?: false | undefined
}
| {
/**
* Middleware that will be called when the path/method matches
*
* Compatible with Express middleware
*/
handler: PayloadHandler<Request>
/**
* Set to `true` to disable the Payload middleware for this endpoint
* @default false
*/
root: true
}
)
/**
* @deprecated in 3.0
*
* Please add "root" routes under the /api folder in the Payload Project.
* https://nextjs.org/docs/app/api-reference/file-conventions/route
*/
root: never
}
export type AdminViewConfig = {
Component: AdminViewComponent

View File

@@ -199,7 +199,7 @@ export type GlobalConfig = {
export interface SanitizedGlobalConfig
extends Omit<DeepRequired<GlobalConfig>, 'endpoints' | 'fields' | 'versions'> {
endpoints: Omit<Endpoint, 'root'>[] | false
endpoints: Endpoint[] | false
fields: Field[]
versions: SanitizedGlobalVersions
}

View File

@@ -48,6 +48,13 @@ export type CustomPayloadRequest<U = any> = {
* Only available for localized collections
*/
locale?: string
/**
* The URL path of the request
*/
pathname: null | string
/**
* The payload object
*/
payload: typeof payload
/**
* The context in which the request is being made
@@ -57,6 +64,10 @@ export type CustomPayloadRequest<U = any> = {
payloadDataLoader?: DataLoader<string, TypeWithID>
/** Resized versions of the image that was uploaded during this request */
payloadUploadSizes?: Record<string, Buffer>
/**
* The search parameters from the request URL
*/
searchParams: URLSearchParams
/** Translate function - duplicate of i18n.t */
t: TFunction
/**

View File

@@ -6,7 +6,6 @@ import mkdirp from 'mkdirp'
import path from 'path'
import sanitize from 'sanitize-filename'
import sharp from 'sharp'
import { URL } from 'url'
import type { Collection } from '../collections/config/types'
import type { SanitizedConfig } from '../config/types'
@@ -54,7 +53,7 @@ export const generateFileData = async <T>({
let file = req.file
const { searchParams } = new URL(req.url)
const { searchParams } = req
const uploadEdits = searchParams.get('uploadEdits') || {}
const { disableLocalStorage, formatOptions, imageSizes, resizeOptions, staticDir, trimOptions } =

View File

@@ -55,6 +55,8 @@ export const createLocalReq: CreateLocalReq = (
req.user = user || req?.user || null
req.collection = collection ? payload.collections?.[collection] : null
req.payloadDataLoader = req?.payloadDataLoader || getDataLoader(req)
req.searchParams = req?.searchParams || new URLSearchParams()
req.pathname = req?.pathname || null
return req
}

View File

@@ -8,7 +8,7 @@ export async function getFilePrefix({
req: PayloadRequest
}): Promise<string> {
const imageSizes = (collection?.upload as IncomingUploadType)?.imageSizes || []
const { searchParams } = new URL(req.url)
const { searchParams } = req
const filename = searchParams.get('filename')
const files = await req.payload.find({

View File

@@ -1,13 +1,13 @@
'use client'
import { Modal, useModal } from '@faceless-ui/modal'
import React, { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import type { Props, TogglerProps } from './types'
import { Gutter } from '../Gutter'
import { EditDepthContext, useEditDepth } from '../../providers/EditDepth'
import { X } from '../../icons/X'
import { useTranslation } from '../..'
import './index.scss'
@@ -51,7 +51,7 @@ export const Drawer: React.FC<Props> = ({
slug,
title,
}) => {
const { t } = useTranslation('general')
const { t } = useTranslation()
const { closeModal, modalState } = useModal()
const drawerDepth = useEditDepth()
const [isOpen, setIsOpen] = useState(false)
@@ -84,7 +84,7 @@ export const Drawer: React.FC<Props> = ({
>
{(!drawerDepth || drawerDepth === 1) && <div className={`${baseClass}__blur-bg`} />}
<button
aria-label={t('close')}
aria-label={t('general:close')}
className={`${baseClass}__close`}
id={`close-drawer__${slug}`}
onClick={() => closeModal(slug)}
@@ -104,7 +104,7 @@ export const Drawer: React.FC<Props> = ({
i.e. changing to a `div` element will fix the animation issue but will break accessibility
*/}
<button
aria-label={t('close')}
aria-label={t('general:close')}
className={`${baseClass}__header__close`}
id={`close-drawer__${slug}`}
onClick={() => closeModal(slug)}