Skip to content

本地 API ​

Payload 本地 API 允许您在 Node 服务器上直接执行与 REST 和 GraphQL 相同的操作。在这里,您无需处理服务器延迟或网络速度问题,可以直接与数据库交互。

TIP

本地 API 在 React Server Components 和其他类似的服务器端环境中非常强大。对于其他无头 CMS,您需要通过 HTTP 层向第三方服务器请求数据,这可能会显著增加服务器渲染页面的加载时间。而在 Payload 中,您无需离开服务器即可获取所需数据,速度极快,绝对是一个革命性的改变。

以下是一些使用本地 API 的常见示例:

  • 在 React Server Components 中获取 Payload 数据
  • 通过 Node 种子脚本(seed scripts)批量导入数据
  • 开启自定义 Next.js 路由处理程序,添加额外功能的同时仍依赖 Payload
  • 在访问控制(Access Control)和钩子(Hooks)中使用

访问 Payload ​

您可以通过两种方式访问当前运行的 Payload 对象:

从参数(args)或请求(req)中访问 ​

在 Payload 内部的大多数地方,例如 Hooks(钩子)、访问控制(Access Control)、验证函数等,您可以直接从函数参数中访问 payload。这通常是最简单的方法。大多数配置函数都会接收 req(请求对象),而 req 绑定了 payload,因此可以通过 req.payload 访问它。

示例:

javascript
const afterChangeHook: CollectionAfterChangeHook = async ({
  req: { payload },
}) => {
  const posts = await payload.find({
    collection: 'posts',
  })
}

导入 Payload ​

如果您需要在无法通过函数参数或 req 访问 payload 的地方使用它,可以直接导入并初始化 Payload。

javascript
import { getPayload } from 'payload'
import config from '@payload-config'

const payload = await getPayload({ config })

如果您在 Next.js 的开发模式下工作,Payload 将支持热模块替换(HMR)。当您对 Payload 配置进行更改时,Payload 的使用方式将始终与您的更改保持同步。在生产环境中,getPayload 会自动禁用所有 HMR 功能,因此您无需更改代码,我们会在生产模式下为您优化处理。

如果您通过函数参数或 req.payload 访问 Payload,并在 Next.js 中使用它,则 HMR 将自动受到支持。

有关在 Next.js 之外使用 Payload 的更多信息,请点击这里。

本地 API 可用选项 ​

相比于 REST 或 GraphQL,您可以在本地 API 中指定更多选项,因为它们仅在服务器端执行。

选项描述
collection必填,适用于集合操作。指定要操作的集合标识(slug)。
data用于操作的数据。create 和 update 操作必填。
depth控制自动填充嵌套关系和上传字段的深度。
locale指定返回文档的语言区域。
select指定返回结果中包含哪些字段。
populate指定从关联文档中填充哪些字段。
fallbackLocale指定返回文档时使用的备用语言区域。
overrideAccess跳过访问控制。默认情况下,此属性在所有本地 API 操作中设为 true。
overrideLock默认情况下,文档锁被忽略(true)。设置为 false 时,会强制遵守锁定状态,防止其他用户操作已锁定的文档。
user如果 overrideAccess 设为 false,则可以传递用户对象以用于访问控制检查。
showHiddenFields允许返回隐藏字段。默认情况下,返回的文档会根据配置隐藏这些字段。
pagination设为 false 以返回所有文档,并避免查询文档总数。
context传递 context,它将被传递到 context 和 req.context,可供钩子读取。例如,您可以传递 triggerBeforeChange 选项,让 BeforeChange 钩子决定是否运行。
disableErrors设为 true 时,错误不会抛出。findByID 操作返回 null,find 操作返回空的 documents 数组。
disableTransaction设为 true 时,不会初始化数据库事务。

此外,每个具体操作可能还有其他可用选项,详情请参考相关文档。

事务 ​

