教學課程:使RESTAPI用 Lambda 非代理整合建立 - Amazon API Gateway

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

教學課程:使RESTAPI用 Lambda 非代理整合建立

在本逐步解說中,我們使用API閘道主控台來建置API可讓用戶端透過 Lambda 非代理整合 (也稱為自訂整合) 呼叫 Lambda 函數。如需有關 AWS Lambda 和 Lambda 函數的詳細資訊,請參閱 AWS Lambda 開發人員指南

為了促進學習,我們選擇了最少API設定的簡單 Lambda 函數,引導您完成API使用 Lambda 自訂整合建置API閘道的步驟。必要時,我們會說明一些邏輯。如需 Lambda 自訂整合的更詳細範例,請參閱教學課程:建立RESTAPI包含兩個 AWS 服務整合和一個 Lambda 非代理整合的計算器

在建立之前API,請在中建立 Lambda 函數來設定 Lambda 後端 AWS Lambda,如下所述。

為 Lambda 非代理整合建立 Lambda 函數

注意

建立 Lambda 函數可能會導致您的 AWS 帳戶收取費用。

在此步驟中,您會為 Lambda 自訂整合建立 "Hello, World!" 之類的 Lambda 函數。在此演練中,此函數稱為 GetStartedLambdaIntegration

以下是此 GetStartedLambdaIntegration Lambda 函數的實作:

