GraphQL模式定义语言中的别名类型

GraphQL模式定义语言中的别名类型,graphql,graphql-js,apollo-server,Graphql,Graphql Js,Apollo Server,我现在在生产中有以下graphql模式定义: type BasketPrice { amount: Int! currency: String! } type BasketItem { id: ID! price: BasketPrice! } type Basket { id: ID! items: [BasketItem!]! total: BasketPrice! } type Query { basket(id: String!): Ba

我现在在生产中有以下graphql模式定义:

type BasketPrice {
  amount: Int!
  currency: String!
}

type BasketItem {
   id: ID!
   price: BasketPrice!
}

type Basket {
   id: ID!
   items: [BasketItem!]!
   total: BasketPrice!
}

type Query {
   basket(id: String!): Basket!
}
我想将
BasketPrice
重命名为just
Price
,但是这样做会对模式造成破坏性的更改,因为客户端可能在片段中引用它,例如

fragment Price on BasketPrice {
   amount
   currency
}

query Basket {
   basket(id: "123") {
      items {
         price {
            ...Price
         }
      }
      total {
         ...Price
      }
   }
}
我曾希望有可能将其命名为向后兼容性,例如

type Price {
  amount: Int!
  currency: String!
}

# Remove after next release.
type alias BasketPrice = Price;

type BasketPrice {
  amount: Int!
  currency: String!
}

type BasketItem {
   id: ID!
   price: BasketPrice!
}

type Basket {
   id: ID!
   items: [BasketItem!]!
   total: BasketPrice!
}

type Query {
   basket(id: String!): Basket!
}

但这似乎不是一个功能。是否有一种建议的方法可以安全地重命名graphql中的类型而不引起中断更改?

由于您已经指定的原因,如果类型没有中断更改,则无法重命名该类型。重命名类型是一种表面的更改,而不是功能性的更改,因此没有实际的理由这样做

处理对模式的任何破坏性更改的最佳方法是在不同端点上公开新模式,然后将客户端转换为使用新端点,从而有效地实现API的版本控制

我能想到的解决此问题的唯一其他方法是为使用旧类型的任何字段创建新字段,例如:

type BasketItem {
   id: ID!
   price: BasketPrice! @ deprecated(reason: "Use itemPrice instead")
   itemPrice: Price!
}

type Basket {
   id: ID!
   items: [BasketItem!]!
   total: BasketPrice! @ deprecated(reason: "Use basketTotal instead")
   basketTotal: Price!
}

我也想要这个,显然我们不能拥有它。确保名称随着时间的推移反映实际的语义对于正在进行的项目非常重要——这是文档的一个非常重要的部分

我发现实现这一点的最好方法是多步骤的,而且相当耗费人力,但至少可以在以后保持兼容性。它涉及到在协议级别使输入字段可选,以及在应用程序级别强制实现“其中一个”的应用程序级别需求。(因为我们没有工会。)

将其更改为以下内容:

input OldThing {
   thingId: ID!
}

input NewThing {
  newId: ID!
}

input Referee {
  oldThing: OldThing @ deprecated(reason: "Use newThing instead")
  newThing: NewThing
}
实际上,所有老客户都会继续工作。您可以更新处理程序代码以始终生成新内容,然后在需要时使用过程字段解析器将其复制到oldThing(取决于您使用的框架)。在输入时,您可以更新处理程序以始终在收到时将旧内容转换为新内容,并且仅在代码中使用新内容。如果两个元素都不存在,您还必须手动返回错误


在某个时候,客户端将全部更新,您可以删除不推荐使用的版本。

我想要重命名该类型的实际原因是为了让其他开发人员能够理解代码。如果命名并不重要,那么我只需调用每种类型T1、T2、T3等。我一直认为gql的好处在于,例如REST,您不必对API进行版本设置,因为您只需添加新字段,而不会影响使用@deprecated fields的客户机,我并不想暗示命名本身并不重要——它是重要的——但在为表达意义而重命名和为审美目的而重命名之间有一条细微的界线。但是,我可以理解,如果您想将
BasketPrice
类型的用法扩展到篮子以外的东西(例如),那么继续命名类型
BasketPrice
是不可取的。使用GraphQL可以更容易地避免版本控制,但是,有些更改正在破坏更改,如果您想要实现这些更改,版本控制是非常必要的。虽然你不能像反对字段那样反对类型,但重命名字段和重命名类型一样是一个破坏性的改变。@Riscarott更新了答案,因为从技术上讲,有另一种方法可以绕过这个限制,而不破坏模式。我想“没有实际的理由重命名东西”就是错了——名字就是文档。名称通常是文档中最重要的部分!这就是为什么“命名事物”是计算机科学中两大难题之一有很多道理。
input OldThing {
   thingId: ID!
}

input NewThing {
  newId: ID!
}

input Referee {
  oldThing: OldThing @ deprecated(reason: "Use newThing instead")
  newThing: NewThing
}