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

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

GraphQL 中的接口和并集

本主题概述了 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 } } }

在中输入分辨率AmazonAppSync

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

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

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

与AmazonAppSync,此提示由名为__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" : "2018-05-29", "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。最终需要由您来定义要使用的逻辑。