Node.js
'use strict'; var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; var times = ['morning', 'afternoon', 'evening', 'night', 'day']; console.log('Loading function'); export const handler = function(event, context, callback) { // Parse the input for the name, city, time and day property values let name = event.name === undefined ? 'you' : event.name; let city = event.city === undefined ? 'World' : event.city; let time = times.indexOf(event.time)<0 ? 'day' : event.time; let day = days.indexOf(event.day)<0 ? null : event.day; // Generate a greeting let greeting = 'Good ' + time + ', ' + name + ' of ' + city + '. '; if (day) greeting += 'Happy ' + day + '!'; // Log the greeting to CloudWatch console.log('Hello: ', greeting); // Return a greeting to the caller callback(null, { "greeting": greeting }); };
Python
import json days = { 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'} times = {'morning', 'afternoon', 'evening', 'night', 'day'} def lambda_handler(event, context): print(event) # parse the input for the name, city, time, and day property values try: if event['name']: name = event['name'] except KeyError: name = 'you' try: if event['city']: city = event['city'] except KeyError: city = 'World' try: if event['time'] in times: time = event['time'] else: time = 'day' except KeyError: time = 'day' try: if event['day'] in days: day = event['day'] else: day = '' except KeyError: day = '' # Generate a greeting greeting = 'Good ' + time + ', ' + name + ' of ' + \ city + '.' + ['', ' Happy ' + day + '!'][day != ''] # Log the greeting to CloudWatch print(greeting) # Return a greeting to the caller return {"greeting": greeting}

對於 Lambda 自訂整合,API閘道會將輸入作為整合要求主體從用戶端傳遞至 Lambda 函數。此輸入是 Lambda 函數處理常式的 event 物件。

我們的 Lambda 函數很簡單。它會剖析 eventnamecitytime 屬性的輸入 day 物件。然後,它會將問候語 (做為JSON物{"message":greeting}件) 傳回給呼叫者。該訊息的模式為 "Good [morning|afternoon|day], [name|you] in [city|World]. Happy day!"。假設 Lambda 函數的輸入屬於下列JSON物件:

{ "city": "...", "time": "...", "day": "...", "name" : "..." }

如需詳細資訊,請參閱《AWS Lambda 開發人員指南》

此外,該函數 CloudWatch 通過調用將其執行記錄到 Amazon console.log(...)。這有助於在偵錯函數時追蹤呼叫。若要允許GetStartedLambdaIntegration函數記錄呼叫,請為 Lambda 函數設定具有適當政策的IAM角色,以建立 CloudWatch 串流並將記錄項目新增至串流。Lambda 主控台會引導您建立必要的IAM角色和政策。

如果您在API不使用 API Gateway 主控台的情況下進行設定,例如API從 Open API 檔案匯入時,必須明確建立 (如有必要),並為 API Gateway 設定叫用角色和政策,以呼叫 Lambda 函數。如需如何為API閘道設定 Lambda 叫用和執行角色的詳細資訊API,請參閱控制對RESTAPI具有IAM權限的訪問

相較於 GetStartedLambdaProxyIntegration Lambda 代理整合的 Lambda 函數,GetStartedLambdaIntegrationLambda 自訂整合的 Lambda 函數只會從API閘道API整合要求主體取得輸入。該函數可以返回任何JSON對象,字符串,數字,布爾甚至二進制 blob 的輸出。相較之下,Lambda 代理整合的 Lambda 函數可以從任何請求資料取得輸入,但必須傳回特定JSON物件的輸出。Lambda 自訂整合的GetStartedLambdaIntegration函數可以將API請求參數作為輸入,前提是 API Gateway 會將必要的API請求參數對應至整合要求主體,然後再將用戶端請求轉送至後端。為了實現這API種情況,API開發人員必須創建一個映射模板,並在創建API.

現在,建立 GetStartedLambdaIntegration Lambda 函數。

建立 Lambda 自訂整合的 GetStartedLambdaIntegration Lambda 函數
  1. 在開啟 AWS Lambda 主控台https://console.aws.amazon.com/lambda/

  2. 執行以下任意一項:

    • 出現歡迎頁面時,請選擇 Get Started Now (立即開始使用),然後選擇 Create function (建立函數)

    • 出現 Lambda > Functions (Lambda > 函數) 清單頁面時,請選擇 Create function (建立函數)

  3. 選擇 Author from scratch (從頭開始撰寫)。

  4. Author from scratch (從頭開始撰寫) 窗格上,執行下列操作:

    1. 名稱,輸入 GetStartedLambdaIntegration 做為 Lambda 函數名稱。

    2. 針對執行期,請選擇最新支援的 Node.jsPython 執行期。

    3. 對於「架構」,請保留預設設定。

    4. 許可下,展開變更預設執行角色。從執行角色下拉式清單中,選擇從 AWS 政策範本建立新角色

    5. 角色名稱中輸入角色名稱 (例如 GetStartedLambdaIntegrationRole)。

    6. Policy templates (政策範本) 中,選擇 Simple microservice permissions (簡易微服務許可)

    7. 選擇 Create function (建立函式)

  5. Configure function (設定函數) 窗格的 Function code (函數程式碼) 中,執行下列操作:

    1. 將本節開頭列出的 Lambda 函數程式碼複製並貼到內嵌程式碼編輯器。

    2. 對於此區段中的所有其他欄位,則保留預設選項。

    3. 選擇 Deploy (部署)

  6. 若要測試新建立的函數,請選擇測試索引標籤。

    1. 事件名稱輸入 HelloWorldTest

    2. 對於 Event JSON,請使用下列命令取代預設程式碼。

      { "name": "Jonny", "city": "Seattle", "time": "morning", "day": "Wednesday" }
    3. 選擇測試以呼叫函數。執行結果:成功區段會隨即顯示。展開詳細資訊,您會看到下列輸出。

      { "greeting": "Good morning, Jonny of Seattle. Happy Wednesday!" }

      輸出也會寫入 CloudWatch 日誌。

作為輔助練習,您可以使用IAM主控台來檢視作為 Lambda 函數建立一部分而建立的IAM角色 (GetStartedLambdaIntegrationRole)。附加到此IAM角色的是兩個內嵌政策。其中一個規定 Lambda 執行的最基本許可。它允許在 CloudWatchCreateLogGroup建立 Lambda 函數的區域中呼叫您帳戶的任何 CloudWatch 資源。此原則也允許建立 GetStartedLambdaIntegration Lambda 函數的 CloudWatch 串流和記錄事件。

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "logs:CreateLogGroup", "Resource": "arn:aws:logs:region:account-id:*" }, { "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": [ "arn:aws:logs:region:account-id:log-group:/aws/lambda/GetStartedLambdaIntegration:*" ] } ] }

另一個原則文件適用於呼叫此範例中未使用的其他 AWS 服務。您目前可以略過。

與IAM角色相關聯的是受信任的實體,也就是說lambda.amazonaws.com。以下是信任關係:

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

