精通 AppSync:联合类型和接口

发布: (2026年2月12日 GMT+8 21:36)
8 分钟阅读
原文: Dev.to

I’m happy to translate the article for you, but I’ll need the actual text of the post. Could you please paste the content you’d like translated (excluding the source line you already provided)? Once I have the article text, I’ll translate it into Simplified Chinese while preserving all formatting, markdown, code blocks, and URLs.

向团队介绍 AppSync

向团队介绍 AppSync 充满挑战——尤其是当团队不熟悉 GraphQL(GQL)时。作为 AppSync APPSYNC_JS 解析器专家,你需要解释:

  • 合并的 API
  • 如何测试更改
  • GQL 类型、模式和查询 的基础

根据我的经验,大多数团队能快速掌握 GQL 基础,但他们经常 在 Union 和 Interface 类型上遇到困难

他们何时应该选择其中一种?两者有什么区别?团队真的需要它们吗?

我们真的需要接口或联合吗?

简短答案: 不,你不必使用它们。

然而,接口和联合可以让你表达在其他情况下难以捕获的模式约束。下面的示例说明了它们为何有用。

示例:错误类型

想象一种错误类型,用来告知用户其输入无效。其基本形式具有以下属性:

字段类型描述
codeString!机器可读的错误代码
messageString!人类可读的错误信息

在 GQL 中可以这样表达:

type ValidationError {
  code: String!
  message: String!
}

扩展基础错误

具体的错误变体可能会添加额外字段。考虑以下两种具体错误:

  • MissingPropertiesError – 指出缺少了哪些必填字段
  • ImproperAgeError – 指出允许的最小年龄

它们都共享 codemessage,但各自添加了自己的可选字段:

type MissingPropertiesError {
  code: String!
  message: String!
  missingProperties: [String!]   # e.g. ["firstName", "email"]
}

type ImproperAgeError {
  code: String!
  message: String!
  minimumAge: Int                # e.g. 18
}

客户端可以检查错误类型并读取额外属性以获取更详细的信息。

简单模式无法表达的内容

上述模式 未传达 missingPropertiesminimumAge互斥 的——你只能收到 一种 错误类型,而不会同时出现两者。

其他 API 描述语言(例如 OpenAPI)有 oneOf 构造来实现这一点。在 GraphQL 中,你可以使用 接口联合类型 来实现相同的排他性。

GraphQL 接口

什么是接口?

  • 在面向对象语言中,接口是类的抽象,定义实现类必须支持的方法和属性。
  • 在 GraphQL 中,接口更简单:它定义了一组字段,任何实现该接口的类型必须公开这些字段。没有方法,只有字段。

为错误定义接口

interface ValidationError {
  code: String!
  message: String!
}

现在具体的错误类型 实现 该接口:

type MissingPropertiesError implements ValidationError {
  code: String!
  message: String!
  missingProperties: [String!]!
}

type ImproperAgeError implements ValidationError {
  code: String!
  message: String!
  minimumAge: Int!
}

在 Mutation 中使用接口

type Mutation {
  saveInput(input: Input!): ValidationError
}

使用内联片段查询

mutation Save($input: Input!) {
  saveInput(input: $input) {
    __typename               # 告诉你得到的是哪种具体类型
    ... on ValidationError {
      code
      message
    }
    ... on MissingPropertiesError {
      missingProperties
    }
    ... on ImproperAgeError {
      minimumAge
    }
  }
}

__typename 字段是 GraphQL 自动添加的,用于让客户端在可能的具体类型之间进行区分。
片段使 minimumAgemissingProperties二选一特性变得明确。

GraphQL 联合

什么是联合?

  • 联合独立、无关的类型组合在一起。
  • 与接口不同,联合不定义任何公共字段

何时使用联合?

  • 当结果集可能是异构的(例如全文搜索返回文章、用户和标签)。
  • 通常,从单个字段返回无关类型是不良的 API 设计——想象一个 REST 端点可能返回鞋子、船只或封蜡。

为错误定义联合

type MissingPropertiesError {
  code: String!
  message: String!
  missingProperties: [String!]!
}

type ImproperAgeError {
  code: String!
  message: String!
  minimumAge: Int!
}

union ValidationError = MissingPropertiesError | ImproperAgeError

在 Mutation 中使用联合

type Mutation {
  saveInput(input: Input!): ValidationError
}

查询联合

因为联合没有公共字段,必须在片段中请求所有内容:

mutation Save($input: Input!) {
  saveInput(input: $input) {
    __typename
    ... on MissingPropertiesError {
      code
      message
      missingProperties
    }
    ... on ImproperAgeError {
      code
      message
      minimumAge
    }
  }
}

你仍然可以获得互斥性,但失去了共享字段的便利。

在 Interface 与 Union 之间的选择

决策因素InterfaceUnion
是否存在公共字段?✅ 使用 interface❌ 不适用
类型在概念上是否相关?✅ 使用 interface❌ 不理想
结果集是否异构(例如搜索结果)?❌ 更适合使用 union✅ 使用 union
单个字段返回多个不相关的类型?✅ 使用 union(罕见)

经验法则:
只要有任何*共享字段,优先使用 interface。如果类型确实毫不相关,union 可能更合适。

GraphQL “Code Smells” for Interfaces & Unions

  1. 可选的互斥字段 – 适合作为接口的候选(例如前面展示的重载 Error 类型)。
  2. 仅共享琐碎字段(例如仅 id – 避免创建接口;认知负担大于收益。
  3. 在全文搜索结果上使用接口 – 可疑;此时通常使用联合类型更合适,因为搜索可能返回许多不相关的类型。
  4. 在非搜索端点上使用联合类型 – 通常是一种异味;除非上游 API 强制,否则应寻找共同的接口。

回顾

  • Interfaces = 共享字段 + 具体实现 → 当有共同点时使用。
  • Unions = 完全独立的类型 → 用于异构结果(例如搜索)。
  • 两者都会暴露 __typename,以便客户端在运行时进行区分。
  • 避免过度设计:仅在它们能解决实际问题(互斥、共享字段、异构结果)时才添加接口/联合。

有了这些理解,你就能在向团队讲解 GraphQL 类型系统细节的同时,引入 AppSync 强大的解析器模型。祝 schema 设计愉快!

AWS AppSync GraphQL 开发者指南:GraphQL 中的接口和联合

模式和类型

他们会向你寻求答案和建议。提供示例和一些经验法则来指导决策,可以在帮助你的团队取得成功方面发挥重要作用。

祝构建愉快!

0 浏览
Back to Blog

相关文章

阅读更多 »