当您的数据库使用事务时,您需要将 req 传递给所有本地操作。PostgreSQL 默认使用事务,MongoDB 在使用**副本集(replica set)**时支持事务。

即使不使用事务,传递 req 仍然是推荐的做法。

javascript
const post = await payload.find({
  collection: 'posts',
  req, // passing req is recommended
})

NOTE

默认情况下,本地 API(Local API)会禁用所有访问控制检查,但如果需要,您可以重新启用访问控制,并指定特定的用户来执行操作。

集合 ​

以下集合操作可通过本地 API 进行:

创建 ​

javascript
// The created Post document is returned
const post = await payload.create({
  collection: 'posts', // required
  data: {
    // required
    title: 'sure',
    description: 'maybe',
  },
  locale: 'en',
  fallbackLocale: false,
  user: dummyUserDoc,
  overrideAccess: true,
  showHiddenFields: false,

  // If creating verification-enabled auth doc,
  // you can optionally disable the email that is auto-sent
  disableVerificationEmail: true,

  // If your collection supports uploads, you can upload
  // a file directly through the Local API by providing
  // its full, absolute file path.
  filePath: path.resolve(__dirname, './path-to-image.jpg'),

  // Alternatively, you can directly pass a File,
  // if file is provided, filePath will be omitted
  file: uploadedFile,

  // If you want to create a document that is a duplicate of another document
  duplicateFromID: 'document-id-to-duplicate',
})

查找 ​

