Strapi - 如何使用自定义属性扩展 graphql 类型模式?

Posted

技术标签:

【中文标题】Strapi - 如何使用自定义属性扩展 graphql 类型模式?【英文标题】:Strapi - How to extend graphql type schema with custom property? 【发布时间】:2020-02-28 13:40:28 【问题描述】:

假设我在创建为 Strapi 内容类型的作者类型架构上具有“firstName”和“lastName”属性。

我可以使用 graphql 查询它们,但是如果我想查询 'fullName' 属性而不在我的内容类型上添加该字段怎么办?

由于字段不存在,现在它显示:Cannot query field \"fullName\" on type \"Author\"

如何使用附加的“虚拟”字段扩展现有类型架构?

【问题讨论】:

【参考方案1】:

我设法在 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 架构有更合适的解决方案,请随时发布。

【讨论】:

【参考方案2】:

刚刚找到这篇文章,也找到了合适的解决方案。这个example repo 演示了如何使用带有自定义控制器方法和自定义 GraphQL 模式的服务函数来获得你想要的。我刚刚在自己的项目中实现了相同的功能。

您的案例不需要服务功能。你只需要做两件事:

    /api/authors/config/schema.graphql.js 中定义fullName 属性,如下所示:
module.exports = 
  definition:
    extend type Author 
      fullName: AuthorFullName
    

    type AuthorFullName 
      firstName: String
      lastName: String
    
  `,
;
    接下来,您需要为Author 覆盖findfindOne 控制器方法,如下所示:
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,以便 findfindOne 可以正确地将其传递给 GraphQL。

我希望这会有所帮助,因为我觉得在学习了这些之后我的等级提升了很多!

【讨论】:

这是金子!我也觉得学了这个就升级了!!!!!!谢谢@wavematt【参考方案3】:

这些都不适合我。从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`;
  ,
));

【讨论】:

以上是关于Strapi - 如何使用自定义属性扩展 graphql 类型模式?的主要内容,如果未能解决你的问题,请参考以下文章

Strapi 自定义路由重定向到公共目录

Strapi / Nuxt - 找不到自定义路线

包含的自定义过滤器-strapi

除了id,如何在strapi中设置主键?

如何使用自定义属性扩展 IdentityUser

如何在登录时在 JWT 令牌中从 Azure Active Directory 传递自定义扩展属性?