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

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

教程:DynamoDB JavaScript 解析器

在本教程中,您将将 Amazon DynamoDB 表导入Amazon AppSync并连接它们,使用 JavaScript 管道解析器构建功能齐全的 GraphQL API,这些流水线解析器可以在自己的应用程序中使用。

您将使用Amazon AppSync控制台中的创建 API 向导来预置您的 Amazon DynamoDB 资源、创建解析器并将它们连接到您的数据源。您还可以通过 GraphQL 语句读写您的 Amazon DynamoDB 数据库,并订阅实时数据。

要将 GraphQL 语句转换为 Amazon DynamoDB 操作并将响应转换回 GraphQL,需要完成特定的配置步骤。本教程通过一些现实世界的场景和数据访问模式介绍了配置过程。

创建 Ghame (表名称)

要在Amazon AppSync以下位置创建 GraphQL API,请执行

  1. 打开 AppSync 控制台并选择创建 API

  2. 选择 “从头开始构建”,然后选择 “开始”。

  3. 命名您的 APIPostTutorialAPI,然后选择 “创建”。

Amazon AppSync 控制台会使用 API 密钥身份验证模式为您创建新的 GraphQL API。您可以根据本教程后面的说明,使用控制台设置 GraphQL API 的其余部分,并针对它运行查询。

定义一个基本的帖子 API

现在,您已经设置了Amazon AppSync GraphQL API,可以设置一个基本架构,允许对帖子数据进行基本创建、检索和删除。

  1. 在 Amazon AppSync 控制台中,选择 Schema (架构) 选项卡。

  2. 我们将创建一个架构,用于定义用于添加和获取Post对象addPostPost类型和操作。在 “架构” 窗格中,将内容替换为以下代码:

    schema { query: Query mutation: Mutation } type Query { getPost(id: ID): 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! version: Int! }
  3. 选择 Save Schema (保存架构)

设置您的Amazon Dynama (表名称):

Amazon AppSync控制台可以帮助配置在 Amazon DynamoDB 表中存储您自己的Amazon资源所需的资源。在此步骤中,您将创建一个Amazon DynamoDB 表来存储您的帖子。您还将设置二级索引,我们稍后将使用该索引

创建您的Amazon DynamoDB 表

  1. 架构页面上,选择创建资源

  2. 选择 “使用现有类型”,然后选择Post类型。

  3. 在 “其他索引” 部分中,选择 “添加索引”。

  4. 命名索引author-index

  5. 将设置为Primary keyauthor,将Sort密钥设置为None

  6. 禁用 “自动生成 GraphQL”(在此示例中,我们自己编写解析器。)。

  7. 选择 Create(创建)

现在,您有一个名为的新数据源PostTable,您可以通过访问数据源来查看该数据源。您将使用此数据源将您的查询和变更链接到您的 Amazon DynamoDB 表。

设置 AaddPost 解析器(Amazon DynamoDB PutItem)

现在已经知道Amazon AppSync了 Amazon DynamoDB 表,您可以通过定义解析器将其链接到单个查询和突变。您创建的第一个解析器是使用的addPost管道解析器 JavaScript,它使您能够在 Amazon DynamoDB 表中创建帖子。管道解析器包含下列组件:

  • GraphQL 架构中的位置,用于附加解析程序。在本例中,您将设置 addPost 类型的 Mutation 字段的解析程序。当调用者调用突变时,将调用此解析器{ addPost(...){...} }

  • 一个或多个连接到数据源并实现数据访问代码的管道函数。在这种情况下,您想要定义一个使用PostTable数据源的函数,这样您就可以向 Amazon DynamoDB 表中添加条目。

  • 解析器代码定义了在流水线函数按顺序执行之前和之后执行的逻辑。如果您需要在第一个函数执行之前运行一些逻辑来设置管道,或者在解析之前对数据进行一些后处理,这很有用Query。在这种情况下,您不会实现任何特定的逻辑,只需返回管道执行的结果即可。

设置您的解析器

  1. 选择 Schema (架构) 选项卡。

  2. 在 “数据类型” 窗格中,找到该Mutation类型下的addPost字段,然后选择 “附加”。

  3. 解析器的代码编辑器已预先配置。这是您将在本教程中用于所有解析器的默认代码。这是简单的代码,在调用管道函数之前不进行任何预初始化。解析器仅在其响应处理程序中返回管道中最后一个函数的结果。

设置您的函数

  1. 选择 “添加函数”,然后选择 “创建新函数”。如果这是您的第一个函数,请改为选择创建函数

  2. 在下一个屏幕中,选择PostTable数据源。

  3. 命名该函数ADD_POST

  4. 在代码编辑器中,添加以下内容:

    import { util } from '@aws-appsync/utils'; export function request(ctx) { const { id, ...values } = ctx.arguments; values.ups = 1; values.downs = 0; values.version = 1; return dynamodbPutRequest({ key: {id}, values }); } export function response(ctx) { return ctx.result; } /** * Helper function to create a new item * @returns a PutItem request */ function dynamodbPutRequest({key, values}) { return { operation: 'PutItem', key: util.dynamodb.toMapValues(key), attributeValues: util.dynamodb.toMapValues(values), }; }
  5. 选择 Create(创建)

  6. 返回解析器屏幕,ADD_POST添加函数下拉列表中选择。

  7. 选择 Create(创建)

注意

必须在所有键和属性值上指定类型。在此示例中,您正在使用该util.dynamodb.toMapValues实用程序将您的 JavaScript 值自动转换为包含该类型的 Amazon DynamoDB 字段。

在本教程中,您指定了用于索引插入到 Amazon DynamoDB 的新项目的 GraphQLID! 类型作为客户端参数的一部分。 Amazon AppSync附带了一个名为的自动生成 ID 的实用程序util.autoId(),你也可以用它来生成ID(例如,const id = util.autoId())。然后,你可以简单地将的架构定义id: ID!排除在外addPost(),它就会被自动插入。您不会在本教程中使用这种方法,但是在写入 Amazon DynamoDB 表时应将其视为一种很好的做法。

有关可用实用程序的更多信息 JavaScript,请参阅解析器和函数的JavaScript 运行时功能。有关GetItem请求的更多信息,请参阅GetItem参考文档。有关类型的更多信息,请参阅类型系统(请求映射)参考文档。

调用 API 添加帖子

现在解析器已经配置完毕,Amazon AppSync可以将传入的addPost突变转换为 Amazon DynamoDBPutItem 操作。现在,您可以运行一个更改,在表中添加内容。

运行该操作

  1. 选择 Queries 选项卡。

  2. 在 “查询” 窗格中,添加以下变异:

    mutation addPost { addPost( id: 123 author: "AUTHORNAME" title: "Our first post!" content: "This is our first post." url: "https://aws.amazon.com/appsync/" ) { id author title content url ups downs version } }
  3. 选择 Execute query (执行查询)(橙色播放按钮)。新创建的帖子的结果应显示在 “查询” 窗格右侧的结果窗格中。如下所示:

    { "data": { "addPost": { "id": "123", "author": "AUTHORNAME", "title": "Our first post!", "content": "This is our first post.", "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 1 } } }

以下解释显示了发生了什么:

  1. Amazon AppSync 收到 addPost 更改请求。

  2. Amazon AppSync执行管道解析器的请求处理程序,然后执行该ADD_POST函数的请求处理程序。请求处理程序返回一个看起来像这样的对象:

    { "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "123" } }, "attributeValues" : { "author": { "S" : "AUTHORNAME" }, "title": { "S" : "Our first post!" }, "content": { "S" : "This is our first post." }, "url": { "S" : "https://aws.amazon.com/appsync/" }, "ups" : { "N" : 1 }, "downs" : { "N" : 0 }, "version" : { "N" : 1 } } }
  3. Amazon AppSync使用此值生成和执行Amazon DynamoDBPutItem 请求。

  4. Amazon AppSync 将 PutItem 请求的结果转换回 GraphQL 类型。

    { "id" : "123", "author": "AUTHORNAME", "title": "Our first post!", "content": "This is our first post.", "url": "https://aws.amazon.com/appsync/", "ups" : 1, "downs" : 0, "version" : 1 }
  5. ADD_POST函数响应处理程序立即返回结果 (return ctx.result),反过来,解析器的最终响应处理程序返回结果不变 (return ctx.prev.result)。

  6. 最终结果在 GraphQL 响应中可见。

设置 getPost 解析器(Amazon DynamoDB GetItem)

现在您可以向 Amazon DynamoDB 表添加数据,您需要设置getPost查询,这样它才能从表中检索数据。为了实现此目的,您要设置另一解析程序。

添加您的函数

  1. 选择 Schema (架构) 选项卡。

  2. 在右侧的数据类型窗格中,找到Query类型上的getPost、字段,然后选择附加

  3. 现在,设置您的函数。选择 “添加函数”,然后选择 “创建新函数”。

  4. 在下一个屏幕中,选择PostTable数据源。

  5. 将该函数命名为 GET_POST

  6. 在代码编辑器中,添加以下内容:

    import { util } from '@aws-appsync/utils'; export function request(ctx) { return dynamoDBGetItemRequest({ id: ctx.args.id }); } export function response(ctx) { return ctx.result; } /** * A helper function to get a DynamoDB item */ function dynamoDBGetItemRequest(key) { return { operation: 'GetItem', key: util.dynamodb.toMapValues(key), }; }
  7. 选择 Create(创建)

  8. 返回解析器屏幕,GET_POST添加函数下拉列表中选择。

  9. 选择 Create(创建)

调用 API 获取帖子

现在解析器已经设置好了,Amazon AppSync知道如何将传入的getPost查询转换为 Amazon DynamoDBGetItem 操作。现在,您可以运行查询,检索之前创建的文章。

运行您的查询

  1. 选择 Queries 选项卡。

  2. 在 “查询” 窗格中,添加以下代码:

    query getPost { getPost(id:123) { id author title content url ups downs version } }
  3. 选择 Execute query (执行查询)(橙色播放按钮)。

  4. 从 Amazon DynamoDB 检索到的帖子应显示在 “查询” 窗格右侧的结果窗格中。如下所示:

    { "data": { "getPost": { "id": "123", "author": "AUTHORNAME", "title": "Our first post!", "content": "This is our first post.", "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 1 } } }

或者,使用以下示例:

query getPost { getPost(id:123) { id author title } }

如果您的getPost查询只需要idauthor、和title,则可以将请求函数更改为使用投影表达式来仅指定您想要从 DynamoDB 表中获取的属性,以避免从 DynamoDB 向其传输不必要的数据Amazon AppSync。例如,请求函数可能看起来像下面的片段:

import { util } from '@aws-appsync/utils'; export function request(ctx) { return dynamoDBGetItemRequest({ id: ctx.args.id }); } export function response(ctx) { return ctx.result; } /** * A helper function to get a DynamoDB item */ function dynamoDBGetItemRequest(key) { return { operation: 'GetItem', key: util.dynamodb.toMapValues(key), projection: { expression : "#author, id, title", expressionNames : {"#author" : "author"} } } }

你也可以使用selectionSetList带宽getPost来表示expression

import { util } from '@aws-appsync/utils'; export function request(ctx) { return dynamoDBGetItemRequest(ctx); } export function response(ctx) { return ctx.result; } /** * A helper function to get a DynamoDB item */ function dynamoDBGetItemRequest(ctx) { return { operation: 'GetItem', key: util.dynamodb.toMapValues({ id: ctx.args.id}), projection: { expression : ctx.info.selectionSetList.join(",") } } }

创建 UpdatePost 变异(Amazon DynamoDB UpdateItem)

到目前为止,您可以在 Amazon DynamoDB 中创建和检索Post对象。接下来,你将设置一个新的突变来允许我们更新一个对象。与需要指定所有字段的addPost突变相比,此突变允许您仅指定要更改的字段。它还引入了一个新expectedVersion参数,允许您指定要修改的版本。您将设置一个条件,确保您正在修改对象的最新版本。您将使用UpdateItem Amazon DynamoDB 操作来完成此操作。

更新您的函数

  1. 选择 Schema (架构) 选项卡。

  2. Schema (架构) 窗格中修改 Mutation 类型,添加新的 updatePost 更改,如下所示:

    type Mutation { updatePost( id: ID!, author: String, title: String, content: String, url: String, expectedVersion: Int! ): Post addPost( id: ID! author: String! title: String! content: String! url: String! ): Post! }
  3. 选择 Save(保存)。

  4. 在右侧的数据类型窗格中,找到该Mutation类型上新创建的updatePost字段,然后选择附加

  5. 使用以下代码创建并附加使用PostTable数据源(调用UPDATE_POST)的新函数:

    import { util } from '@aws-appsync/utils'; export function request(ctx) { const { id, expectedVersion, ...values } = ctx.args; const condition = { version: { eq: expectedVersion } }; return dynamodbUpdateRequest({ key: {id}, values, condition }); } export function response(ctx) { const { error, result } = ctx; if (error) { util.appendError(error.message, error.type); } return result; } /** * Helper function to update an item in DynamoDB */ function dynamodbUpdateRequest({ key, values, condition }) { const sets = []; const removes = []; const expressionNames = {}; const expValues = {}; // iterate through the entries (key,value) of the values to be updated for (const [k, value] of Object.entries(values)) { // set the name expressionNames[`#${k}`] = k; if (value && value.length) { // if the value exists, add it to the list to be SET sets.push(`#${k} = :${k}`); expValues[`:${k}`] = value; } else { // if not, markt it to be REMOVEd removes.push(`#${k}`); } } let expression = sets.length ? `SET ${sets.join(', ')}` : ''; expression += removes.length ? ` REMOVE ${removes.join(', ')}` : ''; // increase the value of the version by 1 expressionNames['#version'] = 'version'; expValues[':version'] = 1; expression += ' ADD #version :version'; return { operation: 'UpdateItem', key: util.dynamodb.toMapValues(key), update: { expression, expressionNames, expressionValues: util.dynamodb.toMapValues(expValues), }, condition: JSON.parse( util.transform.toDynamoDBConditionExpression(condition) ), }; }

此函数使用Amazon DynamoDBUpdateItem,这与PutIem操作有很大不同。你不是写整篇文章,而是要求Amazon DynamoDB 更新某些属性。这是使用Amazon DynamoDB 更新表达式完成的。

dynamodbUpdateRequest函数循环遍历values对象中的所有参数。如果参数设置为某个值,它会要求Amazon AppSync Amazon DynamoDB 更新Amazon DynamoDB 中该对象的该属性。如果将该属性设置为null,它会要求Amazon AppSync Amazon DynamoDB 从Post对象中删除该属性。如果未指定参数,该属性会保留原样。它还会递增 version 字段。

还有一个新的 condition 部分。条件表达式允许您在执行操作之前根据已在 Amazon DynamoDB 中的对象的状态告知Amazon AppSync Amazon DynamoDB 请求是否应该成功。在这种情况下,只有当 Amazon DynamoDB 中当前项目的version字段与expectedVersion参数完全匹配时,您才希望UpdateItem请求成功。

有关这些条件表达式的更多信息,请参阅条件表达式的更多信息,请参阅条件表达式的更多信息。

有关UpdateItem请求的更多信息,请参阅UpdateItem文档。

有关如何编写更新表达式的更多信息,请参阅 Dynamice ( UpdateExpressions表名称):

调用 API 更新帖子

让我们尝试使用新的解析器更新Post对象。

更新您的对象

  1. 选择 Queries 选项卡。

  2. 在 “查询” 窗格中,添加以下变异。你还需要将id参数更新为你之前记下的值:

    mutation updatePost { updatePost( id:123 title: "An empty story" content: null expectedVersion: 1 ) { id author title content url ups downs version } }
  3. 选择 Execute query (执行查询)(橙色播放按钮)。

  4. Amazon DynamoDB 中更新的帖子应显示在 “查询” 窗格右侧的结果窗格中。如下所示:

    { "data": { "updatePost": { "id": "123", "author": "A new author", "title": "An empty story", "content": null, "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 3 } } }

在此请求中,您要求Amazon AppSync Amazon DynamoDB 仅更新titlecontent字段。所有其他字段都保持不变(除了增加version字段之外)。您将该title属性设置为新值并从帖子中删除了该content属性。authorurlupsdowns 字段没有变化。尝试再次执行突变请求,同时保持请求完全不变。您可以看到类似以下内容的响应:

{ "data": { "updatePost": null }, "errors": [ { "path": [ "updatePost" ], "data": null, "errorType": "DynamoDB:ConditionalCheckFailedException", "errorInfo": null, "locations": [ { "line": 2, "column": 3, "sourceName": null } ], "message": "The conditional request failed (Service: DynamoDb, Status Code: 400, Request ID: TSRLD79IMVB91KRI4CITA42LTNVV4KQNSO5AEMVJF66Q9ASUAAJG)" }, { "path": [ "updatePost", "id" ], "locations": null, "message": "Cannot return null for non-nullable type: 'ID' within parent 'Post' (/updatePost/id)" } ] }

请求失败,因为条件表达式的计算结果为false

  1. 首次运行请求时,Amazon DynamoDB 中帖子version字段的值为1,该值与expectedVersion参数相匹配。请求成功,这意味着该version字段在 Amazon DynamoDB 中递增至2

  2. 第二次运行请求时,Amazon DynamoDB 中帖子version字段的值为2,该值与expectedVersion参数不匹配。

这种模式通常被称为乐观锁

创建投票变体(Amazon DynamoDB UpdateItem)

Post类型包含upsdowns字段,用于记录赞成票和反对票。但是,目前,API 不允许我们对它们做任何事情。让我们添加一个变异来让我们对帖子投赞成票和反对票。

添加你的突变

  1. 选择 Schema (架构) 选项卡。

  2. 架构窗格中,修改Mutation类型并添加DIRECTION枚举以添加新的投票突变:

    type Mutation { vote(id: ID!, direction: DIRECTION!): Post updatePost( id: ID!, author: String, title: String, content: String, url: String, expectedVersion: Int! ): Post addPost( author: String!, title: String!, content: String!, url: String! ): Post! } enum DIRECTION { UP DOWN }
  3. 选择 Save(保存)。

  4. 在右侧的数据类型窗格中,找到该类型上新创建的vote字段,然后选择Mutation Attac h

  5. 重复这些步骤以配置新的 JavaScript 管道解析器(使用默认代码)。然后,创建并附加一个使用以下代码调VOTE用的新函数:

    import { util } from '@aws-appsync/utils'; export function request(ctx) { const { id, direction } = ctx.arguments; const field = direction === 'UP' ? 'ups' : 'downs'; return { operation: 'UpdateItem', key: util.dynamodb.toMapValues({ id }), update: { expression: `ADD ${field} :plusOne, version :plusOne`, expressionValues: util.dynamodb.toMapValues({ ':plusOne': 1 }), }, }; } export function response(ctx) { return ctx.result; }
  6. 附加函数。

调用 API 为帖子加赞或减票

现在,新的解析器已经设置完毕,Amazon AppSync知道如何将传入upvotePostdownvote突变转换为 Amazon DynamoDBUpdateItem 操作。现在您可以运行更改,为之前创建的文章投赞同票或反对票。

来运行你的突变

  1. 选择 Queries 选项卡。

  2. 在 “查询” 窗格中,添加以下变异。你还需要将id参数更新为你之前记下的值:

    mutation votePost { vote(id:123, direction: UP) { id author title content url ups downs version } }
  3. 选择 Execute query (执行查询)(橙色播放按钮)。

  4. Amazon DynamoDB 中更新的帖子应显示在 “查询” 窗格右侧的结果窗格中。如下所示:

    { "data": { "vote": { "id": "123", "author": "A new author", "title": "An empty story", "content": null, "url": "https://aws.amazon.com/appsync/", "ups": 6, "downs": 0, "version": 4 } } }
  5. 再选择几次 (执行查询) 按钮。1每次执行查询时,您应该会看到upsversion字段递增。

  6. 将查询更改为使用不同的查询进行调用DIRECTION

    mutation votePost { vote(id:123, direction: DOWN) { id author title content url ups downs version } }
  7. 选择 Execute query (执行查询)(橙色播放按钮)。

    这次,您应该看到downsversion字段在1每次运行查询时递增。

设置 DeletePost 解析器(Amazon DynamoDB DeleteItem)

接下来,你需要创建一个变异来删除帖子。您将使用DeleteItem Amazon DynamoDB 操作来完成此操作。

添加你的突变

  1. 选择 Schema (架构) 选项卡。

  2. 架构窗格中,修改Mutation类型以添加新的deletePost突变:

    type Mutation { deletePost(id: ID!, expectedVersion: Int): Post vote(id: ID!, direction: DIRECTION!): Post updatePost( id: ID!, author: String, title: String, content: String, url: String, expectedVersion: Int! ): Post addPost( id: ID! author: String!, title: String!, content: String!, url: String! ): Post! }
  3. 这次你将该expectedVersion字段设为可选。接下来,选择 “保存”。

  4. 在右侧的数据类型窗格中,在Mutation类型中找到新创建的delete字段,然后选择附加

  5. 重复这些步骤,使用直通代码配置新的 JavaScript 管道解析器。然后,创建并附加一个使用以下代码调DELETE_POST用的新函数:

    import { util } from '@aws-appsync/utils'; export function request(ctx) { const { id, expectedVersion } = ctx.arguments; const request = { operation: 'DeleteItem', key: util.dynamodb.toMapValues({ id }), }; if (expectedVersion) { request.condition = JSON.parse( util.transform.toDynamoDBConditionExpression({ or: [ { id: { attributeExists: false } }, { version: { eq: expectedVersion } }, ], }) ); } return request; } export function response(ctx) { const { error, result } = ctx; if (error) { util.appendError(error.message, error.type); } return result; }
    注意

    expectedVersion参数是可选参数。如果调用者在请求中设置了expectedVersion参数,则请求处理程序会添加一个条件,该条件仅在项目已被删除或者 Amazon DynamoDB 中帖子的version属性完全匹配时才允许DeleteItem请求成功expectedVersion。如果未设置此参数,则 DeleteItem 请求中不指定条件表达式。无论该物品的价值如何,无论该物品是否存在于 Amazon DynamoDB 中,它都会成功。version

    即使您要删除项目,也可以返回已删除的项目(如果该项目尚未删除)。

有关DeleteItem请求的更多信息,请参阅DeleteItem文档。

调用 API 删除帖子

现在解析器已经设置好了,Amazon AppSync知道如何将传入的delete突变转换为 Amazon DynamoDBDeleteItem 操作。现在,您可以运行更改,从表中删除一些内容。

来运行你的突变

  1. 选择 Queries 选项卡。

  2. 在 “查询” 窗格中,添加以下变异。你还需要将 id 参数更新为你之前记下的值。

    mutation deletePost { deletePost(id:123) { id author title content url ups downs version } }
  3. 选择 Execute query (执行查询)(橙色播放按钮)。

  4. 该帖子已从Amazon Dynama (表中删除)。请注意,这会Amazon AppSync返回从 Amazon DynamoDB 中删除的项目的值,该值应显示在 “查询” 窗格右侧的结果窗格中。如下所示:

    { "data": { "deletePost": { "id": "123", "author": "A new author", "title": "An empty story", "content": null, "url": "https://aws.amazon.com/appsync/", "ups": 6, "downs": 4, "version": 12 } } }
  5. 仅当对的调用是实际将其从 Amazon DynamoDB 中删除的调用时,才会返回该值。deletePost再次选择 Execute query (执行查询)

  6. 调用仍然成功,但不返回任何值:

    { "data": { "deletePost": null } }
  7. 现在,让我们尝试删除一篇帖子,但这次要指定一个expectedValue。首先,你需要创建一个新帖子,因为你刚刚删除了迄今为止一直在使用的帖子。

  8. 在 “查询” 窗格中,添加以下变异:

    mutation addPost { addPost( id:123 author: "AUTHORNAME" title: "Our second post!" content: "A new post." url: "https://aws.amazon.com/appsync/" ) { id author title content url ups downs version } }
  9. 选择 Execute query (执行查询)(橙色播放按钮)。

  10. 新创建的帖子的结果应显示在 “查询” 窗格右侧的结果窗格中。记下新创建id的对象的内容,因为过一会儿你就需要它了。如下所示:

    { "data": { "addPost": { "id": "123", "author": "AUTHORNAME", "title": "Our second post!", "content": "A new post.", "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 1 } } }
  11. 现在,让我们尝试删除该帖子,但为 e xpectedVersion 输入了错误的值。在 “查询” 窗格中,添加以下变异。你还需要将id参数更新为你之前记下的值:

    mutation deletePost { deletePost( id:123 expectedVersion: 9999 ) { id author title content url ups downs version } }
  12. 选择 Execute query (执行查询)(橙色播放按钮)。返回以下结果:

    { "data": { "deletePost": null }, "errors": [ { "path": [ "deletePost" ], "data": null, "errorType": "DynamoDB:ConditionalCheckFailedException", "errorInfo": null, "locations": [ { "line": 2, "column": 3, "sourceName": null } ], "message": "The conditional request failed (Service: DynamoDb, Status Code: 400, Request ID: 7083O037M1FTFRK038A4CI9H43VV4KQNSO5AEMVJF66Q9ASUAAJG)" } ] }
  13. 请求失败,因为条件表达式的计算结果为false。Amazon DynamoDB 中帖子的值与参数中expectedValue指定的值不匹配。version对象的当前值返回到 GraphQL 响应的 data 部分的 errors 字段中。重试请求,但更正 expectedVersion

    mutation deletePost { deletePost( id:123 expectedVersion: 1 ) { id author title content url ups downs version } }
  14. 选择 Execute query (执行查询)(橙色播放按钮)。

    这次请求成功,并返回从 Amazon DynamoDB 中删除的值:

    { "data": { "deletePost": { "id": "123", "author": "AUTHORNAME", "title": "Our second post!", "content": "A new post.", "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 1 } } }
  15. 再次选择 Execute query (执行查询)。调用仍然成功,但这次没有返回任何值,因为该帖子已在 Amazon DynamoDB 中删除。

    { "data": { "deletePost": null } }

设置 AallPost 解析器(Amazon DynamoDB 扫描)

到目前为止,只有当你知道你想看id的每篇文章时,API 才有用。让我们添加新的解析程序,它可以返回表中的所有文章。

添加你的突变

  1. 选择 Schema (架构) 选项卡。

  2. Schema (架构) 窗格中修改 Query 类型,添加新的 allPost 查询,如下所示:

    type Query { allPost(limit: Int, nextToken: String): PaginatedPosts! getPost(id: ID): Post }
  3. 添加新 PaginationPosts 类型:

    type PaginatedPosts { posts: [Post!]! nextToken: String }
  4. 选择 Save(保存)。

  5. 在右侧的数据类型窗格中,在Query类型中找到新创建的allPost字段,然后选择附加

  6. 重复这些步骤,使用直通代码配置新的 JavaScript 管道解析器。然后使用以下代码创建并附加一个新函数:

    import { util } from '@aws-appsync/utils'; export function request(ctx) { const { limit = 20, nextToken } = ctx.arguments; return { operation: 'Scan', limit, nextToken }; } export function response(ctx) { const { items: posts = [], nextToken } = ctx.result; return { posts, nextToken }; }

    此函数的请求处理程序需要两个可选参数:

    • limit-指定单个调用中要返回的最大项目数。

    • nextToken-用于检索下一组结果(稍后我们将显示的值nextToken来自哪里)。

  7. 附加函数并创建解析器。

有关Scan请求的更多信息,请参阅扫描参考文档。

调用 API 扫描所有帖子

现在解析器已经设置好了,Amazon AppSync知道如何将传入的allPost查询转换为 Amazon DynamoDBScan 操作。现在您可以扫描整个表,检索所有文章。在进行尝试之前,您需要在表中填充一些数据,因为您已经删除了之前使用的所有内容。

添加数据和查询

  1. 选择 Queries 选项卡。

  2. 在 “查询” 窗格中,添加以下变异:

    mutation addPost { post1: addPost(id:1 author: "AUTHORNAME" title: "A series of posts, Volume 1" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post2: addPost(id:2 author: "AUTHORNAME" title: "A series of posts, Volume 2" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post3: addPost(id:3 author: "AUTHORNAME" title: "A series of posts, Volume 3" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post4: addPost(id:4 author: "AUTHORNAME" title: "A series of posts, Volume 4" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post5: addPost(id:5 author: "AUTHORNAME" title: "A series of posts, Volume 5" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post6: addPost(id:6 author: "AUTHORNAME" title: "A series of posts, Volume 6" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post7: addPost(id:7 author: "AUTHORNAME" title: "A series of posts, Volume 7" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post8: addPost(id:8 author: "AUTHORNAME" title: "A series of posts, Volume 8" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post9: addPost(id:9 author: "AUTHORNAME" title: "A series of posts, Volume 9" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } }
  3. 选择 Execute query (执行查询)(橙色播放按钮)。

  4. 现在,让我们扫描表,每次返回 5 个结果。在 “查询” 窗格中,添加以下查询:

    query allPost { allPost(limit: 5) { posts { id title } nextToken } }
  5. 选择 Execute query (执行查询)(橙色播放按钮)。

    前五篇文章应显示在 “查询” 窗格右侧的结果窗格中。如下所示:

    { "data": { "allPost": { "posts": [ { "id": "5", "title": "A series of posts, Volume 5" }, { "id": "1", "title": "A series of posts, Volume 1" }, { "id": "6", "title": "A series of posts, Volume 6" }, { "id": "9", "title": "A series of posts, Volume 9" }, { "id": "7", "title": "A series of posts, Volume 7" } ], "nextToken": "<token>" } } }
  6. 您收到了五个结果nextToken,还有一个可以用来获得下一组结果。更新 allPost 查询,加入上一组结果的 nextToken

  7. query allPost { allPost( limit: 5 nextToken: "<token>" ) { posts { id author } nextToken } }
  8. 选择 Execute query (执行查询)(橙色播放按钮)。

    其余四篇文章应显示在 “查询” 窗格右侧的结果窗格中。这组结果nextToken中没有,因为你已经浏览了所有九篇帖子,没有剩下任何帖子。如下所示:

    { "data": { "allPost": { "posts": [ { "id": "2", "title": "A series of posts, Volume 2" }, { "id": "3", "title": "A series of posts, Volume 3" }, { "id": "4", "title": "A series of posts, Volume 4" }, { "id": "8", "title": "A series of posts, Volume 8" } ], "nextToken": null } } }

设置 allPostsBy作者解析器(Amazon DynamoDB 查询)

除了扫描Amazon DynamoDB 中的所有帖子外,您还可以查询 Amazon DynamoDB 以检索特定作者创建的帖子。您之前创建的 Amazon DynamoDB 表已经有一个GlobalSecondaryIndex调用,author-index您可以将其与 Amazon DynamoDBQuery 操作一起使用,以检索特定作者创建的所有帖子。

添加您的查询

  1. 选择 Schema (架构) 选项卡。

  2. Schema (架构) 窗格中修改 Query 类型,添加新的 allPostsByAuthor 查询,如下所示:

    type Query { allPostsByAuthor(author: String!, limit: Int, nextToken: String): PaginatedPosts! allPost(limit: Int, nextToken: String): PaginatedPosts! getPost(id: ID): Post }

    请注意,这使用的PaginatedPosts类型与您在allPost查询中使用的类型相同。

  3. 选择 Save(保存)。

  4. 在右侧的数据类型窗格中,找到该类型上新创建的allPostsByAuthor字段,然后选择Query Attac h

  5. 创建您的管道解析器,然后使用此代码创建一个函数并将其附加。

    import { util } from '@aws-appsync/utils'; export function request(ctx) { const { limit = 20, nextToken, author } = ctx.arguments; const index = 'author-index'; const query = JSON.parse( util.transform.toDynamoDBConditionExpression({ author: { eq: author } }) ); return { operation: 'Query', index, query, limit, nextToken }; } export function response(ctx) { const { items: posts = [], nextToken } = ctx.result; return { posts, nextToken }; }
  6. 像解allPost析器一样,这个解析器有两个可选参数:

    • limit-指定单个调用中要返回的最大项目数。

    • nextToken-检索下一组结果(的值nextToken可以从之前的调用中获得)。

  7. 选择 Create(创建)

有关该Query请求的更多信息,请参阅查询参考中的。

调用 API 查询作者的所有帖子

现在解析器已经设置好了,Amazon AppSync知道如何将传入的allPostsByAuthor突变转换为针对author-index索引的 DynamoDBQuery 操作。现在,您可以查询表,检索某一作者的所有文章。

但是,在此之前,让我们再在表格中填充一些帖子,因为到目前为止每篇文章都有相同的作者。

添加数据和查询

  1. 选择 Queries 选项卡。

  2. 在 “查询” 窗格中,添加以下变异:

    mutation addPost { post1: addPost(id:10 author: "Nadia" title: "The cutest dog in the world" content: "So cute. So very, very cute." url: "https://aws.amazon.com/appsync/" ) { author, title } post2: addPost(id:11 author: "Nadia" title: "Did you know...?" content: "AppSync works offline?" url: "https://aws.amazon.com/appsync/" ) { author, title } post3: addPost(id:12 author: "Steve" title: "I like GraphQL" content: "It's great" url: "https://aws.amazon.com/appsync/" ) { author, title } }
  3. 选择 Execute query (执行查询)(橙色播放按钮)。

  4. 现在,让我们查询表,返回作者为 Nadia 的所有文章。在 “查询” 窗格中,添加以下查询:

    query allPostsByAuthor { allPostsByAuthor(author: "Nadia") { posts { id title } nextToken } }
  5. 选择 Execute query (执行查询)(橙色播放按钮)。由撰写的所有帖子都Nadia应显示在 “查询” 窗格右侧的 “结果” 窗格中。如下所示:

    { "data": { "allPostsByAuthor": { "posts": [ { "id": "10", "title": "The cutest dog in the world" }, { "id": "11", "title": "Did you know...?" } ], "nextToken": null } } }
  6. Query 的分页方式与 Scan 相同。例如,如果我们查找作者为 AUTHORNAME 的所有文章,每次显示 5 个结果。

  7. 在 “查询” 窗格中,添加以下查询:

    query allPostsByAuthor { allPostsByAuthor( author: "AUTHORNAME" limit: 5 ) { posts { id title } nextToken } }
  8. 选择 Execute query (执行查询)(橙色播放按钮)。由撰写的所有帖子都AUTHORNAME应显示在 “查询” 窗格右侧的 “结果” 窗格中。如下所示:

    { "data": { "allPostsByAuthor": { "posts": [ { "id": "6", "title": "A series of posts, Volume 6" }, { "id": "4", "title": "A series of posts, Volume 4" }, { "id": "2", "title": "A series of posts, Volume 2" }, { "id": "7", "title": "A series of posts, Volume 7" }, { "id": "1", "title": "A series of posts, Volume 1" } ], "nextToken": "<token>" } } }
  9. 用上次查询返回的值更新 nextToken 参数,如下所示:

    query allPostsByAuthor { allPostsByAuthor( author: "AUTHORNAME" limit: 5 nextToken: "<token>" ) { posts { id title } nextToken } }
  10. 选择 Execute query (执行查询)(橙色播放按钮)。其余撰写的帖子AUTHORNAME应显示在 “查询” 窗格右侧的结果窗格中。如下所示:

    { "data": { "allPostsByAuthor": { "posts": [ { "id": "8", "title": "A series of posts, Volume 8" }, { "id": "5", "title": "A series of posts, Volume 5" }, { "id": "3", "title": "A series of posts, Volume 3" }, { "id": "9", "title": "A series of posts, Volume 9" } ], "nextToken": null } } }

使用集合

到目前为止,该Post类型一直是平面键/值对象。您还可以使用Amazon AppSync DynamoDB 函数对复杂对象进行建模,例如集合、列表和地图。让我们更新 Post 类型,加入标签。帖子可以有零个或多个标签,这些标签作为字符串集存储在 DynamoDB 中。您还将设置一些更改,用于添加并删除标签;还要用一个新查询扫描具有特定标签的文章。

设置您的数据

  1. 选择 Schema (架构) 选项卡。

  2. Schema (架构) 窗格中修改 Post 类型,添加新的 tags 字段,如下所示:

    type Post { id: ID! author: String title: String content: String url: String ups: Int! downs: Int! version: Int! tags: [String!] }
  3. Schema (架构) 窗格中修改 Query 类型,添加新的 allPostsByTag 查询,如下所示:

    type Query { allPostsByTag(tag: String!, limit: Int, nextToken: String): PaginatedPosts! allPostsByAuthor(author: String!, limit: Int, nextToken: String): PaginatedPosts! allPost(limit: Int, nextToken: String): PaginatedPosts! getPost(id: ID): Post }
  4. Schema (架构) 窗格中修改 Mutation 类型,添加新的 addTagremoveTag 更改,如下所示:

    type Mutation { addTag(id: ID!, tag: String!): Post removeTag(id: ID!, tag: String!): Post deletePost(id: ID!, expectedVersion: Int): Post upvotePost(id: ID!): Post downvotePost(id: ID!): Post updatePost( id: ID!, author: String, title: String, content: String, url: String, expectedVersion: Int! ): Post addPost( author: String!, title: String!, content: String!, url: String! ): Post! }
  5. 选择 Save(保存)。

  6. 在右侧的数据类型窗格中,找到该类型上新创建的allPostsByTag字段,然后选择Query Attac h

  7. 使用以下代码创建一个名SCAN_BY_TAG为的新函数,该函数附加到您的数据源:

    import { util } from '@aws-appsync/utils'; export function request(ctx) { const { limit = 20, nextToken, tag } = ctx.arguments; const filter = JSON.parse( util.transform.toDynamoDBFilterExpression({ tags: { contains: tag, }, }) ); return { operation: 'Scan', limit, filter, nextToken }; } export function response(ctx) { const { items: posts = [], nextToken } = ctx.result; return { posts, nextToken }; }
  8. 将该函数添加到您的解析器中,然后选择 Create(创建)。

  9. 在右侧的数据类型窗格中,找到该类型上新创建的addTag字段,然后选择Mutation Attac h

  10. 使用以下代码创建一个名ADD_TAG为的新函数,该函数附加到您的数据源:

    import { util } from '@aws-appsync/utils'; export function request(ctx) { const { id, tag } = ctx.arguments; const expressionValues = util.dynamodb.toMapValues({ ':plusOne': 1 }); expressionValues[':tags'] = util.dynamodb.toStringSet([tag]); return { operation: 'UpdateItem', key: util.dynamodb.toMapValues({ id }), update: { expression: `ADD tags :tags, version :plusOne`, expressionValues, }, }; } export function response(ctx) { return ctx.result; }
  11. 将该函数添加到您的解析器中,然后选择 Create(创建)。

  12. 在右侧的数据类型窗格中,找到该类型上新创建的removeTag字段,然后选择Mutation Attac h

  13. 使用以下代码创建一个名REMOVE_TAG为的新函数,该函数附加到您的数据源:

    import { util } from '@aws-appsync/utils'; export function request(ctx) { const { id, tag } = ctx.arguments; const expressionValues = util.dynamodb.toMapValues({ ':plusOne': 1 }); expressionValues[':tags'] = util.dynamodb.toStringSet([tag]); return { operation: 'UpdateItem', key: util.dynamodb.toMapValues({ id }), update: { expression: `DELETE tags :tags ADD version :plusOne`, expressionValues, }, }; } export function response(ctx) { return ctx.result; }
  14. 将该函数添加到您的解析器中,然后选择 Create(创建)。

调用 API 以处理标签

现在,您已经设置了解析器,Amazon AppSync知道如何将传入的addTagremoveTag、和allPostsByTag请求转换为 DynamoDBUpdateItemScan操作。我们选择您之前创建的一个文章进行尝试。例如,我们使用作者为 Nadia 的一篇文章。

使用标签

  1. 选择 Queries 选项卡。

  2. 在 “查询” 窗格中,添加以下查询:

    query allPostsByAuthor { allPostsByAuthor( author: "Nadia" ) { posts { id title } nextToken } }
  3. 选择 Execute query (执行查询)(橙色播放按钮)。

  4. Nadia 的所有帖子都应显示在 “查询” 窗格右侧的 “结果” 窗格中。如下所示:

    { "data": { "allPostsByAuthor": { "posts": [ { "id": "10", "title": "The cutest dog in the world" }, { "id": "11", "title": "Did you known...?" } ], "nextToken": null } } }
  5. 让我们使用标题为 “世界上最可爱的狗” 的那个。记下其 id,因为您稍后将用到它。现在,让我们尝试添加 dog 标签。

  6. 在 “查询” 窗格中,添加以下变异。您还需要更新 id 参数,改为您之前记下的值。

    mutation addTag { addTag(id:10 tag: "dog") { id title tags } }
  7. 选择 Execute query (执行查询)(橙色播放按钮)。该帖子已使用新标签更新:

    { "data": { "addTag": { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog" ] } } }
  8. 您可以添加更多标签。更新突变以将tag参数更改为puppy

    mutation addTag { addTag(id:10 tag: "puppy") { id title tags } }
  9. 选择 Execute query (执行查询)(橙色播放按钮)。该帖子已使用新标签更新:

    { "data": { "addTag": { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog", "puppy" ] } } }
  10. 您也可以删除标签。在 “查询” 窗格中,添加以下变异。你还需要将id参数更新为你之前记下的值:

    mutation removeTag { removeTag(id:10 tag: "puppy") { id title tags } }
  11. 选择 Execute query (执行查询)(橙色播放按钮)。文章已更新,puppy 标签已删除。

    { "data": { "addTag": { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog" ] } } }
  12. 您还可以搜索所有带有标签的帖子。在 “查询” 窗格中,添加以下查询:

    query allPostsByTag { allPostsByTag(tag: "dog") { posts { id title tags } nextToken } }
  13. 选择 Execute query (执行查询)(橙色播放按钮)。将返回具有 dog 标签的所有文章,如下所示:

    { "data": { "allPostsByTag": { "posts": [ { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog", "puppy" ] } ], "nextToken": null } } }

结论

在本教程中,您构建了一个 API,允许您使用Amazon AppSync GraphQL 在 DynamoDB 中操作Post对象。

要进行清理,可以从控制台中删除Amazon AppSync GraphQL API。

要删除与您的 DynamoDB 表关联的角色,请在数据源表中选择您的数据源,然后单击编辑。记下 “创建” 或 “使用现有角色” 下的角色值。前往 IAM 控制台删除该角色。

要删除您的 DynamoDB 表名称),请在数据源中单击表的名称。这将带您进入 DynamoDB 控制台,您可以在其中删除表。