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

Posted

技术标签:

【中文标题】GraphQL.js - 在 resolveType 函数中使用接口作为默认(后备)类型【英文标题】:GraphQL.js - use Interface as a default (fallback) type in resolveType function 【发布时间】:2018-09-23 04:21:57 【问题描述】:

如果没有提供的类型匹配,我将尝试在 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 可能不会返回任何类型。

解决方法

包含与接口 SearchableType 相同字段的 Crate 类型(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

问题

有没有办法返回接口SearchableTyperesolveType 中的等效接口?对我来说,关键是在文档中隐藏这种“后备类型”。

【问题讨论】:

【参考方案1】:

GraphQL 是强类型的,在解析联合和接口时不支持泛型或某种“回退”机制。归根结底,如果您的底层数据层正在返回您尚未在架构中实现的某种类型,那么最简单的解决方案就是将该类型添加到您的架构中。迁移到数据库和更改架构应该齐头并进。

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

也就是说,如果您一心想要使用解决方法,您可以回退到现有类型之一:

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

现在仍然可以访问一本书的名称,前提是您在界面上查询它而不是其中一种类型。这种方法的唯一缺点是电影特定的字段将返回一本书并解析为 null,但这不会导致任何问题,除非它们在您的架构中明确定义为非 null。

【讨论】:

以上是关于GraphQL.js - 在 resolveType 函数中使用接口作为默认(后备)类型的主要内容,如果未能解决你的问题,请参考以下文章

如何在express中实现resolveType函数/初始化graphQL服务器

如何在 Graphql.js 中使用 GraphQL 订阅

Graphql + Relay graphql-relay-js 依赖

GraphQL JS 使用 .graphql 文件从节点 js 进行查询

GraphQL.js Node/Express:如何将对象作为 GraphQL 查询参数传递

GraphQL js 文件上传