此信任關係和內嵌政策的組合使 Lambda 函數可以叫用console.log()函數將事件 CloudWatch 記錄到日誌。

API使用 Lambda 非代理整合建立

建立並測試 Lambda 函數 (GetStartedLambdaIntegration) 後,您就可以透過API閘道公開函數了API。出於說明目的,我們使用泛型HTTP方法公開 Lambda 函數。我們使用請求主體,URL路徑變量,查詢字符串和頭從客戶端接收所需的輸入數據。我們打開 API Gateway 請求驗證程序,API以確保所有必需的數據正確定義和指定。我們為 API Gateway 設定對應範本,將用戶端提供的請求資料轉換為後端 Lambda 函數所需的有效格式。

若要API使用 Lambda 非代理整合建立
  1. https://console.aws.amazon.com/ap igateway 登入API閘道主控台。

  2. 如果這是您第一次使用 API Gateway,您會看到一個介紹服務功能的頁面。在下方 RESTAPI,選擇 [建置]。出現 [建立範例] API 快顯視窗時,選擇 [確定]

    如果這不是您第一次使用API閘道,請選擇 [建立] API。在下方 RESTAPI,選擇 [建置]。

  3. 對於API名稱,輸入LambdaNonProxyAPI

  4. 描述,請輸入描述。

  5. 保持API端點類型設定為 [地區]。

  6. 選擇 [建立] API。

建立您的資源之後API,您會建立/{city} 資源。這是具有路徑變數的資源範例,其會接受來自用戶端的輸入。稍後,您會使用對應範本將此路徑變數對應到 Lambda 函數輸入。

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

  2. 代理資源保持關閉。

  3. 資源路徑保持為 /

  4. 針對資源名稱,輸入 {city}

  5. 保持 CORS(跨源資源共享)關閉。

  6. 選擇建立資源

在建立 /{city} 資源後,請建立 ANY 方法。動ANYHTTP詞是客戶端在運行時提交的有效HTTP方法的佔位符。此範例顯示 ANY 方法可用於 Lambda 自訂整合以及 Lambda 代理整合。

建立 ANY 方法
  1. 選取 /{city} 資源,然後選擇建立方法

  2. 針對方法類型,選取 ANY

  3. 針對整合類型,選取 Lambda 函數

  4. Lambda 代理整合保持關閉。

  5. 對於 Lambda 函數,請選取 AWS 區域 您建立 Lambda 函數的位置,然後輸入函數名稱。

  6. 選擇 [方法要求設定]。

    現在,您開啟URL路徑變數、查詢字串參數和標頭的要求驗證程式,以確保已定義所有必要資料。在此範例中,您會建立 time 查詢字串參數和 day 標頭。

  7. 對於請求驗證程式,選取驗證查詢字串參數與標頭

  8. 選擇URL查詢字串參數,然後執行下列動作:

    1. 選擇新增查詢字串

    2. 針對名稱,輸入 time

    3. 開啟必要

    4. 快取保持關閉。

  9. 選擇HTTP要求標頭,然後執行下列動作:

    1. 選擇新增標頭

    2. 針對名稱,輸入 day

    3. 開啟必要

    4. 快取保持關閉。

  10. 選擇建立方法

開啟請求驗證程式之後,您可以根據後端 Lambda 函數的要求,新增內文對應範本來將傳入的請求轉換為JSON有效負載,以設定ANY方法的整合要求。

設定整合請求
  1. 整合要求索引標籤的整合要求設定下,選擇編輯

  2. 針對請求內文傳遞,選取未定義範本時 (建議)

  3. 選擇對應範本

  4. 選擇新增對應範本

  5. 針對內容類型,輸入 application/json

  6. 針對範本內文,輸入下列程式碼:

    #set($inputRoot = $input.path('$')) { "city": "$input.params('city')", "time": "$input.params('time')", "day": "$input.params('day')", "name": "$inputRoot.callerName" }
  7. 選擇 Save (儲存)。

測試調用方法 API

APIGateway 主控台提供測試工具,供您在部署之API前測試呼叫。您可以使用主控台的「測試」功能,API藉由提交下列要求來測試:

