本地 API

Payload Local API 让你能够在 Node 环境中直接执行与 REST 和 GraphQL 相同的操作,直接在服务器上运行。在这里,你无需处理服务器延迟或网络速度问题,可以直接与数据库交互。

提示:

Local API 在 React Server Components 和其他类似的服务器端上下文中使用时极其强大。使用其他 headless CMS 时,你需要通过 HTTP 层从第三方服务器请求数据,这会显著增加服务器渲染页面的加载时间。而使用 Payload,你无需离开服务器就能获取所需数据。这种方式可以非常快速,绝对是一个改变游戏规则的功能。

以下是使用 Local API 的一些常见场景:

  • 在 React Server Components 中获取 Payload 数据
  • 通过编写和维护的 Node 种子脚本填充数据
  • 开启自定义 Next.js 路由处理器,这些处理器具有额外功能但仍依赖 Payload
  • 访问控制钩子中使用

访问 Payload

你可以通过两种方式获取当前运行的 payload 对象:

从参数或 req 中访问

在 Payload 内部的大多数地方,你可以直接从钩子访问控制验证函数等参数中访问 payload。这是大多数情况下最简单的访问方式。大多数配置函数都接收 req (Request) 对象,其中绑定了 Payload (req.payload)。

示例:

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

导入使用

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

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 的更多信息,点击此处

可用的本地选项

由于 Local API 是在仅服务器端上下文中执行的,相比 REST 或 GraphQL,你可以指定更多选项。

Local Option描述
collection对 Collection 操作必需。指定要操作的 Collection slug。
data操作中使用的数据。createupdate 操作必需。
depth控制嵌套关系和上传字段的自动填充
locale为返回的文档指定语言环境
select指定select来控制结果中包含哪些字段。
populate指定populate来控制从填充文档中包含哪些字段到结果中。
fallbackLocale为返回的文档指定备用语言环境
overrideAccess跳过访问控制。默认情况下,所有 Local API 操作中此属性都设置为 true。
overrideLock默认情况下忽略文档锁(true)。设置为 false 可强制执行锁定,并在文档被其他用户锁定时阻止操作。更多详情
user如果将 overrideAccess 设置为 false,可以传递一个用户用于访问控制检查。
showHiddenFields选择接收隐藏字段。默认情况下,根据你的配置,它们会从返回的文档中隐藏。
pagination设置为 false 可返回所有文档并避免查询文档计数。
context上下文,将传递给 contextreq.context,可被钩子读取。如果你想向钩子传递不应成为文档部分的额外信息时很有用,例如 triggerBeforeChange 选项,BeforeChange 钩子可以读取该选项以确定是否应运行。
disableErrors设置为 true 时,不会抛出错误。相反,findByID 操作将返回 nullfind 操作将返回空文档数组。
disableTransaction设置为 true 时,不会初始化数据库事务

下面按操作类型列出了更多可用选项。

事务处理

当你的数据库使用事务时,需要将 req 传递到所有本地操作中。Postgres 使用事务,而 MongoDB 在使用副本集时也会使用事务。即使没有事务,也建议传递 req。

const post = await payload.find({
  collection: 'posts',
  req, // 建议传递 req
})

注意:

默认情况下,Local API 中所有访问控制检查都是禁用的,但你可以根据需要重新启用它们,并指定特定用户来执行操作。

集合操作

以下集合操作可通过 Local API 使用:

创建#collection-create

// 返回创建的 Post 文档
const post = await payload.create({
  collection: 'posts', // 必填
  data: {
    // 必填
    title: 'sure',
    description: 'maybe',
  },
  locale: 'en',
  fallbackLocale: false,
  user: dummyUserDoc,
  overrideAccess: true,
  showHiddenFields: false,

  // 如果创建支持验证的 auth 文档,
  // 可以选择禁用自动发送的邮件
  disableVerificationEmail: true,

  // 如果你的集合支持上传,可以通过 Local API
  // 直接上传文件,需提供完整的绝对文件路径
  filePath: path.resolve(__dirname, './path-to-image.jpg'),

  // 或者,你可以直接传递 File 对象,
  // 如果提供了 file,filePath 将被忽略
  file: uploadedFile,

  // 如果你想创建另一个文档的副本
  duplicateFromID: 'document-id-to-duplicate',
})

查询#collection-find

