

# 教程：通过两种 AWS 服务集成和一种 Lambda 非代理集成创建计算器 REST API
<a name="integrating-api-with-aws-services-lambda"></a>

[教程：利用 Lambda 非代理集成创建 REST API](getting-started-lambda-non-proxy-integration.md) 完全使用 `Lambda Function` 集成。`Lambda Function` 集成是 `AWS Service` 集成类型的特殊情况，该类型可为您执行大量集成设置，如自动添加所需的基于资源的权限以调用 Lambda 函数。在这里，三个集成中的两个集成使用的是 `AWS Service` 集成。在此集成类型中，您将具有更多控制，但您将需要手动执行任务，如创建和指定包含相应权限的 IAM 角色。



在本教程中，您将创建一个 `Calc` Lambda 函数，该函数可实施基本算术运算，同时接受 JSON 格式的输入和输出。然后，您将采用以下方式创建一个 REST API 并将其与 Lambda 函数集成：

1. 通过在 `GET` 资源上公开 `/calc` 方法以调用 Lambda 函数，同时提供输入作为查询字符串参数。（`AWS Service` 集成）

1. 通过在 `POST` 资源上公开 `/calc` 方法以调用 Lambda 函数，同时在方法请求负载中提供输入。（`AWS Service` 集成）

1. 通过在嵌套的 `GET` 资源上公开 `/calc/{operand1}/{operand2}/{operator}` 以调用 Lambda 函数，同时提供输入作为路径参数。（`Lambda Function` 集成）

除了尝试使用本教程外，您可能还希望研究 `Calc` API 的 [OpenAPI 定义文件](api-as-lambda-proxy-export-swagger-with-extensions.md)，您可通过按照 [在 API Gateway 中使用 OpenAPI 开发 REST API](api-gateway-import-api.md) 中的说明操作来将其导入 API Gateway 中。