POST /Seattle?time=morning day:Wednesday { "callerName": "John" }

在此測試請求中,您會將 ANY 設定為 POST、將 {city} 設定為 Seattle、將 Wednesday 設定為 day 標頭值,並將 "John" 指派為 callerName 值。

測試 ANY 方法
  1. 選擇測試標籤。您可能需要選擇向右箭頭按鈕才能顯示此索引標籤。

  2. 針對方法類型,選取 POST

  3. 針對路徑,在城市下輸入 Seattle

  4. 針對查詢字串,輸入 time=morning

  5. 針對標頭,輸入 day:Wednesday

  6. 針對請求內文,輸入 { "callerName": "John" }

  7. 選擇測試

遵循下列方式驗證所傳回的回應承載:

{ "greeting": "Good morning, John of Seattle. Happy Wednesday!" }

您也可以檢視記錄,以檢查 API Gateway 處理要求和回應的方式。

Execution log for request test-request Thu Aug 31 01:07:25 UTC 2017 : Starting execution for request: test-invoke-request Thu Aug 31 01:07:25 UTC 2017 : HTTP Method: POST, Resource Path: /Seattle Thu Aug 31 01:07:25 UTC 2017 : Method request path: {city=Seattle} Thu Aug 31 01:07:25 UTC 2017 : Method request query string: {time=morning} Thu Aug 31 01:07:25 UTC 2017 : Method request headers: {day=Wednesday} Thu Aug 31 01:07:25 UTC 2017 : Method request body before transformations: { "callerName": "John" } Thu Aug 31 01:07:25 UTC 2017 : Request validation succeeded for content type application/json Thu Aug 31 01:07:25 UTC 2017 : Endpoint request URI: https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:GetStartedLambdaIntegration/invocations Thu Aug 31 01:07:25 UTC 2017 : Endpoint request headers: {x-amzn-lambda-integration-tag=test-request, Authorization=****************************************************************************************************************************************************************************************************************************************************************************************************************************************338c72, X-Amz-Date=20170831T010725Z, x-amzn-apigateway-api-id=beags1mnid, X-Amz-Source-Arn=arn:aws:execute-api:us-west-2:123456789012:beags1mnid/null/POST/{city}, Accept=application/json, User-Agent=AmazonAPIGateway_beags1mnid, X-Amz-Security-Token=FQoDYXdzELL//////////wEaDMHGzEdEOT/VvGhabiK3AzgKrJw+3zLqJZG4PhOq12K6W21+QotY2rrZyOzqhLoiuRg3CAYNQ2eqgL5D54+63ey9bIdtwHGoyBdq8ecWxJK/YUnT2Rau0L9HCG5p7FC05h3IvwlFfvcidQNXeYvsKJTLXI05/yEnY3ttIAnpNYLOezD9Es8rBfyruHfJfOqextKlsC8DymCcqlGkig8qLKcZ0hWJWVwiPJiFgL7laabXs++ZhCa4hdZo4iqlG729DE4gaV1mJVdoAagIUwLMo+y4NxFDu0r7I0/EO5nYcCrppGVVBYiGk7H4T6sXuhTkbNNqVmXtV3ch5bOlh7 [TRUNCATED] Thu Aug 31 01:07:25 UTC 2017 : Endpoint request body after transformations: { "city": "Seattle", "time": "morning", "day": "Wednesday", "name" : "John" } Thu Aug 31 01:07:25 UTC 2017 : Sending request to https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:GetStartedLambdaIntegration/invocations Thu Aug 31 01:07:25 UTC 2017 : Received response. Integration latency: 328 ms Thu Aug 31 01:07:25 UTC 2017 : Endpoint response body before transformations: {"greeting":"Good morning, John of Seattle. Happy Wednesday!"} Thu Aug 31 01:07:25 UTC 2017 : Endpoint response headers: {x-amzn-Remapped-Content-Length=0, x-amzn-RequestId=c0475a28-8de8-11e7-8d3f-4183da788f0f, Connection=keep-alive, Content-Length=62, Date=Thu, 31 Aug 2017 01:07:25 GMT, X-Amzn-Trace-Id=root=1-59a7614d-373151b01b0713127e646635;sampled=0, Content-Type=application/json} Thu Aug 31 01:07:25 UTC 2017 : Method response body after transformations: {"greeting":"Good morning, John of Seattle. Happy Wednesday!"} Thu Aug 31 01:07:25 UTC 2017 : Method response headers: {X-Amzn-Trace-Id=sampled=0;root=1-59a7614d-373151b01b0713127e646635, Content-Type=application/json} Thu Aug 31 01:07:25 UTC 2017 : Successfully completed execution Thu Aug 31 01:07:25 UTC 2017 : Method completed with status: 200

日誌會顯示對應前的傳入請求,以及對應後的整合請求。測試失敗時,日誌可用於評估原始輸入是否正確或對應範本是否正常運作。

部署 API

測試呼叫是一種模擬並有所限制。例如,它會略過在. API 若要即時測試API執行,您必須API先部署。若要部署API,您可以建立階段來建立API當時的快照。階段名稱也會在預設主機名稱API之後定義基本路徑。API的根資源會附加在階段名稱之後。修改時API,您必須將其重新部署到新的或現有的階段,變更才會生效。

若要部署API到階段
  1. 選擇部署API

  2. 針對階段,選取新階段

  3. 針對階段名稱,輸入 test

    注意

    輸入必須是 UTF -8 編碼(即非本地化)文本。

  4. 描述,請輸入描述。

  5. 選擇部署

階段詳細資料下,選擇複製圖示以複製您API的呼叫URL。的基礎的一API般模式URL是https://api-id.region.amazonaws.com/stageName。例如,在us-west-2區域中建立並部署到test階段URL的 API (beags1mnid) 基底為https://beags1mnid.execute-api.us-west-2.amazonaws.com/test

API在部署階段測試

有幾種方法可以測試已部署的API. 對於僅使用URL路徑變數或查詢字串參數的GET請求,您可以在瀏覽器URL中輸入API資源。對於其他方法,您必須使用更進階的RESTAPI測試公用程式,例如POSTMANc URL

為了測試API使用 c URL
  1. 在連線至網際網路的本機電腦上,開啟終端機視窗。

  2. 若要測試 POST /Seattle?time=evening

    複製以下 c URL 命令並將其粘貼到終端窗口中。

    curl -v -X POST \ 'https://beags1mnid.execute-api.us-west-2.amazonaws.com/test/Seattle?time=evening' \ -H 'content-type: application/json' \ -H 'day: Thursday' \ -H 'x-amz-docs-region: us-west-2' \ -d '{ "callerName": "John" }'

    您應該取得具有下列承載的成功回應:

    {"greeting":"Good evening, John of Seattle. Happy Thursday!"}

    如果您在此方法請求中將 POST 變更為 PUT,您會取得相同的回應。

清除

若您不再需要因為此演練所建立的 Lambda 函數,可立即將其刪除。您也可以刪除隨附的IAM資源。

警告

如果您打算完成本系列中的其他演練,則不要刪除 Lambda 執行角色或 Lambda 呼叫角色。如果刪除APIs依賴的 Lambda 函數,這些函數APIs將不再起作用。而刪除 Lambda 函數無法復原。所以若要再次使用該 Lambda 函數,必須加以重新建立。

如果您刪除 Lambda 函數所依賴的IAM資源,則該 Lambda 函數將無法再運作,任何依賴APIs該函數的資源都將不再有效。刪除資IAM源無法復原。如果要再次使用資IAM源,則必須重新建立資源。

若要刪除 Lambda 函數
  1. 登入 AWS Management Console 並開啟 AWS Lambda 主控台,位於https://console.aws.amazon.com/lambda/

  2. 從函數清單中選擇,選擇「GetStartedLambdaIntegration動作」,然後選擇「刪除函數」。出現提示時,再次選擇 Delete (刪除)

刪除相關聯的 IAM 資源
  1. 在開啟IAM主控台https://console.aws.amazon.com/iam/

  2. Details (詳細資訊) 中,選擇 Roles (角色)

  3. 從角色清單中選擇 GetStartedLambdaIntegrationRole,選擇角色動作,然後選擇刪除角色。依照主控台中的步驟刪除角色。