GraphQL 插件
🌐 GraphQL plugin
Page summary:
GraphQL 插件添加了一个 GraphQL 端点和基于 Apollo 的沙箱,用于创建查询和变更。配置/plugins 中的选项可以让你调整深度、项目限制以及其他 Apollo Server 设置,这些内容在本指南中有详细说明。
默认情况下,Strapi 会为你的每个内容类型创建 REST 端点。GraphQL 插件会添加一个 GraphQL 端点,以获取和修改你的内容。安装 GraphQL 插件后,你可以使用基于 Apollo Server 的 GraphQL 沙箱交互式地构建查询和变更,并查看针对你的内容类型定制的文档。
🌐 By default Strapi create REST endpoints for each of your content-types. The GraphQL plugin adds a GraphQL endpoint to fetch and mutate your content. With the GraphQL plugin installed, you can use the Apollo Server-based GraphQL Sandbox to interactively build your queries and mutations and read documentation tailored to your content types.

安装
🌐 Installation
要安装 GraphQL 插件,请在终端中运行以下命令:
🌐 To install the GraphQL plugin, run the following command in your terminal:
- Yarn
- NPM
yarn add @strapi/plugin-graphql
npm install @strapi/plugin-graphql
安装完成后,GraphQL 沙箱可以通过 /graphql URL 访问,并可用于交互式地构建你的查询和变更操作,以及阅读针对你的内容类型定制的文档。
🌐 Once installed, the GraphQL sandbox is accessible at the /graphql URL and can be used to interactively build your queries and mutations and read documentation tailored to your content-types.
一旦插件安装完成,当你的 Strapi 应用服务器运行时,GraphQL Sandbox 可以通过 /graphql 路由访问(例如, localhost:1337/graphql)。
配置
🌐 Configuration
文档插件的大多数配置选项都通过你的 Strapi 项目的代码处理,尽管 GraphQL 在线运行也提供了一些非特定的 Strapi 设置。
🌐 Most configuration options for the Documentation plugin are handled via your Strapi project's code, though the GraphQL playground also offers some non-specific Strapi settings.
管理面板设置
🌐 Admin panel settings
Strapi 管理面板不提供针对 GraphQL 插件的 Strapi 特定设置。然而,可在 /graphql 路由访问的 GraphQL Playground 是一个嵌入的 Apollo Server Playground,因此它包含该实例可用的所有配置和设置。详情请参阅官方 GraphQL playground documentation 。
基于代码的配置
🌐 Code-based configuration
插件配置在 config/plugins.js 文件 中定义。该配置文件可以包含一个 graphql.config 对象,以定义 GraphQL 插件的特定配置。
🌐 Plugins configuration are defined in the config/plugins.js file. This configuration file can include a graphql.config object to define specific configurations for the GraphQL plugin.
可用选项
🌐 Available options
Apollo Server 选项可以通过 graphql.config.apolloServer 配置对象直接传递给 Apollo。Apollo Server 选项可用于例如启用 tracing feature,GraphQL Sandbox 支持该功能以跟踪查询每个部分的响应时间。Apollo Server 默认缓存选项是 cache: 'bounded'。你可以在 apolloServer 配置中更改它。更多信息请访问 Apollo Server Docs。
GraphQL 插件具有以下特定配置选项,应在 config/plugins 文件中的 graphql.config 对象内声明。所有参数都是可选的:
🌐 The GraphQL plugin has the following specific configuration options that should be declared in a graphql.config object within the config/plugins file. All parameters are optional:
| 选项 | 类型 | 描述 | 默认值 | 备注 |
|---|---|---|---|---|
endpoint | 字符串 | 设置 GraphQL 端点路径。 | '/graphql' | 示例:/custom-graphql |
shadowCRUD | 布尔值 | 启用或禁用内容类型的自动模式生成功能。 | true | |
depthLimit | 数字 | 限制 GraphQL 查询的深度以防止过度嵌套。 | 10 | 使用此选项以减轻潜在的拒绝服务(DoS)攻击。 |
amountLimit | 数字 | 限制单次响应返回的最大条目数。 | 100 | 谨慎使用以避免性能问题。 |
playgroundAlways | 布尔值 | [已弃用] 在所有环境中启用 GraphQL Playground(已弃用)。 | false | 建议改用 landingPage。 |
| “landingPage” | 布尔 |功能 | 启用或 禁用 GraphQL 的着陆页面。接受布尔值、返回布尔值的函数,或实现“renderLandingPage”的 ApolloServerPlugin。 | 生产环境中的“false”,其他环境中的“true” | |
apolloServer | 对象 | 将配置选项直接传递给 Apollo Server。 | {} | 示例: { tracing: true } |
响应返回的最大项目数量默认限制为100。可以使用 amountLimit 配置选项更改此值,但应在仔细考虑后再进行更改:大量查询可能导致DDoS(分布式拒绝服务)攻击,并可能对你的Strapi服务器以及数据库服务器造成异常负载。
🌐 The maximum number of items returned by the response is limited to 100 by default. This value can be changed using the amountLimit configuration option, but should only be changed after careful consideration: a large query can cause a DDoS (Distributed Denial of Service) and may cause abnormal load on your Strapi server, as well as your database server.
GraphQL 沙盒在所有环境中默认启用,但生产环境除外。将 landingPage 配置选项设置为 true,即可在生产环境中也启用 GraphQL 沙盒。
🌐 The GraphQL Sandbox is enabled by default in all environments except production. Set the landingPage configuration option to true to also enable the GraphQL Sandbox in production environments.
以下是自定义配置示例:
🌐 The following is an example custom configuration:
- JavaScript
- TypeScript
module.exports = {
graphql: {
config: {
endpoint: '/graphql',
shadowCRUD: true,
landingPage: false, // disable Sandbox everywhere
depthLimit: 7,
amountLimit: 100,
apolloServer: {
tracing: false,
},
},
},
};
export default () => ({
graphql: {
config: {
endpoint: '/graphql',
shadowCRUD: true,
landingPage: false, // disable Sandbox everywhere
depthLimit: 7,
amountLimit: 100,
apolloServer: {
tracing: false,
},
},
},
})
动态启用 Apollo Sandbox
🌐 Dynamically enable Apollo Sandbox
你可以使用一个函数根据环境动态启用 Apollo Sandbox:
🌐 You can use a function to dynamically enable Apollo Sandbox depending on the environment:
- JavaScript
- TypeScript
module.exports = ({ env }) => {
graphql: {
config: {
endpoint: '/graphql',
shadowCRUD: true,
landingPage: (strapi) => {
if (env("NODE_ENV") !== "production") {
return true;
} else {
return false;
}
},
},
},
};
export default ({ env }) => {
graphql: {
config: {
endpoint: '/graphql',
shadowCRUD: true,
landingPage: (strapi) => {
if (env("NODE_ENV") !== "production") {
return true;
} else {
return false;
}
},
},
},
};
登录页面的 CORS 异常
🌐 CORS exceptions for Landing Page
如果在生产环境中启用了登录页面(不推荐),则必须手动添加 Apollo Server 登录页面的 CORS 标头。
🌐 If the landing page is enabled in production environments (which is not recommended), CORS headers for the Apollo Server landing page must be added manually.
要全局添加它们,你可以将以下内容合并到中间件配置中:
🌐 To add them globally, you can merge the following into your middleware configuration:
{
name: "strapi::security",
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
"connect-src": ["'self'", "https:", "apollo-server-landing-page.cdn.apollographql.com"],
"img-src": ["'self'", "data:", "blob:", "apollo-server-landing-page.cdn.apollographql.com"],
"script-src": ["'self'", "'unsafe-inline'", "apollo-server-landing-page.cdn.apollographql.com"],
"style-src": ["'self'", "'unsafe-inline'", "apollo-server-landing-page.cdn.apollographql.com"],
"frame-src": ["sandbox.embed.apollographql.com"]
}
}
}
}
要仅为 /graphql 路径添加这些例外(推荐),你可以创建一个新的中间件来处理它。例如:
🌐 To add these exceptions only for the /graphql path (recommended), you can create a new middleware to handle it. For example:
- JavaScript
- TypeScript
module.exports = (config, { strapi }) => {
return async (ctx, next) => {
if (ctx.request.path === '/graphql') {
ctx.set('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline' cdn.jsdelivr.net apollo-server-landing-page.cdn.apollographql.com; connect-src 'self' https:; img-src 'self' data: blob: apollo-server-landing-page.cdn.apollographql.com; media-src 'self' data: blob: apollo-server-landing-page.cdn.apollographql.com; frame-src sandbox.embed.apollographql.com; manifest-src apollo-server-landing-page.cdn.apollographql.com;");
}
await next();
};
};
export default (config, { strapi }) => {
return async (ctx, next) => {
if (ctx.request.path === '/graphql') {
ctx.set('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline' cdn.jsdelivr.net apollo-server-landing-page.cdn.apollographql.com; connect-src 'self' https:; img-src 'self' data: blob: apollo-server-landing-page.cdn.apollographql.com; media-src 'self' data: blob: apollo-server-landing-page.cdn.apollographql.com; frame-src sandbox.embed.apollographql.com; manifest-src apollo-server-landing-page.cdn.apollographql.com;");
}
await next();
};
};
影子 CRUD
🌐 Shadow CRUD
为了简化和自动化 GraphQL 架构的构建,我们引入了 Shadow CRUD 功能。它会根据你的模型自动生成类型定义、查询、变更和解析器。
🌐 To simplify and automate the build of the GraphQL schema, we introduced the Shadow CRUD feature. It automatically generates the type definitions, queries, mutations and resolvers based on your models.
示例:
如果你使用 交互式 strapi generate CLI 或管理面板生成了一个名为 Document 的 API,你的模型看起来像这样:
🌐 If you've generated an API called Document using the interactive strapi generate CLI or the administration panel, your model looks like this:
{
"kind": "collectionType",
"collectionName": "documents",
"info": {
"singularName": "document",
"pluralName": "documents",
"displayName": "document",
"name": "document"
},
"options": {
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"name": {
"type": "string"
},
"description": {
"type": "richtext"
},
"locked": {
"type": "boolean"
}
}
}
生成的 GraphQL 类型和查询
# Document's Type definition
input DocumentFiltersInput {
name: StringFilterInput
description: StringFilterInput
locked: BooleanFilterInput
createdAt: DateTimeFilterInput
updatedAt: DateTimeFilterInput
publishedAt: DateTimeFilterInput
and: [DocumentFiltersInput]
or: [DocumentFiltersInput]
not: DocumentFiltersInput
}
input DocumentInput {
name: String
description: String
locked: Boolean
createdAt: DateTime
updatedAt: DateTime
publishedAt: DateTime
}
type Document {
name: String
description: String
locked: Boolean
createdAt: DateTime
updatedAt: DateTime
publishedAt: DateTime
}
type DocumentEntity {
id: ID
attributes: Document
}
type DocumentEntityResponse {
data: DocumentEntity
}
type DocumentEntityResponseCollection {
data: [DocumentEntity!]!
meta: ResponseCollectionMeta!
}
type DocumentRelationResponseCollection {
data: [DocumentEntity!]!
}
# Queries to retrieve one or multiple restaurants.
type Query {
document(id: ID): DocumentEntityResponse
documents(
filters: DocumentFiltersInput
pagination: PaginationArg = {}
sort: [String] = []
publicationState: PublicationState = LIVE
):DocumentEntityResponseCollection
}
# Mutations to create, update or delete a restaurant.
type Mutation {
createDocument(data: DocumentInput!): DocumentEntityResponse
updateDocument(id: ID!, data: DocumentInput!): DocumentEntityResponse
deleteDocument(id: ID!): DocumentEntityResponse
}
自定义
🌐 Customization
Strapi 提供了一个编程 API 来自定义 GraphQL,它允许:
🌐 Strapi provides a programmatic API to customize GraphQL, which allows:
- 为 Shadow CRUD 禁用某些操作
- 使用 getter 来返回关于允许操作的信息
- 注册和使用一个
extension对象来扩展现有的模式(例如扩展类型或定义自定义解析器、策略和中间件)
GraphQL 自定义示例
- JavaScript
- TypeScript
module.exports = {
/**
* An asynchronous register function that runs before
* your application is initialized.
*
* This gives you an opportunity to extend code.
*/
register({ strapi }) {
const extensionService = strapi.plugin('graphql').service('extension');
extensionService.shadowCRUD('api::restaurant.restaurant').disable();
extensionService.shadowCRUD('api::category.category').disableQueries();
extensionService.shadowCRUD('api::address.address').disableMutations();
extensionService.shadowCRUD('api::document.document').field('locked').disable();
extensionService.shadowCRUD('api::like.like').disableActions(['create', 'update', 'delete']);
const extension = ({ nexus }) => ({
// Nexus
types: [
nexus.objectType({
name: 'Book',
definition(t) {
t.string('title');
},
}),
],
plugins: [
nexus.plugin({
name: 'MyPlugin',
onAfterBuild(schema) {
console.log(schema);
},
}),
],
// GraphQL SDL
typeDefs: `
type Article {
name: String
}
`,
resolvers: {
Query: {
address: {
resolve() {
return { value: { city: 'Montpellier' } };
},
},
},
},
resolversConfig: {
'Query.address': {
auth: false,
},
},
});
extensionService.use(extension);
},
};
export default {
/**
* An asynchronous register function that runs before
* your application is initialized.
*
* This gives you an opportunity to extend code.
*/
register({ strapi }) {
const extensionService = strapi.plugin('graphql').service('extension');
extensionService.shadowCRUD('api::restaurant.restaurant').disable();
extensionService.shadowCRUD('api::category.category').disableQueries();
extensionService.shadowCRUD('api::address.address').disableMutations();
extensionService.shadowCRUD('api::document.document').field('locked').disable();
extensionService.shadowCRUD('api::like.like').disableActions(['create', 'update', 'delete']);
const extension = ({ nexus }) => ({
// Nexus
types: [
nexus.objectType({
name: 'Book',
definition(t) {
t.string('title');
},
}),
],
plugins: [
nexus.plugin({
name: 'MyPlugin',
onAfterBuild(schema) {
console.log(schema);
},
}),
],
// GraphQL SDL
typeDefs: `
type Article {
name: String
}
`,
resolvers: {
Query: {
address: {
resolve() {
return { value: { city: 'Montpellier' } };
},
},
},
},
resolversConfig: {
'Query.address': {
auth: false,
},
},
});
extensionService.use(extension);
},
};
在 Shadow CRUD 中禁用操作
🌐 Disabling operations in the Shadow CRUD
extension 服务与 GraphQL 插件一起提供,公开的功能可以用于禁用内容类型的操作:
🌐 The extension service provided with the GraphQL plugin exposes functions that can be used to disable operations on Content-Types:
| 内容类型功能 | 描述 | 参数类型 | 可能的参数值 || --- | --- | --- | --- || disable() | 完全禁用内容类型 | - | - || disableQueries() | 仅禁用内容类型的 查询 | - | - || disableMutations() | 仅禁用内容类型的变更 | - | - || disableAction() | 禁用内容类型的特定操作 | 字符串 | 列表中的一个值:
createfindfindOneupdatedelete
disableActions() | 禁用内容类型的特定操作 | 字符串数组 | 列表中的多个值: createfindfindOneupdatedelete
还可以在字段级别禁用操作,具有以下功能:
🌐 Actions can also be disabled at the field level, with the following functions:
| 字段功能 | 描述 || --- | --- || disable() | 完全禁用该字段 || disableOutput() | 禁用字段的输出 || disableInput() | 禁用字段的输入 || disableFilters() | 禁用字段的过滤输入 |
示例:
// Disable the 'find' operation on the 'restaurant' content-type in the 'restaurant' API
strapi
.plugin('graphql')
.service('extension')
.shadowCRUD('api::restaurant.restaurant')
.disableAction('find')
// Disable the 'name' field on the 'document' content-type in the 'document' API
strapi
.plugin('graphql')
.service('extension')
.shadowCRUD('api::document.document')
.field('name')
.disable()
使用 getter 方法
🌐 Using getters
以下 getter 可用于检索有关内容类型上允许的操作的信息:
🌐 The following getters can be used to retrieve information about operations allowed on content-types:
| 内容类型获取器 | 描述 | 参数类型 | 可能的参数值 |
|---|---|---|---|
isEnabled() | 返回内容类型是否已启用 | - | - |
isDisabled() | 返回内容类型是否被禁用 | - | - |
areQueriesEnabled() | 返回内容类型上查询是否已启用 | - | - |
areQueriesDisabled() | 返回内容类型上的查询是否被禁用 | - | - |
areMutationsEnabled() | 返回内容类型上是否启用了变更 | - | - |
areMutationsDisabled() | 返回内容类型上的变更是否被禁用 | - | - |
isActionEnabled(action) | 返回指定 action 是否在内容类型上启用 | 字符串 | 列表中的一个值:
|
isActionDisabled(action) | 返回指定 action 在内容类型中是否被禁用 | 字符串 | 列表中的一个值:
|
以下 getter 可用于检索有关字段上允许的操作的信息:
🌐 The following getters can be used to retrieve information about operations allowed on fields:
| 字段获取器 | 描述 || --- | --- || isEnabled() | 返回字段是否启用 || isDisabled() | 返回字段是否禁用 || hasInputEnabled() | 返回字段是否启用输入 || hasOutputEnabled() | 返回字段是否启用输出 || hasFiltersEnabled() | 返回字段是否启用过滤 |
扩展模式
🌐 Extending the schema
可以通过注册扩展来扩展 Content API 生成的架构。
🌐 The schema generated by the Content API can be extended by registering an extension.
此扩展,可以定义为对象或返回对象的函数,将由由 GraphQL 插件提供的 extension 服务 暴露的 use() 函数使用。
🌐 This extension, defined either as an object or a function returning an object, will be used by the use() function exposed by the extension service provided with the GraphQL plugin.
描述扩展的对象接受以下参数:
🌐 The object describing the extension accepts the following parameters:
| 参数 | 类型 | 描述 || --- | --- | --- || types | 数组 | 允许使用基于 Nexus的类型定义扩展模式类型 || typeDefs | 字符串 | 允许使用 GraphQL SDL 扩展模式类型 || plugins | 数组 | 允许使用 Nexus plugins 扩展模式 || resolvers | 对象 | 定义自定义解析器 || resolversConfig | 对象 | 定义解析器的配置选项,例如授权、策略和