

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

# 教學課程：建立具有兩個 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：建立 `POST` 方法與 JSON 承載搭配來呼叫 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. 選擇 **Create Role (建立角色)**。

1. 在**選取可信任執行個體類型**下，選取 **AWS 服務**。

1. 在 **Choose the service that will use this role (選擇將使用此角色的服務)** 下，選擇 **Lambda (Lambda)**。

1. 選擇 **Next: Permissions (下一步：許可)**。

1. 選擇 **Create Policy (建立政策)**。

   **Create Policy (建立政策)** 主控台將開啟新的時段。在該視窗中，執行下列作業：

   1. 在 **JSON** 標籤中，用以下政策取代現有政策。

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

****  

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

------

   1. 選擇 **Review policy (檢閱政策)**。

   1. 在 **Review Policy (檢閱政策)** 下，執行下列操作：

      1. 在 **Name (名稱)** 中輸入名稱，例如 **lambda\$1execute**。

      1. 選擇 **Create Policy (建立政策)**。

1. 在原本的 **Create Role (建立角色)** 主控台視窗中，執行下列動作：

   1. 在 **Attach permissions policies (連接許可政策)** 下方，從下拉式清單中選擇您的 **lambda\$1execute** 政策。

      如果您在清單中沒有看到您的政策，請選擇清單頂端的重新整理按鈕。(請不要重新整理瀏覽器頁面！)

   1. 選擇 **Next: Add Tags (下一步：新增標籤)**。

   1. 選擇 **Next:Review (下一步：檢閱)**。

   1. 在 **Role name (角色名稱)** 中輸入名稱，例如 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role**。

   1. 選擇 **Create Role** (建立角色)。

1. 從角色清單中選擇您的 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role**。

1. 選擇 **Trust Relationships (信任關係)** 標籤。

1. 選擇 **Edit trust relationship (編輯信任關係)**。

1. 用以下內容取代現有政策：

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

****  

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

------

1. 選擇 **Update Trust Policy (更新信任政策)**。

1. 請記住您剛建立角色的角色 ARN。以供稍後使用。

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

接下來，您會使用 Lambda 主控台建立 Lambda 函數。

1. 在 Lambda 主控台中，請選擇 **Create function (建立函數)**。

1. 選擇 **Author from Scratch (從頭開始撰寫)**。

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. 選擇 **Deploy (部署)**。

 此函數需要 `a` 輸入參數有兩個運算元 (`b` 和 `op`) 和一個運算子 (`event`)。輸入是下列格式的 JSON 物件：

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

此函數會傳回計算的結果 (`c`) 和輸入。對於無效的輸入，該函數會傳回 null 值或「無效 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. 選擇 **Save** (儲存)。

1. 選擇 **Test (測試)**。

1. 展開 **Execution result: succeeded (執行結果：成功)**。請查看下列事項：

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

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

下列程序說明如何為您剛建立的 `Calc` Lambda 函數建立 API。在後續幾節中，您會將資源和方法新增至其中。

**建立 API**

1. 在以下網址登入 API Gateway 主控台：[https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)。

1. 如果這是您第一次使用 API Gateway，您會看到服務功能的介紹頁面。在 **REST API** 下方，選擇 **Build (組建)**。當 **Create Example API (建立範例 API)** 快顯出現時，選擇 **OK (確定)**。

   如果這不是第一次使用 API Gateway，請選擇 **Create API (建立 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>

透過建立 `GET` 方法，將查詢字串參數傳遞至 Lambda 函數，您可以啟用 API，讓其可透過瀏覽器叫用。這種方法很有用，尤其適用於允許開放存取的 API。

在建立 API 之後，請建立資源。一般而言，會根據應用程式邏輯將 API 資源組織為資源樹狀結構。在此步驟中，您會建立 **/calc** 資源。

**建立 **/calc** 資源**

1. 選擇**建立資源**。

1. 讓**代理資源**保持關閉。

1. 將**資源路徑**保持為 `/`。

1. 針對**資源名稱**，輸入 **calc**。

1. 讓 **CORS (跨來源資源分享)** 保持關閉。

1. 選擇**建立資源**。

透過建立 `GET` 方法，將查詢字串參數傳遞至 Lambda 函數，您可以啟用 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. 針對**動作類型**，選取**使用路徑覆寫**。這個選項可讓我們指定 [Invoke](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html) 動作的 ARN，來執行 `Calc` 函數。

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_tw/apigateway/latest/developerguide/images/aws_proxy_lambda_calc_get_method_test_new_console.png)

## 整合 2：建立 `POST` 方法與 JSON 承載搭配來呼叫 Lambda 函數
<a name="api-as-lambda-proxy-expose-post-method-with-json-body-to-call-lambda-function"></a>

透過建立 `POST` 方法與 JSON 承載搭配來呼叫 Lambda 函數，讓用戶端必須在請求內文中提供後端函數的必要輸入。為了確保用戶端上傳正確的輸入資料，您將在承載上啟用請求驗證。

**建立具有 JSON 承載的 `POST` 方法**

1. 選取 **/calc** 資源，然後選擇**建立方法**。

1. 針對**方法類型**，選取 **POST**。

1. 針對**整合類型**，選取 **AWS 服務**。

1. 針對 **AWS 區域**，選取您建立 Lambda 函數 AWS 區域 的 。

1. 針對 **AWS 服務**，選取 **Lambda**。

1. 讓 **AWS 子網域**保持空白。

1. 針對 **HTTP 方法**，選取 **POST**。

1. 針對**動作類型**，選取**使用路徑覆寫**。這個選項可讓我們指定 [Invoke](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html) 動作的 ARN，來執行 `Calc` 函數。

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_tw/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 編碼，所以必須將 division 運算子指定為 `%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. 對於**運算子**，輸入 **\$1**。

1. 選擇 **Test (測試)**。

1. 結果應如下所示：  
![\[在 API Gateway 主控台測試 GET 方法。\]](http://docs.aws.amazon.com/zh_tw/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. 對於**運算子**，輸入 **\$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
    }
  }
}
```

------