GraphQL架构定义语言中的别名类型

时间:2019-07-04 17:27:46

标签: 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!): Basket!
}

我想将BasketPrice重命名为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中的类型而不引起重大更改?

2 个答案:

答案 0 :(得分:0)

由于您已经指定的原因,如果不对类型进行重大更改,就无法重命名。重命名类型是一种表面变化,而不是功能性变化,因此没有实际的理由。

处理模式的任何重大更改的最佳方法是将新模式公开在另一个端点上,然后将客户端转换为使用新端点,从而有效地为您的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!
}

答案 1 :(得分:-1)

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

我发现做到这一点的最佳方法是多步骤,而且相当费力,但至少可以保持兼容性,直到以后。它涉及在协议级别将输入字段设置为可选,并在应用程序级别满足应用程序级别需要“其中之一”的需求。 (因为我们没有工会。)

input OldThing {
   thingId: ID!
}

input Referee {
  oldThing: OldThing!
}

将其更改为以下内容:

input OldThing {
   thingId: ID!
}

input NewThing {
  newId: ID!
}

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

实际上,所有老客户将继续工作。您可以更新处理程序代码以始终生成NewThing,然后使用过程字段解析器将其复制到oldThing(如果需要)(取决于您使用的框架。)在输入时,您可以更新处理程序以始终进行翻译旧的到新的收据,并且仅在代码中使用新的。如果两个元素都不存在,则还必须手动返回错误。

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