本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
AWS AppSync Lambda 的解析器映射模板参考
注意
我们现在主要支持 APPSYNC _JS 运行时及其文档。请考虑在此处使用 APPSYNC _JS 运行时及其指南。
您可以使用 AWS AppSync 函数和解析器来调用位于您账户中的 Lambda 函数。在将请求负载和 Lambda 函数返回给客户之前,您可以调整请求负载和 Lambda 函数的响应。您还可以使用映射模板来提示 AWS AppSync 要调用的操作的性质。本节介绍了支持的 Lambda 操作的各种映射模板。
请求映射模板
Lambda 请求映射模板可以处理与您的 Lambda 函数相关的字段:
{ "version": string, "operation": Invoke|BatchInvoke, "payload": any type, "invocationType": RequestResponse|Event }
这是 Lambda 请求映射模板在解析后的JSON架构表示形式:
{ "definitions": {}, "$schema": "https://json-schema.org/draft-06/schema#", "$id": "https://aws.amazon.com/appsync/request-mapping-template.json", "type": "object", "properties": { "version": { "$id": "/properties/version", "type": "string", "enum": [ "2018-05-29" ], "title": "The Mapping template version.", "default": "2018-05-29" }, "operation": { "$id": "/properties/operation", "type": "string", "enum": [ "Invoke", "BatchInvoke" ], "title": "The Mapping template operation.", "description": "What operation to execute.", "default": "Invoke" }, "payload": {}, "invocationType": { "$id": "/properties/invocationType", "type": "string", "enum": [ "RequestResponse", "Event" ], "title": "The Mapping template invocation type.", "description": "What invocation type to execute.", "default": "RequestResponse" } }, "required": [ "version", "operation" ], "additionalProperties": false }
以下示例使用了一个invoke
操作,其有效载荷数据是 GraphQL 架构中的getPost
字段,其参数来自上下文:
{ "version": "2018-05-29", "operation": "Invoke", "payload": { "field": "getPost", "arguments": $util.toJson($context.arguments) } }
整个映射文档将作为输入传递给您的 Lambda 函数,因此前面的示例现在如下所示:
{ "version": "2018-05-29", "operation": "Invoke", "payload": { "field": "getPost", "arguments": { "id": "postId1" } } }
版本
所有请求映射模板都通用,version
定义了模板使用的版本。version
是必填的,是一个静态值:
"version": "2018-05-29"
操作
Lambda 数据源允许您在operation
字段中定义两个操作:Invoke
和。BatchInvoke
该Invoke
操作允许 AWS AppSync 你为每个 GraphQL 字段解析器调用你的 Lambda 函数。 BatchInvoke
指示 AWS AppSync 对当前 GraphQL 字段进行批量请求。operation
字段为必填项。
对于Invoke
,已解析的请求映射模板与 Lambda 函数的输入负载相匹配。让我们修改上面的示例:
{ "version": "2018-05-29", "operation": "Invoke", "payload": { "arguments": $util.toJson($context.arguments) } }
此问题已解决并传递给 Lambda 函数,该函数可能如下所示:
{ "version": "2018-05-29", "operation": "Invoke", "payload": { "arguments": { "id": "postId1" } } }
对于BatchInvoke
,映射模板将应用于批次中的每个字段解析器。为简洁起见,将所有已解析的映射模板payload
值 AWS AppSync 合并到与映射模板匹配的单个对象下的列表中。以下示例模板显示合并:
{ "version": "2018-05-29", "operation": "BatchInvoke", "payload": $util.toJson($context) }
此模板解析为以下映射文档:
{ "version": "2018-05-29", "operation": "BatchInvoke", "payload": [ {...}, // context for batch item 1 {...}, // context for batch item 2 {...} // context for batch item 3 ] }
payload
列表中的每个元素对应一个批次项目。Lambda 函数还应返回与请求中发送的项目顺序相匹配的列表形响应:
[ { "data": {...}, "errorMessage": null, "errorType": null }, // result for batch item 1 { "data": {...}, "errorMessage": null, "errorType": null }, // result for batch item 2 { "data": {...}, "errorMessage": null, "errorType": null } // result for batch item 3 ]
有效负载
该payload
字段是一个容器,用于将任何格式良好的JSON内容传递给 Lambda 函数。如果该operation
字段设置为BatchInvoke
,则 AWS AppSync 将现有payload
值换成一个列表。payload
字段为可选项。
调用类型
Lambda 数据源允许您定义两种调用类型:和。RequestResponse
Event
调用类型与 Lambda 中定义的调用类型同义。APIRequestResponse
调用类型允许 AWS AppSync 同步调用您的 Lambda 函数以等待响应。该Event
调用允许您异步调用 Lambda 函数。有关 Lambda 如何处理Event
调用类型请求的更多信息,请参阅异步调用。invocationType
字段为可选项。如果请求中未包含此字段, AWS AppSync 则默认为RequestResponse
调用类型。
对于任何invocationType
字段,已解析的请求都与 Lambda 函数的输入负载相匹配。让我们修改上面的示例:
{ "version": "2018-05-29", "operation": "Invoke", "invocationType": "Event" "payload": { "arguments": $util.toJson($context.arguments) } }
此问题已解决并传递给 Lambda 函数,该函数可能如下所示:
{ "version": "2018-05-29", "operation": "Invoke", "invocationType": "Event", "payload": { "arguments": { "id": "postId1" } } }
当该BatchInvoke
操作与Event
调用类型字段结合使用时,将以与上述相同的方式 AWS AppSync 合并字段解析器,然后将请求作为异步事件传递给您的 Lambda 函数,并以值列表的形式传送给您的 Lambda 函数。payload
我们建议您禁用Event
调用类型解析器的解析器缓存,因为如果出现缓存命中,这些解析器不会发送到 Lambda。
响应映射模板
与其他数据源一样,您的 Lambda 函数会向其发送一个必须转换为 GraphQL 类型的响应。 AWS AppSync
Lambda 函数的结果是在通过 Velocity 模板语言 (VTL) $context.result
属性可用的context
对象上设置的。
如果 Lambda 函数响应的形状与 GraphQL 类型的形状完全匹配,您可以使用以下响应映射模板转发响应:
$util.toJson($context.result)
没有必填字段,也没有形状限制应用于响应映射模板。但是,由于 GraphQL 是强类型化的,因此解析的映射模板必须与预期的 GraphQL 类型匹配。
Lambda 函数批处理的响应
如果该operation
字段设置为BatchInvoke
, AWS AppSync则需要从 Lambda 函数返回的项目列表。 AWS AppSync 为了将每个结果映射回原始请求项,响应列表的大小和顺序必须匹配。在响应列表中包含null
项目是有效$ctx.result
的;相应地设置为 null。
直接 Lambda 解析器
如果您想完全避免使用映射模板, AWS AppSync 可以为您的 Lambda 函数提供默认负载,并为 GraphQL 类型提供默认 Lambda 函数响应。您可以选择提供请求模板和响应模板,或者两者都不提供,然后进行相应的 AWS AppSync 处理。
直接 Lambda 请求映射模板
如果未提供请求映射模板,则 AWS AppSync 会将该Context
对象作为操作直接发送到您的 Lambda 函数。Invoke
有关 Context
对象结构的更多信息,请参阅 AWS AppSync 解析器映射模板上下文参考。
直接 Lambda 响应映射模板
如果未提供响应映射模板,则在收到 Lambda 函数的响应后 AWS AppSync 执行以下两项操作之一。如果您没有提供请求映射模板,或者您在版本中提供了请求映射模板2018-05-29
,则响应将等同于以下响应映射模板:
#if($ctx.error) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #end $util.toJson($ctx.result)
如果您提供了带有版本的模板2017-02-28
,则响应逻辑的功能等同于以下响应映射模板:
$util.toJson($ctx.result)
从表面上看,绕过映射模板的操作方式与使用某些映射模板类似,如前面的示例所示。但在幕后,完全绕过了映射模板评估。由于绕过了模板评估步骤,因此与带有需要评估的响应映射模板的 Lambda 函数相比,在某些情况下,应用程序在响应期间遇到的开销和延迟可能会更少。
直接 Lambda 解析器响应中的自定义错误处理
您可以通过引发自定义异常,自定义直接 Lambda 解析器调用的 Lambda 函数的错误响应。以下示例演示如何使用创建自定义异常 JavaScript:
class CustomException extends Error { constructor(message) { super(message); this.name = "CustomException"; } } throw new CustomException("Custom message");
在引发异常时,errorType
和 errorMessage
分别是引发的自定义错误的 name
和 message
。
如果errorType
是UnauthorizedException
,则 AWS AppSync返回默认消息 ("You are not authorized to make this
call."
),而不是自定义消息。
以下片段是演示自定义的 GraphQL 响应示例:errorType
{ "data": { "query": null }, "errors": [ { "path": [ "query" ], "data": null, "errorType": "CustomException", "errorInfo": null, "locations": [ { "line": 5, "column": 10, "sourceName": null } ], "message": "Custom Message" } ] }
直接 Lambda 解析器:已启用批处理
您可以通过在解析器上配置 maxBatchSize
,为直接 Lambda 解析器启用批处理。如果设置0
为大于 D maxBatchSize
irect Lambda 解析器的值,则会分批向您的 Lambda 函数 AWS AppSync 发送大小不超过的请求。maxBatchSize
在 Direct Lambda 解析器0
上设置maxBatchSize
为会关闭批处理。
有关 Lambda 解析器上的批处理的工作方式的更多信息,请参阅高级使用案例:批处理。
请求映射模板
启用批处理但未提供请求映射模板时, AWS AppSync 会将Context
对象列表作为BatchInvoke
操作直接发送到您的 Lambda 函数。
响应映射模板
如果启用了批处理并且未提供响应映射模板,响应逻辑相当于以下响应映射模板:
#if( $context.result && $context.result.errorMessage ) $utils.error($context.result.errorMessage, $context.result.errorType, $context.result.data) #else $utils.toJson($context.result.data) #end
Lambda 函数返回结果列表的顺序必须与发送的 Context
对象列表相同。您可以为特定结果提供 errorMessage
和 errorType
以返回各个错误。列表中的每个结果采用以下格式:
{ "data" : { ... }, // your data "errorMessage" : { ... }, // optional, if included an error entry is added to the "errors" object in the AppSync response "errorType" : { ... } // optional, the error type }
注意
目前忽略结果对象中的其他字段。
处理来自 Lambda 的错误
您可以通过在 Lambda 函数中引发异常或错误,为所有结果返回错误。如果批处理请求的负载请求或响应太大,Lambda 将返回错误。在这种情况下,您应该考虑减少 maxBatchSize
或减少响应负载大小。
有关处理各个错误的信息,请参阅返回单个错误。
示例 Lambda 函数
使用以下架构,您可以为Post.relatedPosts
字段解析器创建 Direct Lambda 解析器,并通过上述设置启用批处理:maxBatchSize
0
schema { query: Query mutation: Mutation } type Query { getPost(id:ID!): Post allPosts: [Post] } type Mutation { addPost(id: ID!, author: String!, title: String, content: String, url: String): Post! } type Post { id: ID! author: String! title: String content: String url: String ups: Int downs: Int relatedPosts: [Post] }
在以下查询中,将为批量请求调用 Lambda 函数以解析 relatedPosts
:
query getAllPosts { allPosts { id relatedPosts { id } } }
下面提供了 Lambda 函数的简单实施:
const posts = { 1: { id: '1', title: 'First book', author: 'Author1', url: 'https://amazon.com/', content: 'SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1', ups: '100', downs: '10', }, 2: { id: '2', title: 'Second book', author: 'Author2', url: 'https://amazon.com', content: 'SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT', ups: '100', downs: '10', }, 3: { id: '3', title: 'Third book', author: 'Author3', url: null, content: null, ups: null, downs: null }, 4: { id: '4', title: 'Fourth book', author: 'Author4', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4', ups: '1000', downs: '0', }, 5: { id: '5', title: 'Fifth book', author: 'Author5', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT', ups: '50', downs: '0', }, } const relatedPosts = { 1: [posts['4']], 2: [posts['3'], posts['5']], 3: [posts['2'], posts['1']], 4: [posts['2'], posts['1']], 5: [], } exports.handler = async (event) => { console.log('event ->', event) // retrieve the ID of each post const ids = event.map((context) => context.source.id) // fetch the related posts for each post id const related = ids.map((id) => relatedPosts[id]) // return the related posts; or an error if none were found return related.map((r) => { if (r.length > 0) { return { data: r } } else { return { data: null, errorMessage: 'Not found', errorType: 'ERROR' } } }) }