

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# AWS AppSync 解析程式映射範本內容參考
<a name="resolver-context-reference"></a>

**注意**  
我們現在主要支援 APPSYNC\$1JS 執行期及其文件。請考慮[在此處](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-js-version.html)使用 APPSYNC\$1JS 執行期及其指南。

AWS AppSync 定義一組變數和函數，以使用解析程式映射範本。這樣可讓使用 GraphQL 對資料進行邏輯運算更簡單。本文件說明這些函式，並提供範本使用範例。

## 正在存取 `$context`
<a name="accessing-the-context"></a>

`$context` 變數是一種映射，保存您的解析程式叫用的所有情境資訊。其結構如下：

```
{
   "arguments" : { ... },
   "source" : { ... },
   "result" : { ... },
   "identity" : { ... },
   "request" : { ... },
   "info": { ... }
}
```

**注意**  
如果您嘗試透過索引鍵存取字典/地圖項目 （例如 中的項目`context`) 來擷取值，則 Velocity 範本語言 (VTL) 可讓您直接使用符號 `<dictionary-element>.<key-name>`。不過，這可能不是所有案例皆適用，例如當索引鍵名稱有特殊字元 (例如，底線「\$1」)。建議您一律使用 `<dictionary-element>.get("<key-name>")` 表示法。

`$context` 映射中每個欄位的定義如下：

### `$context` 欄位
<a name="accessing-the-context-list"></a>

** `arguments` **  
包含此欄位所有 GraphQL 引數的映射。