**Topics**
+ [创建一个可代入的 IAM 角色](#api-as-lambda-proxy-setup-iam-role-policies)
+ [创建 `Calc` Lambda 函数](#api-as-lambda-proxy-create-lambda-function)
+ [测试 `Calc` Lambda 函数](#api-as-lambda-proxy-test-lambda-function-)
+ [创建 `Calc` API](#api-as-lambda-proxy-create-api-resources)
+ [集成 1：创建使用查询参数的 `GET` 方法以调用 Lambda 函数](#api-as-lambda-proxy-expose-get-method-with-query-strings-to-call-lambda-function)
+ [集成 2：创建使用 JSON 负载的 `POST` 方法以调用 Lambda 函数](#api-as-lambda-proxy-expose-post-method-with-json-body-to-call-lambda-function)
+ [集成 3：创建使用路径参数的 `GET` 方法以调用 Lambda 函数](#api-as-lambda-proxy-expose-get-method-with-path-parameters-to-call-lambda-function)
+ [与 Lambda 函数集成的示例 API 的 OpenAPI 定义](api-as-lambda-proxy-export-swagger-with-extensions.md)

## 创建一个可代入的 IAM 角色
<a name="api-as-lambda-proxy-setup-iam-role-policies"></a>

为了确保您的 API 调用您的 `Calc` Lambda 函数，您将需要具有一个 API Gateway 可代入的 IAM 角色，这是一个具有以下信任关联的 IAM 角色：

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

------

您创建的角色将需要具有 Lambda [InvokeFunction](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html) 权限。否则，API 调用方将收到 `500 Internal Server Error` 响应。要向该角色提供此权限，请将以下 IAM 策略附加到它：

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "lambda:InvokeFunction",
            "Resource": "*"
        }
    ]
}
```

------

以下是完成所有操作的方式：

**创建 API Gateway 可代入的 IAM 角色**

1. 登录 IAM 控制台。

1. 选择**角色**。

1. 选择**创建角色**。

1. 在**选择受信任实体的类型**下，选择 **AWS 服务**。

1. 在**选择将使用此角色的服务**下，选择 **Lambda**。

1. 选择**下一步: 权限**。

1. 选择**创建策略**。

   新的**创建策略**控制台窗口将会打开。在该窗口中，执行以下操作：

   1. 在 **JSON** 选项卡中，将现有策略替换为以下策略：

------
#### [ JSON ]

****  

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "lambda:InvokeFunction",
                  "Resource": "*"
              }
          ]
      }
      ```

------

   1. 选择**查看策略**。

   1. 在**查看策略**下，执行以下操作：

      1. 在**名称**中，键入一个名称，如 **lambda\$1execute**。

      1. 选择**创建策略**。

1. 在原来的**创建角色**控制台窗口中，执行以下操作：

   1. 从下拉列表的**添加权限策略**下，选择您的 **lambda\$1execute** 策略。

      如果您未在策略列表中看到您的策略，请选择列表顶部的刷新按钮。（请勿刷新浏览器页面！）

   1. 选择**下一步: 标签**。

   1. 选择**下一步: 审核**。

   1. 对于**角色名称**，键入一个名称，如 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role**。

   1. 选择**创建角色**。

1. 从角色列表中，选择您的 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role**。

1. 选择**信任关系**选项卡。

1. 选择**编辑信任关系**。

1. 使用以下策略替换现有策略：

------
#### [ JSON ]

****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Sid": "",
         "Effect": "Allow",
         "Principal": {
           "Service": [
             "lambda.amazonaws.com",
             "apigateway.amazonaws.com"
           ]
         },
         "Action": "sts:AssumeRole"
       }
     ]
   }
   ```

------

1. 选择**更新信任策略**。

1. 请记下您刚刚创建的角色的角色 ARN。您以后将需要它。

## 创建 `Calc` Lambda 函数
<a name="api-as-lambda-proxy-create-lambda-function"></a>

接下来，您将使用 Lambda 控制台创建 Lambda 函数。

1. 在 Lambda 控制台中，选择**创建函数**。

1. 选择**从头开始创作**。

1. 在**名称**中，输入 **Calc**。

1. 在**运行时**中，选择受支持的最新 **Node.js** 或 **Python** 运行时。

1. 对于所有其它选项，请使用默认设置。

1. 选择**创建函数**。

1.  在首选运行时中复制以下 Lambda 函数，并将其粘贴到 Lambda 控制台的代码编辑器中。

------
#### [ Node.js ]

   ```
   export const handler = async function (event, context) {
     console.log("Received event:", JSON.stringify(event));
   
     if (
       event.a === undefined ||
       event.b === undefined ||
       event.op === undefined
     ) {
       return "400 Invalid Input";
     }
   
     const res = {};
     res.a = Number(event.a);
     res.b = Number(event.b);
     res.op = event.op;
     if (isNaN(event.a) || isNaN(event.b)) {
       return "400 Invalid Operand";
     }
     switch (event.op) {
       case "+":
       case "add":
         res.c = res.a + res.b;
         break;
       case "-":
       case "sub":
         res.c = res.a - res.b;
         break;
       case "*":
       case "mul":
         res.c = res.a * res.b;
         break;
       case "/":
       case "div":
         if (res.b == 0) {
           return "400 Divide by Zero";
         } else {
           res.c = res.a / res.b;
         }
         break;
       default:
         return "400 Invalid Operator";
     }
   
     return res;
   };
   ```

------
#### [ Python ]

   ```
   import json
   
   
   def lambda_handler(event, context):
       print(event)
   
       try:
           (event['a']) and (event['b']) and (event['op'])
       except KeyError:
           return '400 Invalid Input'
   
       try:
           res = {
               "a": float(
                   event['a']), "b": float(
                   event['b']), "op": event['op']}
       except ValueError:
           return '400 Invalid Operand'
   
       if event['op'] == '+':
           res['c'] = res['a'] + res['b']
       elif event['op'] == '-':
           res['c'] = res['a'] - res['b']
       elif event['op'] == '*':
           res['c'] = res['a'] * res['b']
       elif event['op'] == '/':
           if res['b'] == 0:
               return '400 Divide by Zero'
           else:
               res['c'] = res['a'] / res['b']
       else:
           return '400 Invalid Operator'
   
       return res
   ```

------

1. 在“执行角色”下，选择**选择现有角色**。

1. 输入您之前创建的 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role** 角色的角色 ARN。

1. 选择**部署**。

 此函数需要来自 `a` 输入参数的两个操作数 (`b` 和 `op`) 以及一个运算符 (`event`)。该输入是格式如下的 JSON 对象：

```
{
  "a": "Number" | "String",
  "b": "Number" | "String",
  "op": "String"
}
```

此函数会返回计算所得的结果 (`c`) 和输入。对于无效的输入，该函数将返回空值或“Invalid op”字符串作为结果。输出具有以下 JSON 格式：

```
{
  "a": "Number",
  "b": "Number",
  "op": "String",
  "c": "Number" | "String"
}
```

您应该先在 Lambda 控制台中测试该函数，然后再在下一步中将其与 API 集成。

## 测试 `Calc` Lambda 函数
<a name="api-as-lambda-proxy-test-lambda-function-"></a>

以下内容介绍如何在 Lambda 控制台中测试您的 `Calc` 函数：

1. 选择**测试**选项卡。

1. 对于测试事件名称，请输入 **calc2plus5**。

1. 将测试事件定义替换为以下内容：

   ```
   {
     "a": "2",
     "b": "5",
     "op": "+"
   }
   ```

1. 选择**保存**。

1. 选择**测试**。

1. 展开**执行结果: 成功**。您将看到以下内容：

   ```
   {
     "a": 2,
     "b": 5,
     "op": "+",
     "c": 7
   }
   ```

## 创建 `Calc` API
<a name="api-as-lambda-proxy-create-api-resources"></a>

以下过程介绍如何为您刚刚创建的 `Calc` Lambda 函数创建 API。在后续部分中，您将资源和方法添加到该 API。

**创建 API**

1. 通过以下网址登录到 Amazon API Gateway 控制台：[https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)。

1. 如果您是第一次使用 API Gateway，您会看到一个介绍服务特征的页面。在 **REST API** 下，选择**生成**。当**创建示例 API** 弹出框出现时，选择**确定**。

   如果这不是您首次使用 API Gateway，请选择**创建 API**。在 **REST API** 下，选择**生成**。

1.  对于 **API 名称**，请输入 **LambdaCalc**。

1. （可选）对于**描述**，输入描述。

1. 将 **API 端点类型**设置保留为**区域**。

1. 为 **IP 地址类型**选择 **IPv4**。

1. 选择 **Create API (创建 API)**。

## 集成 1：创建使用查询参数的 `GET` 方法以调用 Lambda 函数
<a name="api-as-lambda-proxy-expose-get-method-with-query-strings-to-call-lambda-function"></a>

通过创建将查询字符串参数传递给 Lambda 函数的 `GET` 方法，启用要从浏览器中进行调用的 API。这种方法可能非常有用，特别是对于允许开放访问的 API。

创建 API 后，您将创建一个资源。通常情况下，根据应用程序逻辑将 API 资源组织成资源树形式。在此步骤中，您将创建一个 **/calc** 资源。

**创建 **/calc** 资源**

1. 选择**创建资源**。

1. 将**代理资源**保持为关闭状态。

1. 将**资源路径**保持为 `/`。

1. 对于**资源名称**，输入 **calc**。

1. 将 **CORS（跨源资源共享）**保持为关闭状态。

1. 选择**创建资源**。

通过创建将查询字符串参数传递给 Lambda 函数的 `GET` 方法，启用要从浏览器中进行调用的 API。这种方法可能非常有用，特别是对于允许开放访问的 API。

在此方法中，Lambda 要求使用 `POST` 请求调用任何 Lambda 函数。此示例表明，前端方法请求中的 HTTP 方法可以与后端中的集成请求不同。

**创建 `GET` 方法**

1. 选择 **/calc** 资源，然后选择**创建方法**。

1. 对于**方法类型**，选择 **GET**。

1. 对于**集成类型**，选择 **AWS 服务**。

1. 对于 **AWS 区域**，选择您创建 Lambda 函数的 AWS 区域。

1. 对于 **AWS 服务**，选择 **Lambda**。

1. 将 **AWS 子域**保留为空白。

1. 对于 **HTTP 方法**，选择 **POST**。

1. 对于**操作类型**，选择**使用路径覆盖**。借助此选项，我们可以指定用来执行 `Calc` 函数的[调用](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html)操作的 ARN。

1. 对于**路径覆盖**，输入 **2015-03-31/functions/arn:aws:lambda:*us-east-2*:*account-id*:function:Calc/invocations**。对于 ** *account-id***，输入您的 AWS 账户 ID。对于 ***us-east-2***，输入您创建 Lambda 函数的 AWS 区域。

1. 对于**执行角色**，输入 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role** 的角色 ARN。

1. 请勿更改**凭证缓存**和**默认超时**的设置。

1. 选择**方法请求设置**。

1. 对于**请求验证程序**，选择**验证查询字符串参数和标头**。

   如果客户端没有指定必需的参数，此设置将导致返回错误消息。

1. 选择 **URL 查询字符串参数**。

   现在，为 **/calc** 资源上的 **GET** 方法设置查询字符串参数，来代表后端 Lambda 函数接收输入。

   要创建查询字符串参数，请执行以下操作：

   1. 选择**添加查询字符串**。

   1. 在**名称**中，输入 **operand1**。

   1. 打开**必需**。

   1. 将**缓存**保持为关闭状态。

   重复相同的步骤，创建一个名为 **operand2** 的查询字符串和一个名为 **operator** 的查询字符串。

1. 选择**创建方法**。

现在，创建映射模板，以将客户端提供的查询字符串转换为 `Calc` 函数需要的集成请求负载。此模板会将**方法请求**中声明的三个查询字符串参数映射为 JSON 对象的指定属性值，作为后端 Lambda 函数的输入。转换后的 JSON 对象将作为集成请求负载包含在内。

**将输入参数映射到集成请求**

1. 在**集成请求**选项卡的**集成请求设置**下，选择**编辑**。

1. 对于**请求正文传递**，选择**当未定义模板时（推荐）**。

1. 选择**映射模板**。

1. 选择**添加映射模板**。

1. 对于**内容类型**，输入 **application/json**。

1. 对于**模板正文**，输入以下代码：

   ```
   {
       "a":  "$input.params('operand1')",
       "b":  "$input.params('operand2')", 
       "op": "$input.params('operator')"   
   }
   ```

1. 选择**保存**。

现在，您可以测试 `GET` 方法来验证它是否已经过正确设置，可以调用 Lambda 函数。

**测试 `GET` 方法**

1. 选择**测试**选项卡。您可能需要选择右箭头按钮，以显示该选项卡。

1. 对于**查询字符串**，输入 **operand1=2&operand2=3&operator=\$1**。

1. 选择**测试**。

   结果应与如下显示类似：  
![\[在 API Gateway 中创建 API 作为 Lambda 代理\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/aws_proxy_lambda_calc_get_method_test_new_console.png)

## 集成 2：创建使用 JSON 负载的 `POST` 方法以调用 Lambda 函数
<a name="api-as-lambda-proxy-expose-post-method-with-json-body-to-call-lambda-function"></a>

通过创建使用 JSON 负载的 `POST` 方法以调用 Lambda 函数完成此操作，以便客户端必须将必要的输入提供给请求正文中的后端函数。为确保客户端上传正确的输入数据，您将对负载启用请求验证。

**创建使用 JSON 负载的 `POST` 方法**

1. 选择 **/calc** 资源，然后选择**创建方法**。

1. 对于**方法类型**，选择 **POST**。

1. 对于**集成类型**，选择 **AWS 服务**。

1. 对于 **AWS 区域**，选择您创建 Lambda 函数的 AWS 区域。

1. 对于 **AWS 服务**，选择 **Lambda**。

1. 将 **AWS 子域**保留为空白。

1. 对于 **HTTP 方法**，选择 **POST**。

1. 对于**操作类型**，选择**使用路径覆盖**。借助此选项，我们可以指定用来执行 `Calc` 函数的[调用](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html)操作的 ARN。

1. 对于**路径覆盖**，输入 **2015-03-31/functions/arn:aws:lambda:*us-east-2*:*account-id*:function:Calc/invocations**。对于 ** *account-id***，输入您的 AWS 账户 ID。对于 ***us-east-2***，输入您创建 Lambda 函数的 AWS 区域。

1. 对于**执行角色**，输入 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role** 的角色 ARN。

1. 请勿更改**凭证缓存**和**默认超时**的设置。

1. 选择**创建方法**。

现在，创建**输入**模型以描述输入数据结构和验证传入请求正文。

**创建输入模型**

1. 在主导航窗格中，选择**模型**。

1. 选择**创建模型**。

1. 对于**名称**，请输入 **input**。

1. 对于**内容类型**，输入 **application/json**。

   如果未找到匹配的内容类型，则不执行请求验证。要使用同一模型而不考虑内容类型，请输入 **\$1default**。

1. 对于**模型架构**，输入以下模型：

   ```
   {
       "type":"object",
       "properties":{
           "a":{"type":"number"},
           "b":{"type":"number"},
           "op":{"type":"string"}
       },
       "title":"input"
   }
   ```

1. 选择**创建模型**。

现在，创建**输出**模型。此模型描述了后端计算得出的输出的数据结构。它可用于将集成响应数据映射到不同的模型。本教程依靠传递行为，并不会使用此模型。

**创建输出模型**

1. 选择**创建模型**。

1. 对于**名称**，请输入 **output**。

1. 对于**内容类型**，输入 **application/json**。

   如果未找到匹配的内容类型，则不执行请求验证。要使用同一模型而不考虑内容类型，请输入 **\$1default**。

1. 对于**模型架构**，输入以下模型：

   ```
   {
       "type":"object",
       "properties":{
           "c":{"type":"number"}
       },
       "title":"output"
   }
   ```

1. 选择**创建模型**。

现在，创建**结果**模型。此模型描述了返回响应数据的数据结构。它同时引用您的 API 中定义的**输入**和**输出**架构。

**创建结果模型**

1. 选择**创建模型**。

1. 对于**名称**，请输入 **result**。

1. 对于**内容类型**，输入 **application/json**。

   如果未找到匹配的内容类型，则不执行请求验证。要使用同一模型而不考虑内容类型，请输入 **\$1default**。

1. 对于**模型架构**，使用您的 *restapi-id* 输入以下模型。您的 *restapi-id* 用括号列在控制台顶部，可通过以下流程找到：`API Gateway > APIs > LambdaCalc (abc123).`

   ```
   {
       "type":"object",
       "properties":{
           "input":{
               "$ref":"https://apigateway.amazonaws.com/restapis/restapi-id/models/input"
           },
           "output":{
               "$ref":"https://apigateway.amazonaws.com/restapis/restapi-id/models/output"
           }
       },
       "title":"result"
   }
   ```

1. 选择**创建模型**。

现在，配置 POST 方法的方法请求，以便在传入的请求正文上启用请求验证。

**在 POST 方法上启用请求验证**

1. 在主导航窗格中，选择**资源**，然后从资源树中选择 `POST` 方法。

1. 在**方法请求**选项卡上的**方法请求设置**下，选择**编辑**。

1. 对于**请求验证程序**，选择**验证正文**。

1. 选择**请求正文**，然后选择**添加模型**。

1. 对于**内容类型**，输入 **application/json**。

   如果未找到匹配的内容类型，则不执行请求验证。要使用同一模型而不考虑内容类型，请输入 **\$1default**。

1. 对于**模型**，选择**输入**。

1. 选择**保存**。

现在，您可以测试 `POST` 方法来验证它是否已经过正确设置，可以调用 Lambda 函数。

**测试 `POST` 方法**

1. 选择**测试**选项卡。您可能需要选择右箭头按钮，以显示该选项卡。

1. 对于**请求正文**，输入以下 JSON 负载。

   ```
   {
       "a": 1,
       "b": 2,
       "op": "+"
   }
   ```

1. 选择**测试**。

   您应看到以下输出：

   ```
   {
     "a": 1,
     "b": 2,
     "op": "+",
     "c": 3
   }
   ```

## 集成 3：创建使用路径参数的 `GET` 方法以调用 Lambda 函数
<a name="api-as-lambda-proxy-expose-get-method-with-path-parameters-to-call-lambda-function"></a>

现在，您将在由一系列路径参数指定的资源上创建一个 `GET` 方法，以调用后端 Lambda 函数。路径参数值指定 Lambda 函数的输入数据。您将使用映射模板，将传入路径参数值映射到必需的集成请求负载。

生成的 API 资源结构将如下所示：

![\[在 API Gateway 中创建 API 作为 Lambda 代理\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/aws_proxy_lambda_create_api_resources_new_console.png)


**创建 **/\$1operand1\$1/\$1operand2\$1/\$1operator\$1** 资源**

1. 选择**创建资源**。

1. 对于**资源路径**，选择 `/calc`。

1. 对于**资源名称**，输入 **\$1operand1\$1**。

1. 将 **CORS（跨源资源共享）**保持为关闭状态。

1. 选择**创建资源**。

1. 对于**资源路径**，选择 `/calc/{operand1}/`。

1. 对于**资源名称**，输入 **\$1operand2\$1**。

1. 将 **CORS（跨源资源共享）**保持为关闭状态。

1. 选择**创建资源**。

1. 对于**资源路径**，选择 `/calc/{operand1}/{operand2}/`。

1. 对于**资源名称**，输入 **\$1operator\$1**。

1. 将 **CORS（跨源资源共享）**保持为关闭状态。

1. 选择**创建资源**。

这次，您将在 API Gateway 控制台中使用内置的 Lambda 集成来设置方法集成。

**设置方法集成**

1. 选择 **/\$1operand1\$1/\$1operand2\$1/\$1operator\$1** 资源，然后选择**创建方法**。

1. 对于**方法类型**，选择 **GET**。

1. 对于**集成类型**，选择 **Lambda**。

1. 保持 **Lambda 代理集成**处于关闭状态。

1. 对于 **Lambda 函数**，选择您创建 Lambda 函数的 AWS 区域，并输入 **Calc**。

1. 将**默认超时**保持为开启状态。

1. 选择**创建方法**。

现在，创建映射模板，以将创建 **/calc/\$1operand1\$1/\$1operand2\$1/\$1operator\$1** 资源时声明的三个 URL 路径参数映射到 JSON 对象中的指定属性值。由于 URL 路径必须经过 URL 编码，必须将除法运算符指定为 `%2F`，而不是 `/`。此模板先将 `%2F` 转换为 `'/'`，然后再将其发送到 Lambda 函数。

**创建映射模板**

1. 在**集成请求**选项卡的**集成请求设置**下，选择**编辑**。

1. 对于**请求正文传递**，选择**当未定义模板时（推荐）**。

1. 选择**映射模板**。

1. 对于**内容类型**，输入 **application/json**。

1. 对于**模板正文**，输入以下代码：

   ```
   {
      "a": "$input.params('operand1')",
      "b": "$input.params('operand2')",
      "op": #if($input.params('operator')=='%2F')"/"#{else}"$input.params('operator')"#end
   }
   ```

1. 选择**保存**。

现在，您可以测试 `GET` 方法来验证它是否已经过正确设置，无需映射即可通过集成响应调用 Lambda 函数并传递原始输出。

**测试 `GET` 方法**

1. 选择**测试**选项卡。您可能需要选择右箭头按钮，以显示该选项卡。

1. 对于**路径**，请执行以下操作：

   1. 对于 **operand1**，输入 **1**。

   1. 对于 **operand2**，输入 **1**。

   1. 对于 **operator**，输入 **\$1**。

1. 选择 **Test (测试)**。

1. 结果应该如下所示：  
![\[在 API Gateway 控制台中测试 GET 方法。\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/aws_proxy_lambda_calc_get_method_test_path_parm_new_console.png)

接下来，根据 `result` 架构对方法响应负载的数据结构进行建模。

默认情况下，系统会为方法响应正文分配一个空白模型。这将在不映射的情况下传递集成响应正文。但是，当您为一种强类型语言（例如 Java 或 Objective-C）生成一个开发工具包时，您的开发工具包用户会收到一个空白对象作为结果。为确保 REST 客户端和开发工具包客户端能收到期望的结果，您必须使用预定义的架构为响应数据建模。在这里，您将为方法响应正文定义一个模型，并构建一个映射模板，以便将集成响应正文转换为方法响应正文。

**创建方法响应**

1. 在**方法响应**选项卡的**响应 200** 下，选择**编辑**。

1. 在**响应正文**下，选择**添加模型**。

1. 对于**内容类型**，输入 **application/json**。

1. 对于**模型**，选择**结果**。

1. 选择**保存**。

为方法响应正文设置模型可以确保将响应数据转换为给定开发工具包的 `result` 对象。要确保对集成响应数据进行相应的映射，您将需要一个映射模板。

**创建映射模板**

1. 在**集成响应**选项卡上的**默认 - 响应**下，选择**编辑**。

1. 选择**映射模板**。

1. 对于**内容类型**，输入 **application/json**。

1. 对于**模板正文**，输入以下代码：

   ```
   #set($inputRoot = $input.path('$'))
   {
     "input" : {
       "a" : $inputRoot.a,
       "b" : $inputRoot.b,
       "op" : "$inputRoot.op"
     },
     "output" : {
       "c" : $inputRoot.c
     }
   }
   ```

1. 选择**保存**。

**测试映射模板**

1. 选择**测试**选项卡。您可能需要选择右箭头按钮，以显示该选项卡。

1. 对于**路径**，请执行以下操作：

   1. 对于 **operand1**，输入 **1**。

   1. 对于 **operand2**，输入 **2**。

   1. 对于 **operator**，输入 **\$1**。

1. 选择**测试**。

1. 结果将类似于以下内容：

   ```
   {
     "input": {
       "a": 1,
       "b": 2,
       "op": "+"
     },
     "output": {
       "c": 3
     }
   }
   ```

目前，您只能在 API Gateway 控制台中通过**测试**功能调用 API。要使 API 可用于客户端，您将需要部署 API。每当您添加、修改或删除资源和方法、更新数据映射或者更新阶段设置时，请始终确保重新部署 API。否则，新功能或更新将不可用于您 API 的客户端。如以下所示：

**部署 API**

1. 选择**部署 API**。

1. 对于**阶段**，选择**新建阶段**。

1. 对于**阶段名称**，输入 **Prod**。

1. （可选）对于**描述**，输入描述。

1. 选择**部署**。

1.  （可选）在**阶段详细信息**下，对于**调用 URL**，您可以选择复制图标以复制您 API 的调用 URL。您可以将此值与 [Postman](https://www.postman.com) 和 [cURL](https://curl.se/) 等工具结合使用来测试您的 API。

**注意**  
每当您添加、修改或删除资源或方法、更新数据映射或者更新阶段设置时，请务必重新部署 API。否则，新特征或更新将不可用于您的 API 的客户端。

# 与 Lambda 函数集成的示例 API 的 OpenAPI 定义
<a name="api-as-lambda-proxy-export-swagger-with-extensions"></a>

------
#### [ OpenAPI 2.0 ]

```
{
  "swagger": "2.0",
  "info": {
    "version": "2017-04-20T04:08:08Z",
    "title": "LambdaCalc"
  },
  "host": "uojnr9hd57.execute-api.us-east-1.amazonaws.com",
  "basePath": "/test",
  "schemes": [
    "https"
  ],
  "paths": {
    "/calc": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "operand2",
            "in": "query",
            "required": true,
            "type": "string"
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "type": "string"
          },
          {
            "name": "operand1",
            "in": "query",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            },
            "headers": {
              "operand_1": {
                "type": "string"
              },
              "operand_2": {
                "type": "string"
              },
              "operator": {
                "type": "string"
              }
            }
          }
        },
        "x-amazon-apigateway-request-validator": "Validate query string parameters and headers",
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.operator": "integration.response.body.op",
                "method.response.header.operand_2": "integration.response.body.b",
                "method.response.header.operand_1": "integration.response.body.a"
              },
              "responseTemplates": {
                "application/json": "#set($res = $input.path('$'))\n{\n    \"result\": \"$res.a, $res.b, $res.op => $res.c\",\n  \"a\" : \"$res.a\",\n  \"b\" : \"$res.b\",\n  \"op\" : \"$res.op\",\n  \"c\" : \"$res.c\"\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST",
          "requestTemplates": {
            "application/json": "{\n    \"a\":  \"$input.params('operand1')\",\n    \"b\":  \"$input.params('operand2')\", \n    \"op\": \"$input.params('operator')\"   \n}"
          },
          "type": "aws"
        }
      },
      "post": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "in": "body",
            "name": "Input",
            "required": true,
            "schema": {
              "$ref": "#/definitions/Input"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            }
          }
        },
        "x-amazon-apigateway-request-validator": "Validate body",
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "default": {
              "statusCode": "200",
              "responseTemplates": {
                "application/json": "#set($inputRoot = $input.path('$'))\n{\n  \"a\" : $inputRoot.a,\n  \"b\" : $inputRoot.b,\n  \"op\" : $inputRoot.op,\n  \"c\" : $inputRoot.c\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_templates",
          "httpMethod": "POST",
          "type": "aws"
        }
      }
    },
    "/calc/{operand1}/{operand2}/{operator}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "operand2",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "operator",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "operand1",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "default": {
              "statusCode": "200",
              "responseTemplates": {
                "application/json": "#set($inputRoot = $input.path('$'))\n{\n  \"input\" : {\n    \"a\" : $inputRoot.a,\n    \"b\" : $inputRoot.b,\n    \"op\" : \"$inputRoot.op\"\n  },\n  \"output\" : {\n    \"c\" : $inputRoot.c\n  }\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_templates",
          "httpMethod": "POST",
          "requestTemplates": {
            "application/json": "{\n   \"a\": \"$input.params('operand1')\",\n   \"b\": \"$input.params('operand2')\",\n   \"op\": #if($input.params('operator')=='%2F')\"/\"#{else}\"$input.params('operator')\"#end\n   \n}"
          },
          "contentHandling": "CONVERT_TO_TEXT",
          "type": "aws"
        }
      }
    }
  },
  "definitions": {
    "Input": {
      "type": "object",
      "required": [
        "a",
        "b",
        "op"
      ],
      "properties": {
        "a": {
          "type": "number"
        },
        "b": {
          "type": "number"
        },
        "op": {
          "type": "string",
          "description": "binary op of ['+', 'add', '-', 'sub', '*', 'mul', '%2F', 'div']"
        }
      },
      "title": "Input"
    },
    "Output": {
      "type": "object",
      "properties": {
        "c": {
          "type": "number"
        }
      },
      "title": "Output"
    },
    "Result": {
      "type": "object",
      "properties": {
        "input": {
          "$ref": "#/definitions/Input"
        },
        "output": {
          "$ref": "#/definitions/Output"
        }
      },
      "title": "Result"
    }
  },
  "x-amazon-apigateway-request-validators": {
    "Validate body": {
      "validateRequestParameters": false,
      "validateRequestBody": true
    },
    "Validate query string parameters and headers": {
      "validateRequestParameters": true,
      "validateRequestBody": false
    }
  }
}
```

------