javascript
// Result will be a paginated set of Posts.
// See /docs/queries/pagination for more.
const result = await payload.find({
  collection: 'posts', // required
  depth: 2,
  page: 1,
  limit: 10,
  pagination: false, // If you want to disable pagination count, etc.
  where: {}, // pass a `where` query here
  sort: '-title',
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

通过 ID 查找 ​

javascript
// Result will be a Post document.
const result = await payload.findByID({
  collection: 'posts', // required
  id: '507f1f77bcf86cd799439011', // required
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

计数 ​

javascript
// Result will be an object with:
// {
//   totalDocs: 10, // count of the documents satisfies query
// }
const result = await payload.count({
  collection: 'posts', // required
  locale: 'en',
  where: {}, // pass a `where` query here
  user: dummyUser,
  overrideAccess: false,
})

通过 ID 更新 ​

javascript
// Result will be the updated Post document.
const result = await payload.update({
  collection: 'posts', // required
  id: '507f1f77bcf86cd799439011', // required
  data: {
    // required
    title: 'sure',
    description: 'maybe',
  },
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  overrideLock: false, // By default, document locks are ignored. Set to false to enforce locks.
  showHiddenFields: true,

  // If your collection supports uploads, you can upload
  // a file directly through the Local API by providing
  // its full, absolute file path.
  filePath: path.resolve(__dirname, './path-to-image.jpg'),

  // If you are uploading a file and would like to replace
  // the existing file instead of generating a new filename,
  // you can set the following property to `true`
  overwriteExistingFiles: true,
})

更新多个 ​

javascript
// Result will be an object with:
// {
//   docs: [], // each document that was updated
//   errors: [], // each error also includes the id of the document
// }
const result = await payload.update({
  collection: 'posts', // required
  where: {
    // required
    fieldName: { equals: 'value' },
  },
  data: {
    // required
    title: 'sure',
    description: 'maybe',
  },
  depth: 0,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  overrideLock: false, // By default, document locks are ignored. Set to false to enforce locks.
  showHiddenFields: true,

  // If your collection supports uploads, you can upload
  // a file directly through the Local API by providing
  // its full, absolute file path.
  filePath: path.resolve(__dirname, './path-to-image.jpg'),

  // If you are uploading a file and would like to replace
  // the existing file instead of generating a new filename,
  // you can set the following property to `true`
  overwriteExistingFiles: true,
})

删除 ​

javascript
// Result will be the now-deleted Post document.
const result = await payload.delete({
  collection: 'posts', // required
  id: '507f1f77bcf86cd799439011', // required
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  overrideLock: false, // By default, document locks are ignored. Set to false to enforce locks.
  showHiddenFields: true,
})

删除多个 ​

javascript
// Result will be an object with:
// {
//   docs: [], // each document that is now deleted
//   errors: [], // any errors that occurred, including the id of the errored on document
// }
const result = await payload.delete({
  collection: 'posts', // required
  where: {
    // required
    fieldName: { equals: 'value' },
  },
  depth: 0,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  overrideLock: false, // By default, document locks are ignored. Set to false to enforce locks.
  showHiddenFields: true,
})

认证操作 ​

如果一个集合启用了认证,将会提供额外的本地 API 操作:

认证 ​

javascript
// If you're using Next.js, you'll have to import headers from next/headers, like so:
// import { headers as nextHeaders } from 'next/headers'

// you'll also have to await headers inside your function, or component, like so:
// const headers = await nextHeaders()

// If you're using Payload outside of Next.js, you'll have to provide headers accordingly.

// result will be formatted as follows:
// {
//    permissions: { ... }, // object containing current user's permissions
//    user: { ... }, // currently logged in user's document
//    responseHeaders: { ... } // returned headers from the response
// }

const result = await payload.auth({ headers })

登录 ​

javascript
// result will be formatted as follows:
// {
//   token: 'o38jf0q34jfij43f3f...', // JWT used for auth
//   user: { ... } // the user document that just logged in
//   exp: 1609619861 // the UNIX timestamp when the JWT will expire
// }

const result = await payload.login({
  collection: 'users', // required
  data: {
    // required
    email: '[email protected]',
    password: 'rip',
  },
  req: req, // optional, pass a Request object to be provided to all hooks
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  overrideAccess: false,
  showHiddenFields: true,
})

忘记密码 ​

javascript
// Returned token will allow for a password reset
const token = await payload.forgotPassword({
  collection: 'users', // required
  data: {
    // required
    email: '[email protected]',
  },
  req: req, // pass a Request object to be provided to all hooks
})

重置密码 ​

javascript
// Result will be formatted as follows:
// {
//   token: 'o38jf0q34jfij43f3f...', // JWT used for auth
//   user: { ... } // the user document that just logged in
// }
const result = await payload.resetPassword({
  collection: 'users', // required
  data: {
    // required
    password: req.body.password, // the new password to set
    token: 'afh3o2jf2p3f...', // the token generated from the forgotPassword operation
  },
  req: req, // optional, pass a Request object to be provided to all hooks
})

解锁 ​

javascript
// Returned result will be a boolean representing success or failure
const result = await payload.unlock({
  collection: 'users', // required
  data: {
    // required
    email: '[email protected]',
  },
  req: req, // optional, pass a Request object to be provided to all hooks
  overrideAccess: true,
})

验证 ​

javascript
// Returned result will be a boolean representing success or failure
const result = await payload.verifyEmail({
  collection: 'users', // required
  token: 'afh3o2jf2p3f...', // the token saved on the user as `_verificationToken`
})

全局 ​

以下是通过本地 API 提供的全局操作:

查找 ​

javascript
// Result will be the Header Global.
const result = await payload.findGlobal({
  slug: 'header', // required
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

更新 ​

javascript
// Result will be the updated Header Global.
const result = await payload.updateGlobal({
  slug: 'header', // required
  data: {
    // required
    nav: [
      {
        url: 'https://google.com',
      },
      {
        url: 'https://payloadcms.com',
      },
    ],
  },
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  overrideLock: false, // By default, document locks are ignored. Set to false to enforce locks.
  showHiddenFields: true,
})

TypeScript ​

本地 API 调用将自动推断生成的类型。

以下是使用示例:

javascript
// Properly inferred as `Post` type
const post = await payload.create({
  collection: 'posts',

  // Data will now be typed as Post and give you type hints
  data: {
    title: 'my title',
    description: 'my description',
  },
})