GraphQL 中的接口和并集 - AWS AppSync
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

GraphQL 中的接口和并集

本主题概述了 GraphQL 中的接口和并集类型。

接口

GraphQL 的类型系统中包含接口。接口会公开特定的字段组合,类型要实施接口,必须包含这些字段。如果您刚开始使用 GraphQL,请跳过此部分内容,首先了解如何利用架构自动创建和连接解析程序。以后希望发展架构或添加更多功能时可以再来学习这部分内容。

例如,我们可以利用 Event 接口表示任何类型的活动或人群。可能的事件类型是 ConcertConferenceFestival。这些类型具有共同特征,包括名称、举行活动的地点以及开始和结束日期。这些类型也有不同之处。Conference 提供演讲者的列表和研讨会,而 Concert 包含表演乐队。

在 SDL 中,Event 接口如下所示:

interface Event { id: ID! name : String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int }

每种类型都会实施 Event 接口,如下所示:

type Concert implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performingBand: String } type Festival implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performers: [String] } type Conference implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int speakers: [String] workshops: [String] }

如果要表示多种类型的元素,接口就很有用。例如,我们可以搜索特定地点发生的所有事件。让我们在架构中添加 findEventsByVenue 字段,如下所示:

schema { query: Query } type Query { # Retrieve Events at a specific Venue findEventsAtVenue(venueId: ID!): [Event] } type Venue { id: ID! name: String address: String maxOccupancy: Int } type Concert implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performingBand: String } interface Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int } type Festival implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performers: [String] } type Conference implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int speakers: [String] workshops: [String] }

findEventsByVenue 返回一组 Event。由于 GraphQL 接口字段对于所有实施类型都是通用的,所以可以选择 Event 接口的任何字段(idnamestartsAtendsAtvenueminAgeRestriction)。此外,只要您指定了类型,就可以使用 GraphQL 片段访问任何实施类型的字段。

请参考以下使用了接口的 GraphQL 查询示例。

query { findEventsAtVenue(venueId: "Madison Square Garden") { id name minAgeRestriction startsAt ... on Festival { performers } ... on Concert { performingBand } ... on Conference { speakers workshops } } }

上一查询生成一个结果列表,默认情况下,服务器会根据开始日期将事件排序。

{ "data": { "findEventsAtVenue": [ { "id": "Festival-2", "name": "Festival 2", "minAgeRestriction": 21, "startsAt": "2018-10-05T14:48:00.000Z", "performers": [ "The Singers", "The Screamers" ] }, { "id": "Concert-3", "name": "Concert 3", "minAgeRestriction": 18, "startsAt": "2018-10-07T14:48:00.000Z", "performingBand": "The Jumpers" }, { "id": "Conference-4", "name": "Conference 4", "minAgeRestriction": null, "startsAt": "2018-10-09T14:48:00.000Z", "speakers": [ "The Storytellers" ], "workshops": [ "Writing", "Reading" ] } ] } }

您可以看到,返回的结果是事件的单一集合。对结果进行排序时,使用接口表示共同特征非常有用。

并集

GraphQL 的类型系统中包含并集。并集与接口相同,只是并集未定义一组通用字段。如果可能的类型没有共享的逻辑层次结构,并集通常比接口更加常用。

例如,搜索结果可能表示许多不同的类型。使用 Event 架构,您可以定义一个 SearchResult 并集,如下所示:

type Query { # Retrieve Events at a specific Venue findEventsAtVenue(venueId: ID!): [Event] # Search across all content search(query: String!): [SearchResult] } union SearchResult = Conference | Festival | Concert | Venue

在此示例中,要查询 SearchResult 并集的任何字段,您必须使用片段。让我们考虑以下示例:

query { search(query: "Madison") { ... on Venue { id name address } ... on Festival { id name performers } ... on Concert { id name performingBand } ... on Conference { speakers workshops } } }

在 AWS AppSync 中进行类型解析

类型解析是一种机制,GraphQL 引擎通过这一机制将解析后的值识别为一种特定的对象类型。

再来看一下并集的搜索示例,假设我们的查询生成结果,结果列表中的每个项目必须表示为 SearchResult 并集定义的某种可能的类型(即,ConferenceFestivalConcertVenue)。

由于根据 VenueConference 识别 Festival 的逻辑取决于应用程序要求,必须给 GraphQL 引擎一点提示,这样它才能从原始结果中识别可能的类型。

在 AWS AppSync 中,这种提示由名为 __typename 的元字段表示,其值对应的是识别出的对象类型名称。如果返回类型是接口或并集,__typename 是必要的。

类型解析示例

让我们重复使用之前的架构。如果您要跟随操作,可以导航到控制台,并在 Schema (架构) 页面之下添加以下内容:

schema { query: Query } type Query { # Retrieve Events at a specific Venue findEventsAtVenue(venueId: ID!): [Event] # Search across all content search(query: String!): [SearchResult] } union SearchResult = Conference | Festival | Concert | Venue type Venue { id: ID! name: String! address: String maxOccupancy: Int } interface Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int } type Festival implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performers: [String] } type Conference implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int speakers: [String] workshops: [String] } type Concert implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performingBand: String }

让我们为 Query.search 字段附加解析程序。在控制台中,选择 Attach Resolver (附加解析程序),新建 Data Source (数据源),类型为 NONE,然后将它命名为 StubDataSource。在此示例中,我们假设已从外部源提取了结果,并将提取的结果硬编码到请求映射模板中。

在请求映射模板窗格中,输入以下内容:

{ "version" : "2017-02-28", "payload": ## We are effectively mocking our search results for this example [ { "id": "Venue-1", "name": "Venue 1", "address": "2121 7th Ave, Seattle, WA 98121", "maxOccupancy": 1000 }, { "id": "Festival-2", "name": "Festival 2", "performers": ["The Singers", "The Screamers"] }, { "id": "Concert-3", "name": "Concert 3", "performingBand": "The Jumpers" }, { "id": "Conference-4", "name": "Conference 4", "speakers": ["The Storytellers"], "workshops": ["Writing", "Reading"] } ] }

在应用程序中,选择将返回的类型名称作为 id 字段的一部分。类型解析逻辑仅包含解析 id 字段,以提取类型名称并在每个结果中添加 __typename 字段。您可以在响应映射模板中执行该逻辑,如下所示:

注意:如果您使用的是 Lambda 数据源,则也可以执行此任务作为 Lambda 函数的一部分。

#foreach ($result in $context.result) ## Extract type name from the id field. #set( $typeName = $result.id.split("-")[0] ) #set( $ignore = $result.put("__typename", $typeName)) #end $util.toJson($context.result)

运行以下查询:

query { search(query: "Madison") { ... on Venue { id name address } ... on Festival { id name performers } ... on Concert { id name performingBand } ... on Conference { speakers workshops } } }

查询生成以下结果:

{ "data": { "search": [ { "id": "Venue-1", "name": "Venue 1", "address": "2121 7th Ave, Seattle, WA 98121" }, { "id": "Festival-2", "name": "Festival 2", "performers": [ "The Singers", "The Screamers" ] }, { "id": "Concert-3", "name": "Concert 3", "performingBand": "The Jumpers" }, { "speakers": [ "The Storytellers" ], "workshops": [ "Writing", "Reading" ] } ] } }

类型解析逻辑会随应用程序而改变。例如,您可以使用另一种识别逻辑,检查某些字段或字段的组合是否存在。也就是说,您可以检测是否存在 performers 字段,以识别 Festival;或利用 speakersworkshops 字段的组合来识别 Conference。最终需要由您来定义将使用哪种逻辑。