【问题标题】:Use the same class as Input and Object type in GraphQL in NestJS在 NestJS 中使用与 GraphQL 中的 Input 和 Object 类型相同的类
【发布时间】:2021-02-12 20:46:51
【问题描述】:

我正在尝试设置我的 graphql 解析器来处理一组对象,但无法配置 @Args 装饰器。

我创建了自己的 ArgsType

import { ArgsType, Field, Int, ObjectType } from '@nestjs/graphql';

@ArgsType()  // to be used as type in the resolver
@ObjectType()  // for schema generation 
export class Club {
 @Field(type => String)
 president: string;

 @Field(type => Int)
 members?: number;
}

添加单个俱乐部的解析器工作得很好!

 @Query(() => Int)
 async addClub(@Args() club: Club) {
  // handle stuff
  }

但是如果我想给一个这样的俱乐部数组

 @Query(() => Int)
   async addClubs(@Args({name: 'clubs', type: () => [Club]}) clubs: Array<Club>) {
   // handle stuff
  }

nest 启动时会报错

 UnhandledPromiseRejectionWarning: Error: Cannot determine a GraphQL input type for the "clubs". Make sure your class is decorated with an appropriate decorator.

虽然我可以使用这样的字符串数组

 @Query(() => [String])
 async addStrings(@Args({ name: 'clubs', type: () => [String], }) clubs: Array<string>) {
  // handle stuff
  }

我很确定应该有一个简单的解决方案,但不知道从哪里开始。

【问题讨论】:

    标签: typescript graphql nestjs


    【解决方案1】:

    根据错误,

    Cannot determine a GraphQL input type for the "clubs". Make sure your class is decorated with an appropriate decorator
    

    您尝试将 Club 类用作 GraphQL 输入类型,而它已经是对象类型(根据您使用的 @ObjectType 注释)。


    解决方案 1:

    我建议您编写一个单独的 GraphQL 输入类型,如下所示(未经测试)。如果您需要分离处理Club 的输入和输出的方式,这会更简洁且耦合更少。

    import { InputType, Field } from '@nestjs/graphql';
    
    @InputType()
    export class ClubInput {
     @Field()
     president: string;
    
     @Field()
     members?: number;
    }
    

    然后在你的解析器中,你可以像下面这样使用它。

    @Query(() => Int)
    async addClubs(@Args({name: 'clubs', type: () => [ClubInput]}) clubs: Array<ClubInput>) {
     // handle stuff
    }
    

    解决方案 2:

    但如果您确实需要为这两个目的使用同一个类,您可以尝试使用相同的Club 名称创建输入和对象类型。默认情况下,对象类型的名称是类的名称。因此,您需要明确提供名称以避免冲突。

    import { Field, Int, ObjectType, InputType } from '@nestjs/graphql';
    
    @InputType("ClubInput")
    @ObjectType("ClubType")
    export class Club {
     @Field(type => String)
     president: string;
    
     @Field(type => Int)
     members?: number;
    }
    

    现在您的Club 具有不同的输入和对象类型名称。然后在你的解析器中,你可以像下面这样使用它。

    @Query(() => Int)
    async addClubs(@Args({name: 'clubs', type: () => [ClubInput]}) clubs: Array<ClubInput>) {
     // handle stuff
    }
    

    注意:在此解决方案中,您需要确保Club 永远不会包含表示循环引用或对接口和联合的引用的字段。如果发生这种情况,您将不得不转到解决方案 1,否则这会使您的输入引发错误。


    结论是,在 Typescript GraphQL 中,InputTypeObjectType 是两个不同的概念,我们需要正确使用它以避免任何问题。

    【讨论】:

    • 哇,感谢您的详尽解释。所以基本上是我试图使用螺丝刀作为锤子 xD 没有时间尝试,但是在检查了关于 graphql 突变的nestjs 文档之后,我确信这就是解决方案。我会坚持解决方案 1,因为这是常见的做法,而且我的情况并不特殊
    • 请问您知道如何处理此案。我有一个InputTypeObjectType,它们的大多数属性是相同的,但它们几乎没有区别,有没有办法我可以拥有 2 个类,其中一个从另一个继承相似的属性,所以我不必定义重复两个类中的属性
    • 当然可以,你可以创建一个抽象类,把InputTypeObjectType的类似属性放在里面。然后你可以在你的 InputTypeObjectType 具体类中扩展该类。
    猜你喜欢
    • 2021-04-27
    • 1970-01-01
    • 2019-12-19
    • 2021-06-04
    • 2019-06-12
    • 2018-10-19
    • 2023-04-06
    • 2021-05-14
    • 2020-03-13
    相关资源
    最近更新 更多