GraphQL.js - 在resolveType函数中使用Interface作为默认(回退)类型

时间:2018-04-12 21:40:41

标签: javascript node.js interface graphql graphql-js

如果所提供的类型都不匹配,我正在尝试在resolveType函数中返回泛型类型。下面的示例显示了此问题: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));
});

所以现在这段代码以错误结束:

  

“抽象类型Searchable必须在运行时为字段RootQueryType.search解析为Object类型,其值为”[object Object] \“,收到”undefined“。或者Searchable类型应该提供一个”resolveType“函数或每种可能的类型应该提供一个“isTypeOf”函数。“

这并不奇怪,因为目前resolveType可能不会返回任何类型。

解决方法

包含相同字段的Crate类型,如接口SearchableType(1对1实现):

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

将其用作后备类型:

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

并将其添加到types定义中的schema

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

但是这个解决方案的问题是在这样的文档中存在这个虚拟_SearchableType

problematic _SearchableType in docs

问题

有没有办法在SearchableType中返回接口resolveType或其等价物?对我而言,关键是在文档中隐藏这种“后备类型”。

1 个答案:

答案 0 :(得分:1)

GraphQL是强类型的,并不支持泛型或某种"后备"解析联合和接口时的机制。在一天结束时,如果您的基础数据层返回了某些尚未在架构中实现的类型,那么最简单的解决方案就是将该类型添加到架构中。迁移到您的数据库和模式的更改应该齐头并进。

如果您想从存储层派生架构,我建议您查看类似PostGraphile(以前的PostGraphQL)的内容。

也就是说,如果您一直在尝试使用解决方法,那么您可以回退到现有类型之一:

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

现在,只要您在界面上查询并且不是其中一种类型,书籍的名称仍然可以访问。这种方法的唯一缺点是,将为一本书返回特定于电影的字段并将其解析为null,但这不会导致任何问题,除非它们在模式中被特别定义为非null。