Apollo Graphql 模式拼接冲突

Posted

技术标签:

【中文标题】Apollo Graphql 模式拼接冲突【英文标题】:Apollo Graphql Schema Stitching Conflict 【发布时间】:2018-04-23 22:25:58 【问题描述】:

我有一个关于 GraphQL Schema 拼接的问题。 我有两个 Graphql 模式:

type Name 
   firstname: String!
   lastname: String!


type Address 
   street: String!
   number: Int!


type User 
   name: Name!
   address: Address!


type Query 
   user(userId: String!): User

type User 
   age: String!


type Query 
   user(userId: String!): User

我现在尝试使用 graphql-tools 的 mergeSchemas 功能合并模式:

const schema = mergeSchemas(
   schemas: [schema1, schema2]
);

但不是我想要实现的(扩展的用户类型):

type Name 
   firstname: String!
   lastname: String!


type Address 
   street: String!
   number: Int!


type User 
   name: Name!
   address: Address!
   age: String!


type Query 
   user(userId: String!): User

结果如下: 输入名称 名字:字符串! 姓氏:字符串!

type Address 
   street: String!
   number: Int!


type User 
   name: Name!
   address: Address!


type Query 
   user(userId: String!): User

最终架构中仅显示一个 UserType。 我尝试在mergeSchemas 中使用onTypeConflict API 来扩展类型,但我没有得到任何结果。

有没有办法通过扩展冲突类型来合并模式?

【问题讨论】:

你的目标是什么?您只能有一种用户类型。你想合并它们还是只想要第二个用户类型?在您的情况下发生的情况是默认行为采用所有具有相同名称的类型中的第一个遇到的类型。 理想情况下,我想扩展用户类型。我已经相应地编辑了我的问题。 问题是,这些不是本地模式,所以我不能轻易将type User 更改为extend type User。我使用makeRemoteExecutableSchema 获取它们 【参考方案1】:

这是一种合并对象类型的可能解决方案。也许在onTypeConflict 中按类型名称过滤而不是合并每个类型是有意义的。

import cloneDeep from 'lodash.clonedeep'
import  GraphQLObjectType  from 'graphql/type/definition'
import  mergeSchemas  from 'graphql-tools'

function mergeObjectTypes (leftType, rightType) 
  if (!rightType) 
    return leftType
  
  if (leftType.constructor.name !== rightType.constructor.name) 
    throw new TypeError(`Cannot merge with different base type. this: $leftType.constructor.name, other: $rightType.constructor.name.`)
  
  const mergedType = cloneDeep(leftType)
  mergedType.getFields() // Populate _fields
  for (const [key, value] of Object.entries(rightType.getFields())) 
    mergedType._fields[key] = value
  
  if (leftType instanceof GraphQLObjectType) 
    mergedType._interfaces = Array.from(new Set(leftType.getInterfaces().concat(rightType.getInterfaces())))
  
  return mergedType


const schema = mergeSchemas(
  schemas: [schema1, schema2],
  onTypeConflict: (leftType, rightType) => 
    if (leftType instanceof GraphQLObjectType) 
      return mergeObjectTypes(leftType, rightType)
    
    return leftType
  
)

致谢:mergeObjectTypes 函数由 Jared Wolinsky 编写。

【讨论】:

嘿!感谢您的回答,它确实尝试合并 2 个 GraphQL 用户类型,但有一个问题。当我运行代码时,它会记录一个错误,即找不到 Name 类型。我认为这是因为它在“导入”任何其他类型之前首先处理冲突。你知道如何解决这个问题吗?【参考方案2】:

这应该会有所帮助

extend type User 
   age: String!

【讨论】:

除了我没有本地架构外,我正在尝试使用 graphql-tools 拼接远程架构。

以上是关于Apollo Graphql 模式拼接冲突的主要内容,如果未能解决你的问题,请参考以下文章

使用和组合另一个公共 apollo graphql api 的最佳方式:federation v 模式拼接

Graphql - Apollo 服务器 - 热更新模式

使用mergeSchemas的Apollo Server模式拼接,如何使用来自单独模式的类型?

身份验证Apollo Graphql for android

将 GraphQL 模式拆分为 express-graphql 中不同模块的最佳方法?

GraphQL - “Federations”是普通 Graphql 的事情还是 Apollo 的事情?