

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

# AWS AppSync JavaScript 解析器上下文对象引用
<a name="resolver-context-reference-js"></a>

AWS AppSync 定义了一组用于处理请求和响应处理程序的变量和函数。这样，就可以更轻松地通过 GraphQL 对数据进行逻辑操作。本文档介绍了这些函数并提供了示例。

## 使用 `context`
<a name="accessing-the-context-js"></a>

请求和响应处理程序的 `context` 参数是一个对象，它保存解析器调用的所有上下文信息。它具有以下结构：

```
type Context = {
  arguments: any;
  args: any;
  identity: Identity;
  source: any;
  error?: {
    message: string;
    type: string;
  };
  stash: any;
  result: any;
  prev: any;
  request: Request;
  info: Info;
};
```

**注意**  
您经常会发现 `context` 对象是作为 `ctx` 引用的。

`context` 对象中的每个字段定义如下：

### `context` 字段
<a name="accessing-the-context-list-js"></a>

** `arguments` **  
包含该字段的所有 GraphQL 参数的映射。

** `identity` **  
包含有关调用方的信息的对象。有关该字段结构的更多信息，请参阅[身份](#aws-appsync-resolver-context-reference-identity-js)。

** `source` **  
包含父字段解析的映射。

** `stash` **  
存储区是一个在每个解析器以及函数处理程序中提供的对象。相同的存储区对象在单次解析器运行时间内有效。这意味着，您可以使用存储区在请求和响应处理程序之间以及管道解析器中的函数之间传送任意数据。  
您无法删除或替换整个存储区，但可以添加、更新、删除和读取存储区属性。
您可以修改以下代码示例之一，以将项目添加到存储区中：  

```
//Example 1
ctx.stash.newItem = { key: "something" }

//Example 2
Object.assign(ctx.stash, {key1: value1, key2: value})
```
您可以修改以下代码，以从存储区中删除项目：  

```
delete ctx.stash.key
```

** `result` **  
此解析器结果的容器。该字段仅适用于响应处理程序。  
例如，如果要解析以下查询的 `author` 字段：  

```
query {
    getPost(id: 1234) {
        postId
        title
        content
        author {
            id
            name
        }
    }
}
```
然后，在评估响应处理程序时，可以使用完整的 `context` 变量：  

```
{
  "arguments" : {
    id: "1234"
  },
  "source": {},
  "result" : {
      "postId": "1234",
      "title": "Some title",
      "content": "Some content",
      "author": {
        "id": "5678",
        "name": "Author Name"
      }
  },
  "identity" : {
      "sourceIp" : ["x.x.x.x"],
      "userArn" : "arn:aws:iam::123456789012:user/appsync",
      "accountId" : "666666666666",
      "user" : "AIDAAAAAAAAAAAAAAAAAA"
  }
}
```

** `prev.result` **  
在管道解析器中执行的任何以前操作的结果。  
如果上一个操作是管道解析器的请求处理程序，则 `ctx.prev.result` 表示该评估结果，并提供给管道中的第一个函数。  
如果上一个操作是第一个函数，则 `ctx.prev.result` 表示第一个函数响应处理程序的评估结果，并提供给管道中的第二个函数。  
如果上一个操作是最后一个函数，则 `ctx.prev.result` 表示最后一个函数的评估结果，并提供给管道解析器的响应处理程序。

** `info` **  
包含有关 GraphQL 请求的信息的对象。有关该字段的结构，请参阅[信息](#aws-appsync-resolver-context-reference-info-js)。

### 身份
<a name="aws-appsync-resolver-context-reference-identity-js"></a>

`identity` 部分包含调用方的相关信息。此部分的形式取决于您的 AWS AppSync API 的授权类型。

有关 AWS AppSync 安全选项的更多信息，请参阅[授权和身份验证](security-authz.md#aws-appsync-security)。

** `API_KEY` 授权**  
不填充 `identity` 字段。

**`AWS_LAMBDA` 授权**  
`identity` 采用以下格式：  

```
type AppSyncIdentityLambda = {
  resolverContext: any;
};
```
`identity` 包含 `resolverContext` 密钥，其中包含为请求授权的 Lambda 函数返回的相同 `resolverContext` 内容。

** `AWS_IAM` 授权**  
`identity` 采用以下格式：  

```
type AppSyncIdentityIAM = {
  accountId: string;
  cognitoIdentityPoolId: string;
  cognitoIdentityId: string;
  sourceIp: string[];
  username: string;
  userArn: string;
  cognitoIdentityAuthType: string;
  cognitoIdentityAuthProvider: string;
};
```

** `AMAZON_COGNITO_USER_POOLS` 授权**  
`identity` 采用以下格式：  

```
type AppSyncIdentityCognito = {
  sourceIp: string[];
  username: string;
  groups: string[] | null;
  sub: string;
  issuer: string;
  claims: any;
  defaultAuthStrategy: string;
};
```

每个字段的定义如下所示：

** `accountId` **  
来电者的 AWS 账户 ID。

** `claims` **  
用户拥有的声明。

** `cognitoIdentityAuthType` **  
根据身份类型确定经过身份验证或未经身份验证。

** `cognitoIdentityAuthProvider` **  
外部身份提供程序信息的逗号分隔列表，用于获取对请求进行签名时使用的凭证。

** `cognitoIdentityId` **  
调用方的 Amazon Cognito 身份 ID。

** `cognitoIdentityPoolId` **  
与调用方关联的 Amazon Cognito 身份池 ID。

** `defaultAuthStrategy` **  
此调用方的默认授权策略（`ALLOW` 或 `DENY`）。

** `issuer` **  
令牌发布者。

** `sourceIp` **  
 AWS AppSync 接听的来电者的源 IP 地址。如果请求不包含 `x-forwarded-for` 标头，则源 IP 值仅包含来自 TCP 连接的单个 IP 地址。如果请求中包含 `x-forwarded-for` 标头，那么源 IP 将是来自 `x-forwarded-for` 标头的 IP 地址列表，以及来自 TCP 连接的 IP 地址。

** `sub` **  
经过验证的用户的 UUID。

** `user` **  
IAM 用户。

** `userArn` **  
IAM 用户的 Amazon 资源名称 (ARN)。

** `username` **  
已验证的用户的用户名。对于 `AMAZON_COGNITO_USER_POOLS` 授权，*用户名*的值是 *cognito:username* 属性的值。在`AWS_IAM`授权的情况下，用户名的值就是* AWS 用户*委托人的值。如果您将 IAM 授权与从 Amazon Cognito 身份池提供的凭证一起使用，我们建议您使用 `cognitoIdentityId`。

### 访问请求标头
<a name="aws-appsync-resolver-context-reference-util-js"></a>

AWS AppSync 支持从客户端传递自定义标头并使用在 GraphQL 解析器中访问它们。`ctx.request.headers`然后，您可以使用标头值执行操作，例如，将数据插入到数据来源或进行授权检查。您可以在命令行中使用 `$curl` 将一个或多个请求标头与 API 密钥一起使用，如以下示例中所示：

**单标头示例** 

假设您设置一个 `custom` 标头，值为 `nadia`，如下所示：

```
curl -XPOST -H "Content-Type:application/graphql" -H "custom:nadia" -H "x-api-key:<API-KEY-VALUE>" -d '{"query":"mutation { createEvent(name: \"demo\", when: \"Next Friday!\", where: \"Here!\") {id name when where description}}"}' https://<ENDPOINT>/graphql
```

然后可使用 `ctx.request.headers.custom` 访问它。例如，对于 DynamoDB，它可能位于以下代码中：

```
"custom": util.dynamodb.toDynamoDB(ctx.request.headers.custom)
```

**多标头示例** 

您也可以在单个请求中传递多个标头，并在解析器处理程序中访问这些标头。例如，如果为 `custom` 标头设置了两个值：

```
curl -XPOST -H "Content-Type:application/graphql" -H "custom:bailey" -H "custom:nadia" -H "x-api-key:<API-KEY-VALUE>" -d '{"query":"mutation { createEvent(name: \"demo\", when: \"Next Friday!\", where: \"Here!\") {id name when where description}}"}' https://<ENDPOINT>/graphql
```

它们可以作为一个数组访问，例如 `ctx.request.headers.custom[1]`。

**注意**  
AWS AppSync 不会在中公开 cookie 标头`ctx.request.headers`。

### 访问请求自定义域名
<a name="aws-access-requested-custom-domain-names-js"></a>

AWS AppSync 支持配置自定义域，您可以使用该域名访问您的 GraphQL 和实时终端节点。 APIs在使用自定义域名发出请求时，您可以使用 `ctx.request.domainName` 获取域名。

在使用默认 GraphQL 终端节点域名时，值为 `null`。

### 信息
<a name="aws-appsync-resolver-context-reference-info-js"></a>

`info` 部分包含有关 GraphQL 请求的信息。该部分采用以下格式：

```
type Info = {
  fieldName: string;
  parentTypeName: string;
  variables: any;
  selectionSetList: string[];
  selectionSetGraphQL: string;
};
```

每个字段的定义如下所示：

** `fieldName` **  
当前正在解析的字段的名称。

** `parentTypeName` **  
当前正在解析的字段的父类型的名称。

** `variables` **  
保留传递到 GraphQL 请求的所有变量的映射。

** `selectionSetList` **  
GraphQL 选择集中字段的列表表示形式。具有别名的字段仅按别名进行引用，而不按字段名称进行引用。以下示例对此详细进行了介绍。

** `selectionSetGraphQL` **  
选择集的字符串表示形式，格式为 GraphQL 架构定义语言 (SDL)。尽管片段不会合并到选择集中，但会保留内联片段，如以下示例中所示。

**注意**  
`JSON.stringify` 不会在字符串序列化中包含 `selectionSetGraphQL` 和 `selectionSetList`。您必须直接引用这些属性。

例如，如果您要解析以下查询的 `getPost` 字段：

```
query {
  getPost(id: $postId) {
    postId
    title
    secondTitle: title
    content
    author(id: $authorId) {
      authorId
      name
    }
    secondAuthor(id: "789") {
      authorId
    }
    ... on Post {
      inlineFrag: comments: {
        id
      }
    }
    ... postFrag
  }
}

fragment postFrag on Post {
  postFrag: comments: {
    id
  }
}
```

在处理处理程序时可使用的完整 `ctx.info` 变量可能是：

```
{
  "fieldName": "getPost",
  "parentTypeName": "Query",
  "variables": {
    "postId": "123",
    "authorId": "456"
  },
  "selectionSetList": [
    "postId",
    "title",
    "secondTitle"
    "content",
    "author",
    "author/authorId",
    "author/name",
    "secondAuthor",
    "secondAuthor/authorId",
    "inlineFragComments",
    "inlineFragComments/id",
    "postFragComments",
    "postFragComments/id"
  ],
  "selectionSetGraphQL": "{\n  getPost(id: $postId) {\n    postId\n    title\n    secondTitle: title\n    content\n    author(id: $authorId) {\n      authorId\n      name\n    }\n    secondAuthor(id: \"789\") {\n      authorId\n    }\n    ... on Post {\n      inlineFrag: comments {\n        id\n      }\n    }\n    ... postFrag\n  }\n}"
}
```

`selectionSetList` 仅公开属于当前类型的字段。如果当前类型是接口或联合，则仅公开属于该接口的选定字段。例如，给定以下架构：

```
type Query {
    node(id: ID!): Node
}

interface Node {
    id: ID
}

type Post implements Node {
    id: ID
    title: String
    author: String
}

type Blog implements Node {
    id: ID
    title: String
    category: String
}
```

以及以下查询：

```
query {
    node(id: "post1") {
        id
        ... on Post {
            title
        }

        ... on Blog {
            title
        }
    }
}
```

如果在进行 `Query.node` 字段解析时调用 `ctx.info.selectionSetList`，则仅公开 `id`：

```
"selectionSetList": [
    "id"
]
```