简体   繁体   English

GraphQL.js-使用接口作为resolveType函数中的默认(备用)类型

[英]GraphQL.js - use Interface as a default (fallback) type in resolveType function

I'm trying to return generic type in resolveType function if none of the provided types is matched. 如果提供的类型都不匹配,我试图在resolveType函数中返回泛型。 The example below shows this problem: API worked like a charm supporting UserType and MovieType until in database was added BookType (not supported by GraphQL schema). 下面的示例显示了此问题:API就像支持UserTypeMovieType一样工作,直到在数据库中添加BookType (GraphQL模式不支持)。

const {
  graphql,
  GraphQLSchema,
  GraphQLObjectType,
  GraphQLString,
  GraphQLNonNull,
  GraphQLList,
  GraphQLInterfaceType
} = require("graphql");

const DATA = [
  {
    // UserType
    name: "catherine woolf",
    nick: "catherine"
  },
  {
    // MovieType
    name: "cat woman",
    director: "Jack Wolfgang"
  },
  {
    // --- missing type --- (BookType)
    name: "cats secrets",
    author: "Nicky Glace"
  }
];

const resolveType = data => {
  if (data.nick) {
    return UserType;
  }
  if (data.director) {
    return MovieType;
  }
};

const SearchableType = new GraphQLInterfaceType({
  name: "Searchable",
  fields: {
    name: { type: GraphQLString }
  },
  resolveType: resolveType
});

const UserType = new GraphQLObjectType({
  name: "User",
  interfaces: [SearchableType],
  fields: {
    name: { type: GraphQLString },
    nick: { type: GraphQLString }
  }
});

const MovieType = new GraphQLObjectType({
  name: "Movie",
  interfaces: [SearchableType],
  fields: {
    name: { type: GraphQLString },
    director: { type: GraphQLString }
  }
});

const schema = new GraphQLSchema({
  types: [MovieType, UserType, SearchableType],
  query: new GraphQLObjectType({
    name: "RootQueryType",
    fields: {
      search: {
        type: new GraphQLList(SearchableType),
        args: {
          text: { type: new GraphQLNonNull(GraphQLString) }
        },
        resolve(_, { text }) {
          return DATA.filter(d => d.name.indexOf(text) !== -1);
        }
      }
    }
  })
});

const query = `
  {
    search(text: "cat") {
      name
      ... on User {
        nick
      }
      ... on Movie {
        director
      }
    }
  }
`;

graphql(schema, query).then(result => {
  console.log(JSON.stringify(result, null, 2));
});

So now this code ends with error: 所以现在这段代码以错误结尾:

"Abstract type Searchable must resolve to an Object type at runtime for field RootQueryType.search with value \\"[object Object]\\", received \\"undefined\\". Either the Searchable type should provide a \\"resolveType\\" function or each possible types should provide an \\"isTypeOf\\" function." “抽象类型Searchable必须在运行时解析为值为RootQueryType.search的对象类型,其值为\\“ [object Object] \\”,接收为\\“ undefined \\”。Searchable类型应提供一个\\“ resolveType \\”函数,或者每个可能的类型应提供\\“ isTypeOf \\”函数。

This is nothing surprising since currently resolveType may not return any type. 这不足为奇,因为当前resolveType可能不返回任何类型。

Workaround 解决方法

Crate type containing the same field like interface SearchableType (1 to 1 implementation): 板条箱类型包含相同的字段,例如接口SearchableType (1对1的实现):

const _SearchableType = new GraphQLObjectType({
  name: '_Searchable',
  interfaces: [SearchableType],
  fields: {
    name: { type: GraphQLString },
  }
});

Use it as a fallback type: 使用它作为后备类型:

const resolveType = data => {
  if (data.nick) {
    return UserType;
  }
  if (data.director) {
    return MovieType;
  }
  return _SearchableType;
};

And add it to types in schema definition: 并将其添加到schema定义中的types

types: [MovieType, UserType, SearchableType, _SearchableType],

But the problem with this solution is presence of this dummy _SearchableType in documentation like this: 但是此解决方案的问题是这样的伪_SearchableType在如下文档中的存在:

文档中有问题的_SearchableType

Question

Is there any way to return interface SearchableType or equivalent of it in resolveType ? 有什么方法可以返回接口SearchableTyperesolveType等效接口吗? The key point for me is hiding of this "fallback type" in a documentation. 对我而言,关键点是在文档中隐藏了这种“后备类型”。

GraphQL is strongly typed and doesn't support generics or some kind of "fallback" mechanism when resolving unions and interfaces. GraphQL是强类型的,在解决联合和接口时不支持泛型或某种“后备”机制。 At the end of the day, if your underlying data layer is returning some type that you have not yet implemented in your schema, the simplest solution is to simply add that type to your schema. 归根结底,如果您的基础数据层返回的是您尚未在架构中实现的某种类型,那么最简单的解决方案是将该类型添加到架构中。 Migrations to your database and changes to your schema should go hand-in-hand. 迁移到数据库和更改架构应该同时进行。

If you want to derive your schema from your storage layer, I would suggest looking into something like PostGraphile (formerly PostGraphQL). 如果要从存储层派生架构,建议您使用PostGraphile (以前称为PostGraphQL)之类的工具。

That said, if you're bent on using a workaround, you could just fallback to one of the existing types: 就是说,如果您打算使用一种解决方法,则可以使用现有类型之一:

const resolveType = data => {
  if (data.nick) {
    return UserType
  }
  return MovieType
}

Now a book's name will still be accessible, provided you query it on the interface and not one of the types. 现在,只要您在界面(而不是其中一种类型)上进行查询,一本书的名称仍然可以访问。 The only downside to this approach is that movie-specific fields will be returned for a book and will resolve to null, but that won't cause any issues unless they're specifically defined as non-null in your schema. 这种方法的唯一缺点是,将为书籍返回特定于电影的字段,并将其解析为null,但这不会引起任何问题,除非在您的模式中将它们明确定义为非null。

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

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