// 结果将是一个分页的 Posts 集合。
// 更多信息请查看 /docs/queries/pagination。
const result = await payload.find({
  collection: 'posts', // 必填
  depth: 2,
  page: 1,
  limit: 10,
  pagination: false, // 如果你想禁用分页计数等功能
  where: {}, // 在此处传递 `where` 查询条件
  sort: '-title',
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

按 ID 查询#collection-find-by-id

// 结果将是一个 Post 文档。
const result = await payload.findByID({
  collection: 'posts', // 必填
  id: '507f1f77bcf86cd799439011', // 必填
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

计数#collection-count

// 结果将是一个包含以下内容的对象:
// {
//   totalDocs: 10, // 满足查询条件的文档数量
// }
const result = await payload.count({
  collection: 'posts', // 必填
  locale: 'en',
  where: {}, // 在此处传递 `where` 查询条件
  user: dummyUser,
  overrideAccess: false,
})

按 ID 更新#collection-update-by-id

// 返回结果将是更新后的 Post 文档
const result = await payload.update({
  collection: 'posts', // 必填
  id: '507f1f77bcf86cd799439011', // 必填
  data: {
    // 必填
    title: 'sure',
    description: 'maybe',
  },
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  overrideLock: false, // 默认情况下忽略文档锁定。设置为 false 以强制执行锁定。
  showHiddenFields: true,

  // 如果你的 collection 支持上传,你可以通过 Local API
  // 直接上传文件,只需提供文件的完整绝对路径
  filePath: path.resolve(__dirname, './path-to-image.jpg'),

  // 如果你正在上传文件并希望替换现有文件
  // 而不是生成新的文件名,可以将以下属性设置为 `true`
  overwriteExistingFiles: true,
})

批量更新#collection-update-many

// 返回结果将是一个包含以下内容的对象:
// {
//   docs: [], // 每个被更新的文档
//   errors: [], // 每个错误也包含对应文档的 id
// }
const result = await payload.update({
  collection: 'posts', // 必填
  where: {
    // 必填
    fieldName: { equals: 'value' },
  },
  data: {
    // 必填
    title: 'sure',
    description: 'maybe',
  },
  depth: 0,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  overrideLock: false, // 默认情况下忽略文档锁定。设置为 false 以强制执行锁定。
  showHiddenFields: true,

  // 如果你的 collection 支持上传,你可以通过 Local API
  // 直接上传文件,只需提供文件的完整绝对路径
  filePath: path.resolve(__dirname, './path-to-image.jpg'),

  // 如果你正在上传文件并希望替换现有文件
  // 而不是生成新的文件名,可以将以下属性设置为 `true`
  overwriteExistingFiles: true,
})

删除#collection-delete

// 返回结果将是已删除的 Post 文档
const result = await payload.delete({
  collection: 'posts', // 必填
  id: '507f1f77bcf86cd799439011', // 必填
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  overrideLock: false, // 默认情况下会忽略文档锁定。设置为 false 以强制执行锁定
  showHiddenFields: true,
})

批量删除#collection-delete-many

// 返回结果将是一个包含以下内容的对象:
// {
//   docs: [], // 每个被删除的文档
//   errors: [], // 发生的任何错误,包括出错文档的 id
// }
const result = await payload.delete({
  collection: 'posts', // 必填
  where: {
    // 必填
    fieldName: { equals: 'value' },
  },
  depth: 0,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  overrideLock: false, // 默认情况下会忽略文档锁定。设置为 false 以强制执行锁定
  showHiddenFields: true,
})

认证操作

如果 collection 启用了 Authentication,将可以使用以下额外的 Local API 操作:

认证

// 如果使用 Next.js,需要从 next/headers 导入 headers,如下所示:
// import { headers as nextHeaders } from 'next/headers'

// 还需要在你的函数或组件中 await headers,如下所示:
// const headers = await nextHeaders()

// 如果在 Next.js 之外使用 Payload,需要相应地提供 headers

// 返回结果格式如下:
// {
//    permissions: { ... }, // 包含当前用户权限的对象
//    user: { ... }, // 当前登录用户的文档
//    responseHeaders: { ... } // 响应返回的 headers
// }

const result = await payload.auth({ headers, canSetHeaders: false })

登录

// 返回结果格式如下:
// {
//   token: 'o38jf0q34jfij43f3f...', // 用于身份验证的 JWT
//   user: { ... } // 刚刚登录的用户文档
//   exp: 1609619861 // JWT 过期时间的 UNIX 时间戳
// }

const result = await payload.login({
  collection: 'users', // 必填
  data: {
    // 必填
    email: 'dev@payloadcms.com',
    password: 'rip',
  },
  req: req, // 可选,传递一个 Request 对象给所有钩子
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  overrideAccess: false,
  showHiddenFields: true,
})

忘记密码

// 返回的 token 可用于重置密码
const token = await payload.forgotPassword({
  collection: 'users', // 必填
  data: {
    // 必填
    email: 'dev@payloadcms.com',
  },
  req: req, // 传递一个 Request 对象给所有钩子
})

重置密码

// 返回结果格式如下:
// {
//   token: 'o38jf0q34jfij43f3f...', // 用于身份验证的 JWT
//   user: { ... } // 刚刚登录的用户文档
// }
const result = await payload.resetPassword({
  collection: 'users', // 必填
  data: {
    // 必填
    password: req.body.password, // 要设置的新密码
    token: 'afh3o2jf2p3f...', // 从 forgotPassword 操作生成的 token
  },
  req: req, // 可选,传递一个 Request 对象给所有钩子
})

解锁

// 返回结果是一个布尔值,表示操作成功或失败
const result = await payload.unlock({
  collection: 'users', // 必填
  data: {
    // 必填
    email: 'dev@payloadcms.com',
  },
  req: req, // 可选,传递一个 Request 对象给所有钩子
  overrideAccess: true,
})

验证

// 返回结果将是一个布尔值,表示成功或失败
const result = await payload.verifyEmail({
  collection: 'users', // 必填
  token: 'afh3o2jf2p3f...', // 保存在用户上的 `_verificationToken` 令牌
})

全局数据

以下全局数据操作可通过 Local API 使用:

查找#global-find

// 结果将是 Header 全局数据。
const result = await payload.findGlobal({
  slug: 'header', // 必填
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

更新#global-update

// 结果将是更新后的 Header 全局数据。
const result = await payload.updateGlobal({
  slug: 'header', // 必填
  data: {
    // 必填
    nav: [
      {
        url: 'https://google.com',
      },
      {
        url: 'https://payloadcms.com',
      },
    ],
  },
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  overrideLock: false, // 默认情况下会忽略文档锁定。设置为 false 以强制执行锁定。
  showHiddenFields: true,
})

TypeScript

Local API 调用会自动推断你的生成类型

以下是使用示例:

// 会被正确推断为 `Post` 类型
const post = await payload.create({
  collection: 'posts',

  // 现在 data 将被类型化为 Post 并提供类型提示
  data: {
    title: 'my title',
    description: 'my description',
  },
})