假设我在创建为 Strapi 内容类型的 Author 类型架构上有“ firstName ”和“ lastName ”属性。
我可以使用 graphql 查询它们,但是如果我想查询“ fullName ”属性而不在我的内容类型上添加该字段怎么办?
由于字段不存在,现在它说:Cannot query field \"fullName\" on type \"Author\"。
如何使用附加的“虚拟”字段扩展现有类型模式?
我设法使用位于api/author/config文件夹中的schema.graphql文件中的以下代码来做到这一点:
module.exports = {
definition: `type AuthorOverride {
firstName: String
lastName: String
fullName: String
}`,
query: `
authors: [AuthorOverride]
`,
type: {
Author: false
},
resolver: {
Query: {
authors: {
description: 'Return the authors',
resolver: 'Author.find'
}
}
}
};
关键是在使用不同类型名称(AuthorOverride)的同时使用附加字段定义模式以避免重复类型错误。
此外,设置 type: { Author: false } 以便原始类型不可查询。
现在,在我的解析器函数“Author.find”(放置在我的 Author.js 控制器中)中,我可以映射 fullName 值。
如果有人有更合适的解决方案来在 Strapi 中扩展 graphql 模式,请随时发布。
刚刚找到这个帖子,也找到了合适的解决方案。这个示例 repo演示了如何使用带有自定义控制器方法和自定义 GraphQL 模式的服务函数来获得你想要的东西。我刚刚在自己的项目中实现了相同的功能。
您的案例不需要服务功能。你只需要做两件事:
fullName
属性/api/authors/config/schema.graphql.js
:module.exports = {
definition:
extend type Author {
fullName: AuthorFullName
}
type AuthorFullName {
firstName: String
lastName: String
}
`,
};
find
和findOne
控制器方法,Author
如下所示:module.exports = {
async find( ctx ) {
let entities;
if ( ctx.query._q ) {
entities = await strapi.services.author.search( ctx.query );
} else {
entities = await strapi.services.author.find( ctx.query );
}
// Add computed field `fullName` to entities.
entities.map( entity => {
entity.fullName = `${entity.firstName} ${entity.lastName}`;
return entity;
} );
return entities.map( entity => sanitizeEntity( entity, { model: strapi.models.author } ) );
},
async findOne( ctx ) {
const { id } = ctx.params;
let entity = await strapi.services.author.findOne( { id } );
if ( ! entity ) {
return ctx.notFound();
}
// Add computed field `fullName` to entity.
entity.fullName = `${entity.firstName} ${entity.lastName}`;
return sanitizeEntity( entity, { model: strapi.models.author } );
},
};
这允许 REST API 调用获取fullName
返回值,并告诉 GraphQL 也将其包含fullName
在其架构中,以便正确find
地findOne
将其传递给 GraphQL。
我希望这会有所帮助,因为我觉得我在学习了这个之后就升级了很多!
这些都不适合我。从docs看来,它们似乎已更改v4
为在全局上下文中扩展,而不是按模块/实体 ( src/api/...
)。像这样:
// src/index.js
"use strict";
module.exports = {
register({ strapi }) {
const extensionService = strapi.plugin("graphql").service("extension");
const extension = () => ({
typeDefs: `
type Author {
fullName: String
}
`,
resolvers: {
Author: {
fullName(author) {
return strapi.service("api::author.author").getFullName(author);
},
},
},
});
extensionService.use(extension);
},
};
这可能是错误的,我希望是这样。在我看来,从架构上讲,这是一个后退阶段。但是,您始终可以将此逻辑添加到每个实体文件夹(例如src/api/graphql/index.js
)中的文件中,然后将其导入此全局文件。有点像上面的服务逻辑为了保持关注点分离而发生的事情。它只是有点“手动”。
对于那些想看看什么strapi.service("api::author.author").getFullName(author)
在召唤的人:
// src/api/author/services/author.js
"use strict";
const { createCoreService } = require("@strapi/strapi").factories;
module.exports = createCoreService("api::author.author", () => ({
getFullName(author) {
return `${author.firstName} ${author.lastName}`;
},
}));