- API Gateway
前提条件
API Gatewayへの権限
API Gatewayに対してフル権限があること。
AWS CLI
以下のバージョンで動作確認済
- AWS CLI 1.11.8
aws --version
結果(例):
aws-cli/1.11.34 Python/2.7.10 Darwin/15.6.0 botocore/1.4.91
バージョンが古い場合は最新版に更新しましょう。
sudo -H pip install -U awscli
- 準備
=======
0.1. リージョンの決定
export AWS_DEFAULT_REGION='ap-northeast-1'
0.2. プロファイルの確認
プロファイルが想定のものになっていることを確認します。
aws configure list
結果(例):
Name Value Type Location
---- ----- ---- --------
profile lambdaFull-prjz-mbp13 env AWS_DEFAULT_PROFILE
access_key ****************XXXX shared-credentials-file
secret_key ****************XXXX shared-credentials-file
region ap-northeast-1 env AWS_DEFAULT_REGION
0.3. Lambda関数のARN取得
LAMBDA_FUNC_NAME='microservice_http_endpoint-20170102'
LAMBDA_FUNC_ARN=$( \
aws lambda get-function \
--function-name ${LAMBDA_FUNC_NAME} \
--query 'Configuration.FunctionArn' \
--output text \
) \
&& echo ${LAMBDA_FUNC_ARN}
- 事前作業
===========
API名の指定
APIGW_API_NAME='LambdaMicroservice'
同名のREST APIが存在しないことを確認します。
aws apigateway get-rest-apis \
--query "items[?name == \`${APIGW_API_NAME}\`]"
結果(例):
[]
- APIの作成
============
2.1. APIの作成
APIを作成するときは、説明も必ず入れるようにしましょう。
APIGW_API_DESC='This is my API for demonstration purposes'
cat << ETX
APIGW_API_NAME: ${APIGW_API_NAME}
APIGW_API_DESC: "${APIGW_API_DESC}"
ETX
aws apigateway create-rest-api \
--name ${APIGW_API_NAME} \
--description "${APIGW_API_DESC}"
結果(例):
{
"id": "xxxxxxxxxx",
"name": "LambdaMicroservice",
"description": "This is my API for demonstration purposes",
"createdDate": 1448002904
}
2.2. APIの確認
aws apigateway get-rest-apis \
--query "items[?name == \`${APIGW_API_NAME}\`]"
結果(例):
{
"id": "xxxxxxxxxx",
"name": "LambdaMicroservice",
"description": "This is my API for demonstration purposes",
"createdDate": 1448002904
}
APIGW_API_ID=$( \
aws apigateway get-rest-apis \
--query "items[?name == \`${APIGW_API_NAME}\`].id" \
--output text \
) \
&& echo ${APIGW_API_ID}
結果(例):
xxxxxxxxxx
aws apigateway get-rest-api \
--rest-api-id ${APIGW_API_ID}
結果(例):
{
"id": "xxxxxxxxxx",
"name": "LambdaMicroservice",
"description": "This is my API for demonstration purposes",
"createdDate": 1448002904
}
2.3. アカウントの確認
aws apigateway get-account
結果(例):
{
"throttleSettings": {
"rateLimit": 500.0,
"burstLimit": 1000
}
}
2.4. モデルの確認
aws apigateway get-models \
--rest-api-id ${APIGW_API_ID}
結果(例):
{
"items": [
{
"description": "This is a default empty schema model",
"schema": "{\n \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n \"title\" : \"Empty Schema\",\n \"type\" : \"object\"\n}",
"contentType": "application/json",
"id": "ctcxxf",
"name": "Empty"
},
{
"description": "This is a default error schema model",
"schema": "{\n \"$schema\" : \"http://json-schema.org/draft-04/schema#\",\n \"title\" : \"Error Schema\",\n \"type\" : \"object\",\n \"properties\" : {\n \"message\" : { \"type\" : \"string\" }\n }\n}",
"contentType": "application/json",
"id": "fpdged",
"name": "Error"
}
]
}
- リソースの作成
=================
3.1. 現在のリソースの確認
aws apigateway get-resources \
--rest-api-id ${APIGW_API_ID}
結果(例):
{
"items": [
{
"path": "/",
"id": "xxxxxxxxxx"
}
]
}
3.2. 現在のリソースのリソースID取得
APIGW_RESOURCE_PATH="/"
APIGW_RESOURCE_ID=$( \
aws apigateway get-resources \
--rest-api-id ${APIGW_API_ID} \
--query "items[?path == \`${APIGW_RESOURCE_PATH}\`].id" \
--output text \
) \
&& echo ${APIGW_RESOURCE_ID}
結果(例):
xxxxxxxxxx
aws apigateway get-resource \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID}
結果(例):
{
"path": "/",
"id": "xxxxxxxxxx"
}
3.3. 新しいリソースの作成
APIGW_PARENT_ID="${APIGW_RESOURCE_ID}"
APIGW_PATH_PART='microservice-http-endpoint-python'
cat << ETX
APIGW_API_ID: ${APIGW_API_ID}
APIGW_PARENT_ID: ${APIGW_PARENT_ID}
APIGW_PATH_PART: ${APIGW_PATH_PART}
ETX
aws apigateway create-resource \
--rest-api-id ${APIGW_API_ID} \
--parent-id ${APIGW_PARENT_ID} \
--path-part ${APIGW_PATH_PART}
結果(例):
{
"path": "/microservice-http-endpoint-python",
"pathPart": "microservice-http-endpoint-python",
"id": "xxxxxx",
"parentId": "xxxxxxxxxx"
}
3.4. 新しいリソースのリソースID取得
APIGW_RESOURCE_PATH="${APIGW_RESOURCE_PATH}${APIGW_PATH_PART}" \
&& echo ${APIGW_RESOURCE_PATH}
APIGW_RESOURCE_ID=$( \
aws apigateway get-resources \
--rest-api-id ${APIGW_API_ID} \
--query "items[?path == \`${APIGW_RESOURCE_PATH}\`].id" \
--output text \
) \
&& echo ${APIGW_RESOURCE_ID}
結果(例):
xxxxxx
3.5. 新しいリソースの内容確認
aws apigateway get-resource \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID}
結果(例):
{
"path": "/microservice-http-endpoint-python",
"pathPart": "microservice-http-endpoint-python",
"id": "xxxxxx",
"parentId": "xxxxxxxxxx"
}
- Lambda関数の指定
===================
cat << ETX
AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION}
LAMBDA_FUNC_ARN: ${LAMBDA_FUNC_ARN}
ETX
APIGW_INTEG_URI="arn:aws:apigateway:${AWS_DEFAULT_REGION}:lambda:path/2015-03-31/functions/${LAMBDA_FUNC_ARN}/invocations" \
&& echo ${APIGW_INTEG_URI}
結果(例):
arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:microservice_http_endpoint-20170102 /invocations
- ANYメソッドの作成
====================
5.1. methodの作成
HTTP_METHOD='ANY'
AUTH_TYPE='NONE'
cat << ETX
APIGW_API_ID: ${APIGW_API_ID}
APIGW_RESOURCE_ID: ${APIGW_RESOURCE_ID}
HTTP_METHOD: ${HTTP_METHOD}
AUTH_TYPE: ${AUTH_TYPE}
ETX
aws apigateway put-method \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD} \
--authorization-type ${AUTH_TYPE}
結果(例):
{
"apiKeyRequired": false,
"httpMethod": "ANY",
"authorizationType": "NONE"
}
aws apigateway get-method \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD}
結果(例):
{
"apiKeyRequired": false,
"httpMethod": "ANY",
"authorizationType": "NONE"
}
5.2. integrationの作成
aws apigateway get-integration \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD}
結果(例)
A client error (NotFoundException) occurred when calling the GetIntegration operation: No integration defined for method
APIGW_INTEG_TYPE='AWS_PROXY'
APIGW_INTEG_METHOD='POST'
cat << ETX
APIGW_API_ID: ${APIGW_API_ID}
APIGW_RESOURCE_ID: ${APIGW_RESOURCE_ID}
HTTP_METHOD: ${HTTP_METHOD}
APIGW_INTEG_TYPE: ${APIGW_INTEG_TYPE}
APIGW_INTEG_METHOD: ${APIGW_INTEG_METHOD}
APIGW_INTEG_URI: ${APIGW_INTEG_URI}
ETX
aws apigateway put-integration \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD} \
--type ${APIGW_INTEG_TYPE} \
--integration-http-method ${APIGW_INTEG_METHOD} \
--uri ${APIGW_INTEG_URI}
結果(例):
{
"httpMethod": "POST",
"passthroughBehavior": "WHEN_NO_MATCH",
"cacheKeyParameters": [],
"type": "AWS_PROXY",
"uri": "arn:aws:apigateway::lambda:path/2015-03-31/functions/arn:aws:lambda::XXXXXXXXXXXX:function:\ |LAMBDA_FUNC_NAME|\ /invocations",
"cacheNamespace": "2t9qak"
}
aws apigateway get-integration \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD}
結果(例):
{
"httpMethod": "POST",
"passthroughBehavior": "WHEN_NO_MATCH",
"cacheKeyParameters": [],
"uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:microservice_http_endpoint-20170102/invocations",
"cacheNamespace": "88a637",
"type": "AWS_PROXY"
}
5.3. Integration Responseの作成
GETメソッドのリザルトコード200でのIntegration Responseが存在作成しない
ことを確認します。
HTTP_STATUS_CODE='200'
aws apigateway get-integration-response \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD} \
--status-code ${HTTP_STATUS_CODE}
結果:
A client error (NotFoundException) occurred when calling the GetMethodResponse operation: Invalid Response status code specified
GETメソッドのリザルトコード200でのIntegration Responseを作成します。
cat << ETX
APIGW_API_ID: ${APIGW_API_ID}
APIGW_RESOURCE_ID: ${APIGW_RESOURCE_ID}
HTTP_METHOD: ${HTTP_METHOD}
HTTP_STATUS_CODE: ${HTTP_STATUS_CODE}
ETX
aws apigateway put-integration-response \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD} \
--status-code ${HTTP_STATUS_CODE} \
--selection-pattern '.*'
結果(例):
{
"selectionPattern": ".*",
"statusCode": "200"
}
GETメソッドのリザルトコード200でのIntegration Responseを確認します。
aws apigateway get-integration-response \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD} \
--status-code ${HTTP_STATUS_CODE}
結果(例):
{
"selectionPattern": ".*",
"statusCode": "200"
}
GETメソッドのIntegrationにリザルトコード200でのIntegration Responseが
存在することを確認します。
aws apigateway get-integration \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD}
結果(例):
{
"integrationResponses": {
"200": {
"selectionPattern": ".*",
"statusCode": "200"
}
},
"passthroughBehavior": "WHEN_NO_MATCH",
"cacheKeyParameters": [],
"uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:microservice_http_endpoint-20161231/invocations",
"httpMethod": "POST",
"cacheNamespace": "2t9qak",
"type": "AWS_PROXY"
}
5.4. lambda関数の実行権限付与
GETメソッドのリザルトコード200でのIntegration Responseに、Lambda関数を
実行する権限を付与します。
Statement IDを乱数32桁で生成します。 (もっとスマートな方法があれば教え
てください...)
LAMBDA_STAT_ID=$(od -vAn -N16 -tx < /dev/urandom |sed 's/ //g')
LAMBDA_ACTION='lambda:InvokeFunction'
AWS_PRINCIPAL='apigateway.amazonaws.com'
RESOURCE_PATH="${APIGW_RESOURCE_PATH}"
cat << ETX
AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION}
AWS_ID: ${AWS_ID}
APIGW_API_ID: ${APIGW_API_ID}
HTTP_METHOD: ${HTTP_METHOD}
RESOURCE_PATH: ${RESOURCE_PATH}
ETX
SOURCE_ARN="arn:aws:execute-api:${AWS_DEFAULT_REGION}:${AWS_ID}:${APIGW_API_ID}/*/*${RESOURCE_PATH}" \
&& echo ${SOURCE_ARN}
cat << ETX
LAMBDA_FUNC_NAME: ${LAMBDA_FUNC_NAME}
LAMBDA_STAT_ID: ${LAMBDA_STAT_ID}
LAMBDA_ACTION: ${LAMBDA_ACTION}
AWS_PRINCIPAL: ${AWS_PRINCIPAL}
SOURCE_ARN: ${SOURCE_ARN}
ETX
aws lambda add-permission \
--function-name ${LAMBDA_FUNC_NAME} \
--statement-id ${LAMBDA_STAT_ID} \
--action ${LAMBDA_ACTION} \
--principal ${AWS_PRINCIPAL} \
--source-arn ${SOURCE_ARN}
結果(例):
{
"Statement": "{"Sid":"0230237a9b696476bde295c8bf436f99","Resource":"arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:microservice_http_endpoint-20161231","Effect":"Allow","Principal":{"Service":"apigateway.amazonaws.com"},"Action":["lambda:InvokeFunction"],"Condition":{"ArnLike":{"AWS:SourceArn":"arn:aws:execute-api:ap-northeast-1:XXXXXXXXXXXX:s2ff0lq6l9/*/*/microservice-http-endpoint-python"}}}"
}
aws lambda get-policy \
--function-name ${LAMBDA_FUNC_NAME} \
| sed 's/\\//g' | sed 's/\"{/{/' | sed 's/\"$//' \
| jp.py "Policy.Statement[?Sid == \`${LAMBDA_STAT_ID}\`]"
結果(例)
[
{
"Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:microservice_http_endpoint-20170102",
"Effect": "Allow",
"Sid": "0230237a9b696476bde295c8bf436f99",
"Action": "lambda:InvokeFunction",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:execute-api:ap-northeast-1:XXXXXXXXXXXX:xxxxxxxxxx/*/*/microservice-http-endpoint-python"
}
},
"Principal": {
"Service": "apigateway.amazonaws.com"
}
}
]
5.5. Method Responseの作成
aws apigateway get-method-response \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD} \
--status-code ${HTTP_STATUS_CODE}
結果:
An error occurred (NotFoundException) when calling the GetMethodResponse operation: Invalid Response status code specified
cat << ETX
APIGW_API_ID: ${APIGW_API_ID}
APIGW_RESOURCE_ID: ${APIGW_RESOURCE_ID}
HTTP_METHOD: ${HTTP_METHOD}
HTTP_STATUS_CODE: ${HTTP_STATUS_CODE}
ETX
aws apigateway put-method-response \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD} \
--status-code ${HTTP_STATUS_CODE} \
--response-models '{}'
結果(例)
{
"responseModels": {},
"statusCode": "200"
}
aws apigateway get-method-response \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD} \
--status-code ${HTTP_STATUS_CODE}
結果(例):
{
"responseModels": {},
"statusCode": "200"
}
aws apigateway get-method \
--rest-api-id ${APIGW_API_ID} \
--resource-id ${APIGW_RESOURCE_ID} \
--http-method ${HTTP_METHOD}
結果(例):
{
"apiKeyRequired": false,
"httpMethod": "ANY",
"methodIntegration": {
"integrationResponses": {
"200": {
"selectionPattern": ".*",
"statusCode": "200"
}
},
"passthroughBehavior": "WHEN_NO_MATCH",
"cacheKeyParameters": [],
"uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:microservice-http-endpoint-python/invocations",
"httpMethod": "POST",
"cacheNamespace": "xxxxxx",
"type": "AWS_PROXY"
},
"methodResponses": {
"200": {
"responseModels": {},
"statusCode": "200"
}
},
"authorizationType": "NONE"
}
5.6. メソッドのテスト
(省略)
- APIのデプロイ
================
6.1. APIのデプロイ
aws apigateway get-deployments \
--rest-api-id ${APIGW_API_ID}
結果:
{
"items": []
}
APIGW_STAGE_NAME='test'
APIGW_STAGE_DESC='This is a test.'
APIGW_DEPLOY_DESC='Calling Lambda functions MicroserviceEndpoint.'
cat << ETX
APIGW_API_ID: ${APIGW_API_ID}
APIGW_STAGE_NAME: ${APIGW_STAGE_NAME}
APIGW_STAGE_DESC: "${APIGW_STAGE_DESC}"
APIGW_DEPLOY_DESC: "${APIGW_DEPLOY_DESC}"
ETX
aws apigateway create-deployment \
--rest-api-id ${APIGW_API_ID} \
--stage-name ${APIGW_STAGE_NAME} \
--stage-description "${APIGW_STAGE_DESC}" \
--description "${APIGW_DEPLOY_DESC}"
結果(例):
{
"description": "Calling Lambda functions MicroserviceEndpoint.",
"id": "aody9s",
"createdDate": 1483327540
}
aws apigateway get-deployments \
--rest-api-id ${APIGW_API_ID}
結果(例):
{
"items": [
{
"createdDate": 1483327540,
"id": "aody9s",
"description": "Calling Lambda functions MicroserviceEndpoint."
}
]
}
6.2. API IDの取得
APIGW_DEPLOY_ID=$( \
aws apigateway get-deployments \
--rest-api-id ${APIGW_API_ID} \
--query "items[?description == \`${APIGW_DEPLOY_DESC}\`].id" \
--output text \
) \
&& echo ${APIGW_DEPLOY_ID}
結果(例)
xxxxxx
6.3. APIの情報の取得
aws apigateway get-deployment \
--rest-api-id ${APIGW_API_ID} \
--deployment-id ${APIGW_DEPLOY_ID}
結果(例):
{
"description": "Calling Lambda functions MicroserviceEndpoint.",
"id": "aody9s",
"createdDate": 1483327540
}
6.4. APIのステージ名の取得
APIGW_STAGE_NAME=$( \
aws apigateway get-stages \
--rest-api-id ${APIGW_API_ID} \
--query "item[?description == \`${APIGW_STAGE_DESC}\`].stageName" \
--output text \
) \
&& echo ${APIGW_STAGE_NAME}
結果(例):
test
aws apigateway get-stage \
--rest-api-id ${APIGW_API_ID} \
--stage-name ${APIGW_STAGE_NAME}
結果(例):
{
"stageName": "test",
"description": "This is a test.",
"cacheClusterEnabled": false,
"cacheClusterStatus": "NOT_AVAILABLE",
"deploymentId": "aody9s",
"lastUpdatedDate": 1483327540,
"createdDate": 1483327540,
"methodSettings": {}
}
7 .APIのテスト
GETメソッドのテスト
PATH_WITH_QUERY_STRING='TableName=microservice-http'
cat << ETX
APIGW_API_ID: ${APIGW_API_ID}
AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION}
APIGW_STAGE_NAME: ${APIGW_STAGE_NAME}
APIGW_RESOURCE_PATH: ${APIGW_RESOURCE_PATH}
PATH_WITH_QUERY_STRING: ${PATH_WITH_QUERY_STRING}
ETX
APIGW_URI="https://${APIGW_API_ID}.execute-api.${AWS_DEFAULT_REGION}.amazonaws.com/${APIGW_STAGE_NAME}${APIGW_RESOURCE_PATH}?${PATH_WITH_QUERY_STRING}" \
&& echo ${APIGW_URI}
表示されたURLをブラウザで開いて、以下のJSONファイルが表示されればOKで
す。
ブラウザ表示の結果:
{"Count": 1, "Items": [{"Description": "sample", "Name": "taro"}], "ScannedCount": 1, "ResponseMetadata": {"RetryAttempts": 0, "HTTPStatusCode": 200, "RequestId": "EQ6FPKSBTR75S2LEFQ4JPA6407VV4KQNSO5AEMVJF66Q9ASUAABG", "HTTPHeaders": {"x-amzn-requestid": "EQ6FPKSBTR75S2LEFQ4JPA6407VV4KQNSO5AEMVJF66Q9ASUAABG", "content-length": "89", "server": "Server", "connection": "keep-alive", "x-amz-crc32": "2586798783", "date": "Mon, 02 Jan 2017 03:33:26 GMT", "content-type": "application/x-amz-json-1.0"}}}