** `identity` **  
包含有關發起人資訊的物件。如需此欄位結構的詳細資訊，請參閱[身分](#aws-appsync-resolver-context-reference-identity)。

** `source` **  
包含父欄位解析度的映射。

** `stash` **  
此 stash 是每個解析程式和函數映射範本中都會提供的「映射」。在單一個解析程式執行期間，則會存在相同的 stash 執行個體。這表示您可以使用 stash 在管道解析程式中的所有要求和回應映射範本、以及全部函數中，傳遞任意資料。此 stash 會公開與 [Java 映射](https://docs.oracle.com/javase/8/docs/api/java/util/Map.html)資料結構相同的方法。

** `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)。

### Identity
<a name="aws-appsync-resolver-context-reference-identity"></a>

包含有關發起人資訊的 `identity` 區段。本節的形狀取決於 AWS AppSync API 的授權類型。

如需 AWS AppSync 安全選項的詳細資訊，請參閱[授權和身分驗證](security-authz.md#aws-appsync-security)。

** `API_KEY` 授權**  
`identity` 欄位未填入。

**`AWS_LAMBDA` 授權**  
`identity` 包含 `resolverContext`金鑰，其中包含由授權請求的 Lambda 函數傳回的相同`resolverContext`內容。

** `AWS_IAM` 授權**  
`identity` 的格式如下：  

```
{
    "accountId" : "string",
    "cognitoIdentityPoolId" : "string",
    "cognitoIdentityId" : "string",
    "sourceIp" : ["string"],
    "username" : "string", // IAM user principal
    "userArn" : "string",
    "cognitoIdentityAuthType" : "string", // authenticated/unauthenticated based on the identity type
    "cognitoIdentityAuthProvider" : "string" // the auth provider that was used to obtain the credentials
}
```

** `AMAZON_COGNITO_USER_POOLS` 授權**  
`identity` 的格式如下：  

```
{
    "sub" : "uuid",
    "issuer" : "string",
    "username" : "string"
    "claims" : { ... },
    "sourceIp" : ["x.x.x.x"],
    "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 除了有 TCP 連線的 IP 地址外，也將有 `x-forwarded-for` 標頭中 IP 地址的清單。

** `sub` **  
已驗證使用者的 UUID。

** `user` **  
IAM 使用者。

** `userArn` **  
IAM 使用者的 Amazon Resource Name (ARN)。

** `username` **  
已驗證使用者的使用者名稱。如果是 `AMAZON_COGNITO_USER_POOLS` 授權，*使用者名稱*的值是屬性 *cognito:username* 的值。在`AWS_IAM`授權的情況下，*使用者名稱*的值是 AWS 使用者主體的值。如果您使用 IAM 授權搭配來自 Amazon Cognito 身分集區的憑證，我們建議您使用 `cognitoIdentityId`。

### 存取請求標頭
<a name="aws-appsync-resolver-context-reference-util"></a>

AWS AppSync 支援從用戶端傳遞自訂標頭，並使用 在 GraphQL 解析程式中存取它們`$context.request.headers`。然後，您可以將 標頭值用於動作，例如將資料插入資料來源或授權檢查。您可以將 與來自命令列的 API 金鑰`$curl`搭配使用的單一或多個請求標頭，如下列範例所示：

**單一標頭範例** 

假設您設定使用 `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
```

可使用 `$context.request.headers.custom` 對此進行存取。例如，它可能位於 DynamoDB 的下列 VTL 中：

```
"custom": $util.dynamodb.toDynamoDBJson($context.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
```

然後，您可以將這些存取為陣列，例如 `$context.request.headers.custom[1]`。

**注意**  
AWS AppSync 不會在 中公開 Cookie 標頭`$context.request.headers`。

### 存取請求自訂網域名稱
<a name="aws-access-requested-custom-domain-names"></a>

AWS AppSync 支援設定自訂網域，您可以用來存取 APIs的 GraphQL 和即時端點。使用自訂網域名稱提出請求時，您可以使用 取得網域名稱`$context.request.domainName`。

使用預設 GraphQL 端點網域名稱時，值為 `null`。

### 資訊
<a name="aws-appsync-resolver-context-reference-info"></a>

`info` 區段包含有關 GraphQL 請求的資訊。本節的格式如下：

```
{
    "fieldName": "string",
    "parentTypeName": "string",
    "variables": { ... },
    "selectionSetList": ["string"],
    "selectionSetGraphQL": "string"
}
```

每個欄位的定義如下：

** `fieldName` **  
目前正在解析的欄位名稱。

** `parentTypeName` **  
目前正在解析的欄位父類型名稱。

** `variables` **  
包含傳遞給 GraphQL 請求之所有變數的映射。

** `selectionSetList` **  
此清單表示 GraphQL 選取範圍中的欄位。別名的欄位僅由別名名稱參考，而非欄位名稱。以下範例詳細說明這一點。

** `selectionSetGraphQL` **  
此字串表示格式為 GraphQL 結構描述定義語言 (SDL) 的選取範圍。雖然片段不會合併到選取集，但會保留內嵌片段，如下列範例所示。

**注意**  
在 `$utils.toJson()`上使用 時`context.info`，預設不會序列化 `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
  }
}
```

那麼，在處理映射範本時，可用的完整 `$context.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
        }
    }
}
```

`$ctx.info.selectionSetList` 以`Query.node`欄位解析度呼叫 時，只會`id`公開：

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

## 處理輸入
<a name="sanitizing-inputs"></a>

應用程式必須處理不受信任的輸入，以防止任何外部方使用其預期用途之外的應用程式。由於 包含 `$context.arguments`、、`$context.info.variables`、 `$context.identity` `$context.result`和 等屬性中的`$context`使用者輸入`$context.request.headers`，因此必須小心在映射範本中淨化其值。

由於對應範本代表 JSON，輸入處理採用從表示使用者輸入的字串逸出 JSON 保留字元的形式。將敏感字串值放入對應範本時，最佳做法是使用 `$util.toJson()` 公用程式將 JSON 保留字元從敏感字串值逸出。

例如，在下列 Lambda 請求映射範本中，因為我們存取了不安全的客戶輸入字串 (`$context.arguments.id`)，因此我們使用 包裝它`$util.toJson()`，以防止未逸出的 JSON 字元破壞 JSON 範本。

```
{
    "version": "2017-02-28",
    "operation": "Invoke",
    "payload": {
        "field": "getPost",
        "postId": $util.toJson($context.arguments.id)
    }
}
```

與下面的映射範本相反，我們在其中直接插入`$context.arguments.id`而不進行淨化。這不適用於包含未逸出引號或其他 JSON 預留字元的字串，並且可能會讓您的範本處於開啟失敗狀態。

```
## DO NOT DO THIS
{
    "version": "2017-02-28",
    "operation": "Invoke",
    "payload": {
        "field": "getPost",
        "postId": "$context.arguments.id" ## Unsafe! Do not insert $context string values without escaping JSON characters.
    }
}
```