简体   繁体   English

在 HotChocolate 中拼接远程 GraphQL 模式时,`StringOperationFilterInput` 已被另一种类型注册

[英]`StringOperationFilterInput` was already registered by another type, when stitching a remote GraphQL schema in HotChocolate

I have a main GraphQL project which serves Books, and a secondary project which serves Movies, both including filtering.我有一个主要的 GraphQL 项目,它服务于书籍,还有一个次要项目服务于电影,两者都包括过滤。 I'd like to add the secondary server's schema to the main one, so I can query for Movies on it by forwarding the query to the secondary.我想将辅助服务器的模式添加到主服务器,这样我就可以通过将查询转发到辅助服务器来查询电影。 I used the Schema Stitching tutorial .我使用了模式拼接教程

Without filtering it works well (I can hop onto /graphql on the main server and query for Movies), but adding [UseFiltering] to GetMovie generates an error:没有过滤效果很好(我可以跳到主服务器上的/graphql并查询电影),但是将[UseFiltering]添加到GetMovie产生错误:

The name `StringOperationFilterInput` was already registered by another type. (HotChocolate.Data.Filters.StringOperationFilterInputType)

   at HotChocolate.Configuration.TypeRegistry.Register(NameString typeName, RegisteredType registeredType)

Clearly both schemas generate types for filtering such as StringOperationFilterInput , but schema stitching doesn't want to merge them.显然,两种模式都生成用于过滤的类型,例如StringOperationFilterInput ,但模式拼接不想合并它们。 Not sure what I can do here.不知道我能在这里做什么。

Minimal example: main project Program.cs :最小示例:主项目Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient("Movies", c => c.BaseAddress = new Uri("https://localhost:7001/graphql"));
builder.Services.AddGraphQLServer()
    .AddQueryType<Query>()
    .AddRemoteSchema("Movies", ignoreRootTypes: true)
    .AddTypeExtensionsFromFile("./Stitching.graphql")
    .AddFiltering();

var app = builder.Build();
app.MapGraphQL();
app.Run();

public record Book(string Name);

public class Query
{
    [UseFiltering] public IEnumerable<Book> GetBook() => new[] { new Book("A book") };
}

Main project's Stitching.graphql :主要项目的Stitching.graphql

extend type Query {
  movies: [Movie!]! @delegate(schema: "Movies", path:"movie")
}

Secondary project Program.cs :二级项目Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseUrls("https://localhost:7001/");
builder.Services.AddGraphQLServer()
    .AddQueryType<Query>()
    .AddFiltering();

var app = builder.Build();
app.MapGraphQL();
app.Run();

public record Movie(string Name);

public class Query
{
    [UseFiltering] public IEnumerable<Movie> GetMovie() => new[] { new Movie("Die Hard") };
}

I figured it out.我想到了。 First of all, we need to add a TypeMergeHandler that skips remote types which are already registered.首先,我们需要添加一个 TypeMergeHandler 来跳过已经注册的远程类型。 Unfortunately, the duplicated types to skip have to be hardcoded, since there's no apparent way to inspect already-registered types.不幸的是,要跳过的重复类型必须进行硬编码,因为没有明显的方法来检查已经注册的类型。 I kept adding reported duplicated types based on error messages GraphQL printed.我根据打印的错误消息 GraphQL 不断添加报告的重复类型。

builder.Services.AddTypeMergeHandler<GraphqlTypeMergeHandler>()
public class GraphqlTypeMergeHandler : ITypeMergeHandler
{
    private readonly MergeTypeRuleDelegate _next;

    private readonly string[] _duplicateTypes = new[]
    {
        "ComparableNullableOfDateTimeOperationFilterInput",
        "ComparableNullableOfDecimalOperationFilterInput",
        "ComparableNullableOfInt32OperationFilterInput",
        "BooleanOperationFilterInput",
        "StringOperationFilterInput",
        "SortEnumType",
        "PageInfo",
    };

    public GraphqlTypeMergeHandler(MergeTypeRuleDelegate next) => _next = next;

    public void Merge(ISchemaMergeContext context, IReadOnlyList<ITypeInfo> types)
    {
        var typeName = types[0].Definition.Name.Value;

        if (_duplicateTypes.Contains(typeName))
            return;

        _next(context, types);
    }
}

Secondly, Stitching.graphql needs to be adjusted for filtering support, since the Movie query now includes the where parameter:其次,需要调整Stitching.graphql以支持过滤,因为Movie查询现在包含where参数:

extend type Query {
    movies(where: MovieFilterInput): [Movie!]!
    @delegate(schema: "Movies", path:"movie(where: $arguments:where)")
}

And lastly, the Book and Movie types in my example are records with positional syntax, while GraphQL types must have a parameterless constructor.最后,我示例中的BookMovie类型是具有位置语法的记录,而 GraphQL 类型必须具有无参数构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM