亚马逊云科技 AppSync 管道解析器和函数现在支持其他数组方法和箭头函数

作者: Brice Pellé | 202

亚马逊云科技 AppSync 是一项托管服务,可轻松构建将应用程序连接到数据的可扩展 API。开发人员每天使用 AppSync 来构建与 亚马逊 Dynamo D B 、亚马逊云科技 L ambda 和 HTTP API 等数据源进行交互的 GraphQL API。 有了 AppSync,开发人员可以使用 JavaScript 编写解析器,然后在 AppSync 的 APPSYNC_JS 运行时上运行他们的代码。

今天,我们正在向 APPSYNC_JS 运行时添加功能,支持数组上的以下高阶函数:

  • 数组.prototype.foreach
  • 数组.prototype.map
  • 数组.prototype.flatmap
  • 数组、原型、过滤器
  • 数组。原型。还原
  • 数组。原型。ReduceRight
  • 数组.prototype.find
  • 数组.prototype.some
  • 数组、原型、每一个
  • Array.prototype.findex
  • 数组.prototype.findLast
  • Array.prototype.findlast

通过此更新,APPSYNC_JS 现在还支持箭头函数,可以在我们的解析器或函数代码中的任何级别上定义箭头函数。这允许编写这样的代码:

// filter the array to return odd numbers only
export function response() {
  return [1,2,3,4,5].filter(x => x % 2)
}

要么

// return the array sum
export function response() {
  return [1,2,3,4,5].reduce((sum,x) => sum + x)
}

export function response() {
  // define a test function
  const test = (x) => x > 42
  // return the first match (or null)
  return [12, 34, 56, 9, 75].find(test)
}

有了箭头函数和新的数组函数支持,我们现在可以紧凑地编写业务逻辑。这使得编写代码来解决数组和对象的常见问题变得更加容易,我们也可以使用它们来编写更复杂的功能和实用程序。我们在下面举几个例子。

编写一个库来更新 DynamoDB 表中的项目

在处理 Amazon DynamoDB 表中的数据时,更新项目是一项常见任务。我们可以使用新引入的数组函数来编写一个用于创建 updateItem 请求的帮助器。给定架构

 

type User {
  id: ID!
  email: String!
  name: String
  status: String
}

input UpdateUserInput {
    id: ID!
    email: String
    name: String
}

type Mutation {
  updateUser(input: UpdateUserInput!): User
}

我们可以定义以下 APPSYNC_JS 函数来附加到我们的解析器。我们定义了一个 更新 函数,它使用 Array.reduc e 来迭代值列表并创建 updateItem 请求。

import { util } from '@aws-appsync/utils'

export function request(ctx) {
  const { input: { id, ...values } } = ctx.args
  return update({ id }, values)
}

export function response(ctx) {
  return ctx.result
}

// build an UpdateItem request to SET or DELETE attributes
// of an item identified by `key`.
function update(key, values) {
  const exp = Object.entries(values).reduce(
    (prev, [key, value]) => {
      // expression attribute name is a placeholder that you use in an
      // Amazon DynamoDB expression as an alternative to an actual attribute name.
      prev.names[`#${key}`] = key
      if (value) {
        // if a value exist:
        // Use the SET action in an update expression to add one or
        // more attributes to an item. 
        prev.sets.push(`#${key} = :${key}`)
        // Expression attribute values in Amazon DynamoDB are substitutes
        // for the actual values that you want to compare
        prev.values[`:${key}`] = value
      } else {
        // if the value is null, add it to a list and:
        // Use the REMOVE action in an update expression to remove
        // one or more attributes from an item in Amazon DynamoDB
        prev.removes.push(`#${key}`)
      }
      return prev
    },
    { sets: [], removes: [], names: {}, values: {} }
  )

  // create the update expression
  let expression = exp.sets.length ? `SET ${exp.sets.join(', ')}` : ''
  expression += exp.removes.length ? ` REMOVE ${exp.removes.join(', ')}` : ''

  return {
    operation: 'UpdateItem',
    key: util.dynamodb.toMapValues(key),
    update: {
      expression,
      expressionNames: exp.names,
      expressionValues: util.dynamodb.toMapValues(exp.values),
    },
  }
}

将函数附加到我们的 up datedU ser 变异的管道解析器后,我们可以通过以下操作更新用户名并删除其状态:

mutation UPDATE {
  updateUser(input: {
    id: "123-32-xyz", email: "hsperry@fake.net", name: "Helen S. Perry", status: null
  }) {
    id
    email
    name
    status
  }
}

处理单表设计查询

AppSync 允许定义使用单表设计或多表方法的 DynamoDB 数据源。在单表设计中,不同的数据类型存储在一个 DynamoDB 表中。通过单表设计,我们可以通过单个查询从单个表中检索所有项目。例如,我们可以更新架构,以便在单个请求中检索用户及其订单。首先,我们更新架构,如下所示。用户有订单,每个订单由零件或多件商品组成。

type User {
    id: ID!
    email: String!
    name: String
    status: String
    orders: [Order]
}

type Order {
    id: ID
    items: [Item]
    createdOn: AWSDateTime!
    updatedOn: AWSDateTime!
}

type Item {
    id: ID!
    orderId: ID!
    description: String!
    shipped: Boolean!
    shippedOn: AWSDateTime!
}

type Query {
    getUserAndOrderDetails(id: ID!): User
}

数据使用复合键存储在 DynamoDB 表中:

  • 分区键 ID
  • 一个名为 SK 的排序键

为了获取有关用户及其订单和商品的数据,我们在表中查询分区键等于用户 ID 的所有项目。表中的每个项目都有一个 __typename 属性,用于指定项目类型(例如: 用户 订单或 项目)。

我们将以下 APPSYNC_JS 函数附加到 getUserAndorderDetails 解析器中:

import { util } from "@aws-appsync/utils";

export function request(ctx) {
  const { id } = ctx.args;
  let query = { id: { eq: id } };
  query = JSON.parse(util.transform.toDynamoDBConditionExpression(query));
  return { operation: "Query", query };
}

export function response(ctx) {
  let { items } = ctx.result;
  // find the user
  const user = items.find((item) => item.__typename === "User");
  
  // if no user is found, return null
  if (!user) {
    console.log("could not find user in reponse items");
    return null;
  }
  
  const orders = {};
  const orderItems = [];
  
  // identify each `Order` and `OrderItem` in the returned items
  items.forEach((item) => {
    switch (item.__typename) {
      case "Order":
        orders[item.SK] = { ...item, id: item.SK, items: [] };
        break;
      case "Item":
        orderItems.push({ ...item, id: item.SK });
        break;
      default:
        break;
    }
  });
  
  // associated each order item with an order
  orderItems.forEach((item) => orders[item.orderId].items.push(item));
  
  // finally, assign the orders to the user
  user.orders = Object.values(orders);
  return user;
}

在响应中,我们使用 Array.find 方法找到 用户 项目。然后,我们使用 Array.forEac h 遍历商品,找到每个订单和订单商品。然后,我们将每件商品与其订单关联起来。现在,我们可以使用查询以适合客户的形式获取数据:

query MyQuery {
  getUserAndOrderDetails(id: "<user-id>") {
    id
    name
    email
    status
    orders {
      id
      items {
        id
      }
    }
  }
}

结论

在这篇文章中,我们介绍了 APPSYNC_JS 中引入的新数组函数和箭头函数表示法。我们看到了这些更新后的功能如何轻松处理数组和对象。我们还看到了在解析器中处理数据时如何使用它们来解决常见的复杂问题。通过查看 APPSYNC_JS 支持的 内置对象和函数 ,以及阅读 AppSync 的 DynamoDB JavaScript 解析器教程 ,你可以立即在任何可用 AppS yn c 的地区开始使用。