JavaScript 解析器概述 - Amazon AppSync
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

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

JavaScript 解析器概述

在 Amazon AppSync 中,您可以对数据源执行操作以响应 GraphQL 请求。对于您希望运行查询、变更或订阅的每个 GraphQL 字段,必须附加一个解析器。

解析器是 GraphQL 和数据源之间的连接器。它们指示 Amazon AppSync 如何将传入的 GraphQL 请求转换为后端数据源的指令,以及如何将该数据源的响应转换回 GraphQL 响应。对于 Amazon AppSync,您可以使用 JavaScript 编写解析器,并在 Amazon AppSync (APPSYNC_JS) 环境中运行它们。

Amazon AppSync 允许您编写单位解析器或由管道中的多个 Amazon AppSync 函数组成的管道解析器。

支持的运行时功能

Amazon AppSync JavaScript 运行时环境提供一部分 JavaScript 库、实用程序和功能。有关 APPSYNC_JS 运行时环境支持的功能的完整列表,请参阅解析器和函数的 JavaScript 运行时功能

单位解析器

单位解析器由定义对数据源执行的请求和响应处理程序的代码组成。请求处理程序将上下文对象作为参数,并返回用于调用数据源的请求负载。响应处理程序接收从数据源返回的负载以及执行的请求结果。响应处理程序将负载转换为 GraphQL 响应以解析 GraphQL 字段。在以下示例中,解析器从 DynamoDB 数据源中检索项目:

import * as ddb from '@aws-appsync/utils/dynamodb' export function request(ctx) { return ddb.get({ key: { id: ctx.args.id } }); } export const response = (ctx) => ctx.result;

JavaScript 管道解析器剖析

管道解析器由定义请求和响应处理程序以及函数列表的代码组成。每个函数具有一个对数据源执行的请求响应处理程序。由于管道解析器将运行委派给一组函数,因此,它不会链接到任何数据源。单位解析器和函数是对数据源执行操作的基元。

管道解析器请求处理程序

管道解析器的请求处理程序(预备步骤)允许您在运行定义的函数之前执行一些准备逻辑。

函数列表

管道解析器将按顺序运行的函数的列表。管道解析器请求处理程序评估结果作为 ctx.prev.result 提供给第一个函数。每个函数评估结果作为 ctx.prev.result 提供给下一个函数。

管道解析器响应处理程序

管道解析器的响应处理程序允许您执行从最后一个函数的输出到预期 GraphQL 字段类型的一些最终逻辑。函数列表中的最后一个函数的输出在管道解析器响应处理程序中作为 ctx.prev.resultctx.result 提供。

执行流程

假定一个管道解析器由两个函数组成,下面的列表表示调用解析器时的执行流程:

  1. 管道解析器请求处理程序

  2. 函数 1:函数请求处理程序

  3. 函数 1:数据源调用

  4. 函数 1:函数响应处理程序

  5. 函数 2:函数请求处理程序

  6. 函数 2:数据源调用

  7. 函数 2:函数响应处理程序

  8. 管道解析器响应处理程序

非常有用的 APPSYNC_JS 运行时环境内置实用程序

在使用管道解析器时,以下实用工具可为您提供帮助。

ctx.stash

存储区是一个在每个解析器以及函数请求和响应处理程序中提供的对象。相同的存储区实例在单次解析器运行时间内有效。这意味着,您可以使用存储区在请求和响应处理程序之间以及管道解析器中的函数之间传送任意数据。您可以像常规 JavaScript 对象一样测试存储区。

ctx.prev.result

ctx.prev.result 表示已在管道中执行的上一个操作的结果。如果上一个操作是管道解析器请求处理程序,则将 ctx.prev.result 提供给链中的第一个函数。如果上一个操作是第一个函数,则 ctx.prev.result 表示第一个函数的输出,并且可供管道中的第二个函数使用。如果上一个操作是最后一个函数,则 ctx.prev.result 表示最后一个函数的输出,并提供给管道解析器响应处理程序。

util.error

util.error 实用工具对于引发字段错误很有用。在函数请求或响应处理程序中使用 util.error 将立即引发字段错误,这会禁止执行后续的函数。有关更多详细信息和其他 util.error 签名,请访问解析器和函数的 JavaScript 运行时功能

util.appendError

util.appendErrorutil.error() 类似,主要区别在于,它不会中断处理程序评估。相反,它指示字段存在错误,但允许评估处理程序并因而返回数据。在函数中使用 util.appendError 将不会中断管道的执行流。有关更多详细信息和其他 util.error 签名,请访问解析器和函数的 JavaScript 运行时功能

runtime.earlyReturn

runtime.earlyReturn 函数允许您从任何请求函数中提前返回。在解析器请求处理程序中使用 runtime.earlyReturn 将从解析器中返回。从 Amazon AppSync 函数请求处理程序中调用它将从该函数中返回,并继续运行到管道中的下一个函数或解析器响应处理程序。

编写管道解析器

管道解析器还具有运行管道中的函数之前和之后的请求和响应处理程序:其请求处理程序在第一个函数的请求之前运行,其响应处理程序在最后一个函数的响应之后运行。解析器请求处理程序可以设置管道中的函数使用的数据。解析器响应处理程序负责返回映射到 GraphQL 字段输出类型的数据。在以下示例中,解析器请求处理程序定义 allowedGroups;返回的数据应属于这些组之一。解析器的函数可以使用该值以请求数据。解析器的响应处理程序进行最终检查并筛选结果,以确保仅返回属于允许的组的项目。

import { util } from '@aws-appsync/utils'; /** * Called before the request function of the first AppSync function in the pipeline. * @param ctx the context object holds contextual information about the function invocation. */ export function request(ctx) { ctx.stash.allowedGroups = ['admin']; ctx.stash.startedAt = util.time.nowISO8601(); return {}; } /** * Called after the response function of the last AppSync function in the pipeline. * @param ctx the context object holds contextual information about the function invocation. */ export function response(ctx) { const result = []; for (const item of ctx.prev.result) { if (ctx.stash.allowedGroups.indexOf(item.group) > -1) result.push(item); } return result; }

编写 Amazon AppSync 函数

Amazon AppSync 函数允许您编写可在架构中的多个解析器之间重复使用的通用逻辑。例如,您具有一个名为 QUERY_ITEMS 的 Amazon AppSync 函数,负责从 Amazon DynamoDB 数据源中查询项目。对于要用于查询项目的解析器,只需将函数添加到解析器的管道并提供要使用的查询索引即可。不必重新实施该逻辑。

编写代码

假设您希望在名为 getPost(id:ID!) 的字段上附加一个管道解析器,该解析器使用以下 GraphQL 查询从 Amazon DynamoDB 数据源中返回 Post 类型:

getPost(id:1){ id title content }

首先,使用下面的代码将一个简单的解析器附加到 Query.getPost 中。这是一个简单的解析器代码示例。在请求处理程序中没有定义任何逻辑,响应处理程序只是返回最后一个函数的结果。

/** * Invoked **before** the request handler of the first AppSync function in the pipeline. * The resolver `request` handler allows to perform some preparation logic * before executing the defined functions in your pipeline. * @param ctx the context object holds contextual information about the function invocation. */ export function request(ctx) { return {} } /** * Invoked **after** the response handler of the last AppSync function in the pipeline. * The resolver `response` handler allows to perform some final evaluation logic * from the output of the last function to the expected GraphQL field type. * @param ctx the context object holds contextual information about the function invocation. */ export function response(ctx) { return ctx.prev.result }

接下来,定义从数据源中检索 postitem 的 GET_ITEM 函数:

import { util } from '@aws-appsync/utils' import * as ddb from '@aws-appsync/utils/dynamodb' /** * Request a single item from the attached DynamoDB table datasource * @param ctx the context object holds contextual information about the function invocation. */ export function request(ctx) { const { id } = ctx.args return ddb.get({ key: { id } }) } /** * Returns the result * @param ctx the context object holds contextual information about the function invocation. */ export function response(ctx) { const { error, result } = ctx if (error) { return util.appendError(error.message, error.type, result) } return ctx.result }

如果在请求期间出现错误,则该函数的响应处理程序附加一个错误,该错误将在 GraphQL 响应中返回到调用客户端。将 GET_ITEM 函数添加到您的解析器函数列表中。在您执行查询时,GET_ITEM 函数的请求处理程序使用 Amazon AppSync 的 DynamoDB 模块提供的实用程序创建 DynamoDBGetItem 请求并将 id 作为键。ddb.get({ key: { id } }) 生成相应的 GetItem 操作:

{ "operation" : "GetItem", "key" : { "id" : { "S" : "1" } } }

Amazon AppSync 使用请求从 Amazon DynamoDB 中获取数据。在返回数据后,将由 GET_ITEM 函数的响应处理程序进行处理,响应处理程序检查错误,然后返回结果。

{ "result" : { "id": 1, "title": "hello world", "content": "<long story>" } }

最后,解析器的响应处理程序直接返回结果。

处理错误

如果您的函数在请求期间出现错误,将在函数响应处理程序的 ctx.error 中提供该错误。您可以使用 util.appendError 实用程序将错误附加到 GraphQL 响应中。您可以使用存储区将错误提供给管道中的其他函数。请参见以下示例:

/** * Returns the result * @param ctx the context object holds contextual information about the function invocation. */ export function response(ctx) { const { error, result } = ctx; if (error) { if (!ctx.stash.errors) ctx.stash.errors = [] ctx.stash.errors.push(ctx.error) return util.appendError(error.message, error.type, result); } return ctx.result; }

实用程序

Amazon AppSync 提供了两个库,可以帮助使用 APPSYNC_JS 运行时环境开发解析器:

  • @aws-appsync/eslint-plugin - 在开发过程中快速捕获并修复问题。

  • @aws-appsync/utils - 在代码编辑器中提供类型验证和自动完成功能。

配置 ESLint 插件

ESLint 是一个静态分析代码以快速发现问题的工具。您可以将 ESLint 作为持续集成管道的一部分运行。@aws-appsync/eslint-plugin 是一个 ESLint 插件,可以在使用 APPSYNC_JS 运行时环境时捕获代码中的无效语法。通过使用该插件,您可以在开发过程中快速获得有关代码的反馈,而无需将更改推送到云端。

@aws-appsync/eslint-plugin 提供了两个可以在开发过程中使用的规则集。

"plugin:@aws-appsync/base" 配置您可以在项目中使用的一组基本规则:

规则 描述
no-async 不支持异步过程和 Promise。
no-await 不支持异步过程和 Promise。
no-classes 不支持类。
no-for 不支持 for(支持的 for-infor-of 除外)
no-continue 不支持 continue
no-generators 不支持生成器。
no-yield 不支持 yield
no-labels 不支持标签。
no-this 不支持 this 关键字。
no-try 不支持 try/catch 结构。
no-while 不支持 while 循环。
no-disallowed-unary-operators 不允许使用 ++--~ 一元运算符。
no-disallowed-binary-operators 不允许使用 instanceof 运算符。
no-promise 不支持异步过程和 Promise。

"plugin:@aws-appsync/recommended" 提供一些额外的规则,但还要求您将 TypeScript 配置添加到项目中。

规则 描述
no-recursion 不允许使用递归函数调用。
no-disallowed-methods 不允许使用某些方法。请参阅参考以了解支持的全套内置函数。
no-function-passing 不允许将函数作为函数参数传递给函数。
no-function-reassign 无法重新分配函数。
no-function-return 函数不能是函数的返回值。

要将插件添加到您的项目中,请按照 ESLint 入门中的安装和使用步骤进行操作。然后,使用项目包管理器(例如 npm、yarn 或 pnpm)在项目中安装插件

$ npm install @aws-appsync/eslint-plugin

.eslintrc.{js,yml,json} 文件中,将 "plugin:@aws-appsync/base""plugin:@aws-appsync/recommended" 添加到 extends 属性中。下面的代码片段是 JavaScript 的基本示例 .eslintrc 配置:

{ "extends": ["plugin:@aws-appsync/base"] }

要使用 "plugin:@aws-appsync/recommended" 规则集,请安装所需的依赖项:

$ npm install -D @typescript-eslint/parser

然后,创建一个 .eslintrc.js 文件:

{ "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": 2018, "project": "./tsconfig.json" }, "extends": ["plugin:@aws-appsync/recommended"] }

捆绑、TypeScript 和源映射

使用库并捆绑您的代码

在您的解析器和函数代码中,您可以使用自定义库和外部库,只要它们符合 APPSYNC_JS 要求即可。这样,就可以在应用程序中重复使用现有的代码。要使用由多个文件定义的库,您必须使用捆绑工具(例如 esbuild)将代码合并到单个文件中,然后可以将该文件保存到您的 Amazon AppSync 解析器或函数中。

在捆绑代码时,请记住以下几点:

  • APPSYNC_JS 仅支持 ECMAScript 模块 (ESM)。

  • @aws-appsync/* 模块集成到 APPSYNC_JS 中,不应将其与您的代码捆绑在一起。

  • APPSYNC_JS 运行时环境与 NodeJS 类似,即,不会在浏览器环境中运行代码。

  • 您可以包含可选的源映射。不过,不要包含源内容。

    要了解源映射的更多信息,请参阅使用源映射

例如,要捆绑位于 src/appsync/getPost.resolver.js 中的解析器代码,您可以使用以下 esbuild CLI 命令:

$ esbuild --bundle \ --sourcemap=inline \ --sources-content=false \ --target=esnext \ --platform=node \ --format=esm \ --external:@aws-appsync/utils \ --outdir=out/appsync \ src/appsync/getPost.resolver.js

构建代码并使用 TypeScript

TypeScript 是 Microsoft 开发的一种编程语言,它提供 JavaScript 的所有功能以及 TypeScript 类型系统。您可以使用 TypeScript 编写类型安全的代码,并在构建时捕获错误和缺陷,然后再将代码保存到 Amazon AppSync 中。@aws-appsync/utils 包是完全类型化的。

APPSYNC_JS 运行时环境不直接支持 TypeScript。在将代码保存到 Amazon AppSync 之前,您必须先将 TypeScript 代码转译为 APPSYNC_JS 运行时环境支持的 JavaScript 代码。您可以使用 TypeScript 在本地集成开发环境 (IDE) 中编写代码,但请注意,您无法在 Amazon AppSync 控制台中创建 TypeScript 代码。

首先,请确保在您的项目中安装了 TypeScript。然后,使用 TSConfig 配置 TypeScript 转译设置以与 APPSYNC_JS 运行时环境一起使用。以下是您可以使用的基本 tsconfig.json 文件示例:

// tsconfig.json { "compilerOptions": { "target": "esnext", "module": "esnext", "noEmit": true, "moduleResolution": "node", } }

然后,您可以使用 esbuild 等捆绑工具编译和捆绑代码。例如,假定一个项目的 Amazon AppSync 代码位于 src/appsync 中,您可以使用以下命令编译和捆绑代码:

$ esbuild --bundle \ --sourcemap=inline \ --sources-content=false \ --target=esnext \ --platform=node \ --format=esm \ --external:@aws-appsync/utils \ --outdir=out/appsync \ src/appsync/**/*.ts

使用 Amplify codegen

您可以使用 Amplify CLI 生成架构的类型。从 schema.graphql 文件所在的目录中,运行以下命令并查看提示以配置 codegen:

$ npx @aws-amplify/cli codegen add

要在某些情况下(例如,更新架构时)重新生成 codegen,请运行以下命令:

$ npx @aws-amplify/cli codegen

然后,您可以在解析器代码中使用生成的类型。例如,给定以下架构:

type Todo { id: ID! title: String! description: String } type Mutation { createTodo(title: String!, description: String): Todo } type Query { listTodos: Todo }

您可以在以下示例 Amazon AppSync 函数中使用生成的类型:

import { Context, util } from '@aws-appsync/utils' import * as ddb from '@aws-appsync/utils/dynamodb' import { CreateTodoMutationVariables, Todo } from './API' // codegen export function request(ctx: Context<CreateTodoMutationVariables>) { ctx.args.description = ctx.args.description ?? 'created on ' + util.time.nowISO8601() return ddb.put<Todo>({ key: { id: util.autoId() }, item: ctx.args }) } export function response(ctx) { return ctx.result as Todo }

在 TypeScript 中使用泛型

您可以将泛型与提供的多种类型一起使用。例如,下面的代码片段是 Todo 类型:

export type Todo = { __typename: "Todo", id: string, title: string, description?: string | null, };

您可以为使用 Todo 的订阅编写解析器。在您的 IDE 中,类型定义和自动完成提示将指导您正确使用 toSubscriptionFilter 转换实用程序:

import { util, Context, extensions } from '@aws-appsync/utils' import { Todo } from './API' export function request(ctx: Context) { return {} } export function response(ctx: Context) { const filter = util.transform.toSubscriptionFilter<Todo>({ title: { beginsWith: 'hello' }, description: { contains: 'created' }, }) extensions.setSubscriptionFilter(filter) return null }

检查您的包

您可以导入 esbuild-plugin-eslint 插件以自动检查您的包。然后,您可以提供启用 ESLint 功能的 plugins 值以启用该插件。下面是在名为 build.mjs 的文件中使用 esbuild JavaScript API 的片段:

/* eslint-disable */ import { build } from 'esbuild' import eslint from 'esbuild-plugin-eslint' import glob from 'glob' const files = await glob('src/**/*.ts') await build({ format: 'esm', target: 'esnext', platform: 'node', external: ['@aws-appsync/utils'], outdir: 'dist/', entryPoints: files, bundle: true, plugins: [eslint({ useEslintrc: true })], })

使用源映射

您可以为 JavaScript 代码提供内联源映射 (sourcemap)。如果您捆绑 JavaScript 或 TypeScript 代码,并希望在日志和运行时 JavaScript 错误消息中查看对输入源文件的引用,源映射是非常有用的。

您的 sourcemap 必须出现在代码末尾。它是由采用以下格式的单个注释行定义的:

//# sourceMappingURL=data:application/json;base64,<base64 encoded string>

示例如下:

//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsibGliLmpzIiwgImNvZGUuanMiXSwKICAibWFwcGluZ3MiOiAiO0FBQU8sU0FBUyxRQUFRO0FBQ3RCLFNBQU87QUFDVDs7O0FDRE8sU0FBUyxRQUFRLEtBQUs7QUFDM0IsU0FBTyxNQUFNO0FBQ2Y7IiwKICAibmFtZXMiOiBbXQp9Cg==

可以使用 esbuild 创建源映射。以下示例说明了如何使用 esbuild JavaScript API 在构建和捆绑代码时包含内联源映射:

/* eslint-disable */ import { build } from 'esbuild' import eslint from 'esbuild-plugin-eslint' import glob from 'glob' const files = await glob('src/**/*.ts') await build({ sourcemap: 'inline', sourcesContent: false, format: 'esm', target: 'esnext', platform: 'node', external: ['@aws-appsync/utils'], outdir: 'dist/', entryPoints: files, bundle: true, plugins: [eslint({ useEslintrc: true })], })

特别是,sourcemapsourcesContent 选项指定应在每个构建末尾的行中添加源映射,但源映射不应包含源内容。作为惯例,我们建议不要在您的 sourcemap 中包含源内容。您可以将 sources-content 设置为 false 以在 esbuild 中禁用该功能。

要说明源映射的工作方式,请查看以下示例,其中解析器代码引用帮助程序库中的帮助程序函数。该代码在解析器代码和帮助程序库中包含日志语句:

./src/default.resolver.ts(您的解析器)

import { Context } from '@aws-appsync/utils' import { hello, logit } from './helper' export function request(ctx: Context) { console.log('start >') logit('hello world', 42, true) console.log('< end') return 'test' } export function response(ctx: Context): boolean { hello() return ctx.prev.result }

.src/helper.ts(帮助程序文件)

export const logit = (...rest: any[]) => { // a special logger console.log('[logger]', ...rest.map((r) => `<${r}>`)) } export const hello = () => { // This just returns a simple sentence, but it could do more. console.log('i just say hello..') }

在您构建并捆绑解析器文件时,您的解析器代码将包含内联源映射。在您的解析器运行时,将在 CloudWatch 日志中出现以下条目:

看一下 CloudWatch 日志中的条目,您会注意到这两个文件的功能已捆绑在一起并且同时运行。每个文件的原始文件名也清晰地反映在日志中。

测试

在将代码保存到解析器或函数之前,您可以通过 EvaluateCode API 命令使用模拟数据远程测试解析器和函数处理程序。要开始使用该命令,请确保您已将 appsync:evaluatecode 权限添加到您的策略中。例如:

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "appsync:evaluateCode", "Resource": "arn:aws:appsync:<region>:<account>:*" } ] }

您可以通过 Amazon CLIAmazon SDK 使用该命令。例如,要使用 CLI 测试代码,只需指向您的文件,提供上下文并指定要评估的处理程序:

aws appsync evaluate-code \ --code file://code.js \ --function request \ --context file://context.json \ --runtime name=APPSYNC_JS,runtimeVersion=1.0.0

响应包含一个 evaluationResult,其中包含处理程序返回的负载。它还包含一个 logs 对象,其中保存处理程序在评估期间生成的日志列表。这样,就可以轻松调试代码执行,并查看有关评估的信息以帮助排除故障。例如:

{ "evaluationResult": "{\"operation\":\"PutItem\",\"key\":{\"id\":{\"S\":\"record-id\"}},\"attributeValues\":{\"owner\":{\"S\":\"John doe\"},\"expectedVersion\":{\"N\":2},\"authorId\":{\"S\":\"Sammy Davis\"}}}", "logs": [ "INFO - code.js:5:3: \"current id\" \"record-id\"", "INFO - code.js:9:3: \"request evaluated\"" ] }

可以将评估结果解析为 JSON,其中提供:

{ "operation": "PutItem", "key": { "id": { "S": "record-id" } }, "attributeValues": { "owner": { "S": "John doe" }, "expectedVersion": { "N": 2 }, "authorId": { "S": "Sammy Davis" } } }

通过使用 SDK,您可以轻松合并测试套件中的测试以验证代码行为。此处的示例使用 Jest 测试框架,但任何测试套件都有效。以下代码片段显示假设的验证运行。请注意,我们希望评估响应是有效的 JSON ,因此,我们使用 JSON.parse 从字符串响应中检索 JSON:

const AWS = require('aws-sdk') const fs = require('fs') const client = new AWS.AppSync({ region: 'us-east-2' }) const runtime = {name:'APPSYNC_JS',runtimeVersion:'1.0.0') test('request correctly calls DynamoDB', async () => { const code = fs.readFileSync('./code.js', 'utf8') const context = fs.readFileSync('./context.json', 'utf8') const contextJSON = JSON.parse(context) const response = await client.evaluateCode({ code, context, runtime, function: 'request' }).promise() const result = JSON.parse(response.evaluationResult) expect(result.key.id.S).toBeDefined() expect(result.attributeValues.firstname.S).toEqual(contextJSON.arguments.firstname) })

这会产生以下结果:

Ran all test suites. > jest PASS ./index.test.js ✓ request correctly calls DynamoDB (543 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 totalTime: 1.511 s, estimated 2 s

从 VTL 迁移到 JavaScript

Amazon AppSync 允许您使用 VTL 或 JavaScript 为解析器和函数编写业务逻辑。通过使用这两种语言,您可以编写逻辑以指示 Amazon AppSync 服务如何与数据源进行交互。在使用 VTL 时,您可以编写评估结果必须为有效 JSON 编码字符串的映射模板。在使用 JavaScript 时,您可以编写返回对象的请求和响应处理程序。您不会返回 JSON 编码的字符串。

例如,采用以下 VTL 映射模板以获取 Amazon DynamoDB 项目:

{ "operation": "GetItem", "key": { "id": $util.dynamodb.toDynamoDBJson($ctx.args.id), } }

$util.dynamodb.toDynamoDBJson 实用程序返回 JSON 编码的字符串。如果 $ctx.args.id 设置为 <id>,则模板评估结果为有效的 JSON 编码字符串:

{ "operation": "GetItem", "key": { "id": {"S": "<id>"}, } }

在使用 JavaScript 时,您不需要在代码中输出原始 JSON 编码字符串,并且不需要使用像 toDynamoDBJson 这样的实用程序。上述映射模板的等效示例是:

import { util } from '@aws-appsync/utils'; export function request(ctx) { return { operation: 'GetItem', key: {id: util.dynamodb.toDynamoDB(ctx.args.id)} }; }

另一种方法是使用 util.dynamodb.toMapValues,这是处理值对象的建议方法:

import { util } from '@aws-appsync/utils'; export function request(ctx) { return { operation: 'GetItem', key: util.dynamodb.toMapValues({ id: ctx.args.id }), }; }

它的评估结果为:

{ "operation": "GetItem", "key": { "id": { "S": "<id>" } } }
注意

我们建议将 DynamoDB 模块与 DynamoDB 数据源一起使用:

import * as ddb from '@aws-appsync/utils/dynamodb' export function request(ctx) { ddb.get({ key: { id: ctx.args.id } }) }

再举一个例子,采用以下映射模板将项目放入 Amazon DynamoDB 数据源中:

{ "operation" : "PutItem", "key" : { "id": $util.dynamodb.toDynamoDBJson($util.autoId()), }, "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args) }

在评估后,该映射模板字符串必须生成有效的 JSON 编码字符串。在使用 JavaScript 时,您的代码直接返回请求对象:

import { util } from '@aws-appsync/utils'; export function request(ctx) { const { id = util.autoId(), ...values } = ctx.args; return { operation: 'PutItem', key: util.dynamodb.toMapValues({ id }), attributeValues: util.dynamodb.toMapValues(values), }; }

它的评估结果为:

{ "operation": "PutItem", "key": { "id": { "S": "2bff3f05-ff8c-4ed8-92b4-767e29fc4e63" } }, "attributeValues": { "firstname": { "S": "Shaggy" }, "age": { "N": 4 } } }
注意

我们建议将 DynamoDB 模块与 DynamoDB 数据源一起使用:

import { util } from '@aws-appsync/utils' import * as ddb from '@aws-appsync/utils/dynamodb' export function request(ctx) { const { id = util.autoId(), ...item } = ctx.args return ddb.put({ key: { id }, item }) }

在直接数据源访问和通过 Lambda 数据源代理之间进行选择

通过使用 Amazon AppSync 和 APPSYNC_JS 运行时环境,您可以编写自己的代码,以通过 Amazon AppSync 函数访问数据源来实施自定义业务逻辑。这样,您可以轻松直接与数据源(如 Amazon DynamoDB、Aurora Serverless、OpenSearch Service、HTTP API 和其他 Amazon 服务)交互,而无需部署额外的计算服务或基础设施。AmazonAppSync 还可以配置 Lambda 数据源以轻松与 Amazon Lambda 函数进行交互。通过使用 Lambda 数据源,您可以使用 Amazon Lambda 的全套功能运行复杂的业务逻辑以解析 GraphQL 请求。在大多数情况下,直接连接到目标数据源的 Amazon AppSync 函数将提供您所需的所有功能。在您需要实施 APPSYNC_JS 运行时环境不支持的复杂业务逻辑时,您可以将 Lambda 数据源作为代理以与目标数据源进行交互。

直接数据源集成 将 Lambda 数据源作为代理
使用案例 Amazon AppSync functions interact directly with API data sources. Amazon AppSync functions call Lambdas that interact with API data sources.
Runtime APPSYNC_JS (JavaScript) 任何支持的 Lambda 运行时环境
Maximum size of code 每个 Amazon AppSync 函数 32,000 个字符 每个 Lambda 50 MB(压缩,用于直接上传)
External modules 有限 - 仅 APPSYNC_JS 支持的功能
Call any Amazon service 是 - 使用 Amazon AppSync HTTP 数据源 是 - 使用 Amazon SDK
Access to the request header
Network access
File system access
Logging and metrics
Build and test entirely within AppSync
Cold start 否 - 使用预置并发
Auto-scaling 是 - 由 Amazon AppSync 透明实施 是 - 根据 Lambda 中的配置
Pricing 无额外费用 收取 Lambda 使用费用

直接与目标数据源集成的 Amazon AppSync 函数非常适合以下使用案例:

  • 与 Amazon DynamoDB、Aurora Serverless 和 OpenSearch Service 交互

  • 与 HTTP API 交互并传递传入标头

  • 使用 HTTP 数据源与 Amazon 服务交互(Amazon AppSync 使用提供的数据源角色自动对请求进行签名)

  • 在访问数据源之前实施访问控制

  • 在完成请求之前对检索的数据实施筛选

  • 按顺序执行解析器管道中的 Amazon AppSync 函数以实施简单编排

  • 控制查询和变更中的缓存和订阅连接。

将 Lambda 数据源作为代理的 Amazon AppSync 函数非常适合以下使用案例:

  • 使用 JavaScript 或 Velocity 模板语言 (VTL) 以外的语言

  • 调整和控制 CPU 或内存以优化性能

  • 导入第三方库或要求使用 APPSYNC_JS 中不支持的功能

  • 发出多个网络请求和/或获取文件系统访问权限以完成查询

  • 使用批处理配置对请求进行批处理。