2

我是 GraphQL 新手,目前正在尝试为现有库构建 api。

我有标签,它们有一个唯一的别名、一个可以是不同类型的值和一些属性

为了处理不同的类型,我定义了一个包含别名属性的接口以及 4 个具有不同类型字段的实现。

GraphQL 架构如下:

schema {
  query: Query
  mutation: Mutation
}

type Query {
    allTags: [Tag!]
    tags(aliases: [ID!]!): [Tag]
    tag(alias: ID!): Tag
}

interface Tag {
    alias: ID! @isUnique
    properties: [TagProperty]
}

type StringTag implements Tag {
    alias: ID! @isUnique
    properties: [TagProperty]
    value: String
}

type IntegerTag implements Tag {
    alias: ID! @isUnique
    properties: [TagProperty]
    value: Int
}

type FloatTag implements Tag {
    alias: ID! @isUnique
    properties: [TagProperty]
    value: Float
}

type BooleanTag implements Tag {
    alias: ID! @isUnique
    properties: [TagProperty]
    value: Boolean
}

type TagProperty {
    name: String!
    value: String!
}

在 C# 中的接口实现中,我想按照 graphql-dotnet 入门文档中的建议使用ResolveType 。

接口实现代码:

public TagInterface(
    BooleanTag booleanTag, 
    IntegerTag integerTag, 
    FloatTag floatTag, 
    StringTag stringTag)
{
    Name = "Tag";
    Description = "A resource which points to a value";

    Field<IdGraphType>(
        "alias",
        "the unique alias of the tag"
    );
    Field<ListGraphType<TagPropertyType>>(
        "properties",
        "the properties of a tag defined in the config XML"
    );

    ResolveType = obj =>
    {
        if (obj is HtTag)
        {
            switch ((obj as HtTag).DataType) {
                case EDataType.Bool:

                    return booleanTag;

                case EDataType.Byte:
                case EDataType.Sbyte:
                case EDataType.Short:
                case EDataType.Ushort:
                case EDataType.Int:
                case EDataType.Uint:
                case EDataType.Long:
                case EDataType.Ulong:
                    return integerTag;

                case EDataType.Double:
                case EDataType.Float:
                case EDataType.Decimal:
                    return floatTag;

                default:
                    return stringTag;
            }
        }

        throw new ArgumentOutOfRangeException($"Could not resolve graph type for {obj.GetType().Name}");
    };
}

}

当我运行以下查询时

query {
    tags(aliases:["TagID_S1A02_IN","TagID_S1A03_IN"]) {
      __typename
      alias
      ... on StringTag {
        value
        }
      ... on IntegerTag {
        value
        }
      ... on BooleanTag {
        value
        }
      ... on FloatTag {
        value
        }
    }
}

我收到以下错误:

{
    "errors": [
        {
            "message": "Für dieses Objekt wurde kein parameterloser Konstruktor definiert."
        }
    ]
}

这似乎是因为接口定义中的 4 个构造函数参数(根据文档中的示例)。如果我new StringTag()在 ResolveType 实现中删除它们并返回等,我会得到正确数量的结果,但没有内容:

{
    "data": {
        "tags": [
            {
                "__typename": "StringTag",
                "alias": null,
                "value": null
            },
            {
                "__typename": "StringTag",
                "alias": null,
                "value": null
            }
        ]
    }
}

谁能指出我在这里做错了什么?

更新

我通过使用无参数构造函数并返回解析的对象,如下所示:

ResolveType = obj =>
    {
        if (obj is HtTag)
        {
            switch ((obj as HtTag).DataType) {
                case EDataType.Bool:
                    return (from t in PossibleTypes where t is BooleanTag select t).First();

                case EDataType.Byte:
                case EDataType.Sbyte:
                case EDataType.Short:
                case EDataType.Ushort:
                case EDataType.Int:
                case EDataType.Uint:
                case EDataType.Long:
                case EDataType.Ulong:
                    return (from t in PossibleTypes where t is IntegerTag select t).First();

                case EDataType.Double:
                case EDataType.Float:
                case EDataType.Decimal:
                    return (from t in PossibleTypes where t is FloatTag select t).First();

                default:
                    return (from t in PossibleTypes where t is StringTag select t).First();
            }
        }

        throw new ArgumentOutOfRangeException($"Could not resolve graph type for {obj.GetType().Name}");
    };

这是它应该使用的方式吗?

4

1 回答 1

1

为了能够解析您的TagInterface类型,您需要使用某种形式的依赖注入。您TagInterface和所有其他GraphType模式类型都需要在您的 DI 容器中注册。

如果使用 2.0 预发行版,请使用以下(.NET Core 示例):

services.AddSingleton<ISchema>(
  s => new StarWarsSchema(new FuncDependencyResolver(type => (IGraphType)s.GetRequiredService(type))));

https://github.com/graphql-dotnet/graphql-dotnet/blob/master/src/GraphQL.GraphiQLCore/Startup.cs#L29

旧版本您可以直接使用 func (.NET Core 示例):

services.AddSingleton<ISchema>(
  s => new StarWarsSchema(type => (IGraphType)s.GetRequiredService(type)));

有关更多信息,请参阅这些文档(尚未更新到 2.0 alpha):

https://graphql-dotnet.github.io/docs/getting-started/dependency-injection

如果这些标签类型没有在您的架构中的其他地方公开公开,您可能还需要使用RegisterTypeon注册这些标签类型。Schema

构建 Schema 时,它会查看“根”类型(Query、Mutation、Subscription)并收集它们公开的所有 GraphType。通常,当您使用接口类型时,具体类型不会在根类型(或其任何子类型)上公开。由于这些具体类型从未在类型图中公开,因此 Schema 不知道它们存在。这就是 Schema 上的 RegisterType<> 方法的用途。通过使用 RegisterType<>,它告诉 Schema 特定类型,并在初始化 Schema 时将其正确添加到接口类型上的 PossibleTypes 集合中。

https://graphql-dotnet.github.io/docs/getting-started/interfaces#registertype

于 2017-11-16T04:30:28.690 回答