[JAWS-UG CLI] API Gateway: #1 RestAPIの作成



前提条件
========


API Gatewayへの権限
--------------

API Gatewayに対してフル権限があること。


AWS CLI
-------

以下のバージョンで動作確認済

* AWS CLI 1.9.8

```bash:コマンド:
aws --version
```

```text:結果(例):
aws-cli/1.9.8 Python/2.7.5 Darwin/13.4.0 botocore/1.3.0
```


0. 準備
=======


0.1. 変数の確認
---------------

プロファイルが想定のものになっていることを確認します。

```bash:変数の確認:
aws configure list
```

```text:結果(例):
            Name                    Value             Type    Location
            ----                    -----             ----    --------
         profile       administrator-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.2. リージョンの取得

```bash:コマンド:
AWS_REGION='ap-northeast-1'
```

## 0.3. Lambda関数のARN取得


```bash:変数の設定:
LAMBDA_FUNC_NAME='GetHelloWithName'
```

```bash:変数の設定:
LAMBDA_FUNC_ARN=$( \
  aws lambda get-function \
    --function-name ${LAMBDA_FUNC_NAME} \
    --query 'Configuration.FunctionArn' \
    --output text \
) \
  && echo ${LAMBDA_FUNC_ARN}
```





1. 事前作業
===========


## API名の指定

```bash:コマンド:
APIGW_API_NAME='MyDemoAPI'
```

同名のREST APIが存在しないことを確認します。

```bash:コマンド:
aws apigateway get-rest-api \
  --rest-api-id ${APIGW_API_NAME}
```

```text:結果(例):
A client error (NotFoundException) occurred when calling the GetRestApi operation: Invalid REST API identifier specified
```



# 2. APIの作成

## 2.1. APIの作成

APIを作成するときは、説明も必ず入れるようにしましょう。

```bash:コマンド:
APIGW_API_DESC='This is my API for demonstration purposes'
```

```bash:変数の確認:
cat << ETX

        APIGW_API_NAME: ${APIGW_API_NAME}
        APIGW_API_DESC: "${APIGW_API_DESC}"

ETX
```

```bash:コマンド:
aws apigateway create-rest-api \
        --name ${APIGW_API_NAME} \
        --description "${APIGW_API_DESC}"
```

```json:結果(例):
      {
        "id": "xxxxxxxxxx",
        "name": "MyDemoAPI",
        "description": "This is my API for demonstration purposes",
        "createdDate": 1448002904
      }
```

## 2.2. APIの確認

```bash:コマンド:
aws apigateway get-rest-apis 
```

```json:結果(例):
      {
        "items": [
          {
              "description": "This is my API for demonstration purposes",
              "createdDate": 1445947998,
              "id": "xxxxxxxxxx",
              "name": "MyDemoAPI"
          }
        ]
      }
```

```bash:コマンド:
APIGW_API_ID=$( \
        aws apigateway get-rest-apis \
          --query "items[?name == \`${APIGW_API_NAME}\`].id" \
          --output text \
      ) \
        && echo ${APIGW_API_ID}
```

```text:結果(例):
      xxxxxxxxxx
```

```bash:コマンド:
aws apigateway get-rest-api \
        --rest-api-id ${APIGW_API_ID}
```

```json:結果(例):
      {
        "id": "xxxxxxxxxx",
        "name": "MyDemoAPI",
        "description": "This is my API for demonstration purposes",
        "createdDate": 1445947998
      }
```



## 2.3. アカウントの確認

```bash:コマンド:
aws apigateway get-account 
```

```json:結果(例):
      {
        "throttleSettings": {
          "rateLimit": 500.0,
          "burstLimit": 1000
        }
      }
```


## 2.4. モデルの確認

```bash:コマンド:
aws apigateway get-models \
        --rest-api-id ${APIGW_API_ID}
```

```json:結果(例):
{
    "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": "xxxxxx", 
            "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": "xxxxxx", 
            "name": "Error"
        }
    ]
}
```


# 3. リソースの作成

## 3.1. 現在のリソースの確認

```bash:コマンド:
aws apigateway get-resources \
        --rest-api-id ${APIGW_API_ID}
```

```json:結果(例):
      {
        "items": [
          {
              "path": "/",
              "id": "xxxxxxxxxx"
          }
        ]
      }
```


## 3.2. 現在のリソースのリソースID取得

```bash:変数の設定:
APIGW_RESOURCE_PATH="/"
```

```bash:コマンド:
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}
```

```text:結果(例):
      xxxxxxxxxx
```

```bash:コマンド:
aws apigateway get-resource \
        --rest-api-id ${APIGW_API_ID} \
        --resource-id ${APIGW_RESOURCE_ID}
```

```json:結果(例):
      {
        "path": "/",
        "id": "xxxxxxxxxx"
      }
```


## 3.3. 新しいリソースの作成

```bash:変数の設定:
APIGW_PARENT_ID="${APIGW_RESOURCE_ID}"
APIGW_PATH_PART='mydemoresource'
```

```bash:変数の確認:
cat << ETX

        APIGW_API_ID:    ${APIGW_API_ID}
        APIGW_PARENT_ID: ${APIGW_PARENT_ID}
        APIGW_PATH_PART: ${APIGW_PATH_PART}

ETX
```

```bash:コマンド:
aws apigateway create-resource \
        --rest-api-id ${APIGW_API_ID} \
        --parent-id ${APIGW_PARENT_ID} \
        --path-part ${APIGW_PATH_PART}
```

```json:結果(例):
{
    "path": "/mydemoresource", 
    "pathPart": "mydemoresource", 
    "id": "xxxxxx", 
    "parentId": "xxxxxxxxxx"
}
```

## 3.4. 新しいリソースのリソースID取得

```bash:変数の設定:
APIGW_RESOURCE_PATH="${APIGW_RESOURCE_PATH}${APIGW_PATH_PART}" \
  && echo ${APIGW_RESOURCE_PATH}
```

```bash:コマンド:
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}
```

```text:結果(例):
      xxxxxx
```


## 3.5. 新しいリソースの内容確認

```bash:コマンド:
aws apigateway get-resource \
        --rest-api-id ${APIGW_API_ID} \
        --resource-id ${APIGW_RESOURCE_ID}
```

```json:結果(例):
      {
        "path": "/mydemoresource",
        "pathPart": "mydemoresource",
        "id": "xxxxxx",
        "parentId": "xxxxxxxxxx"
      }
```


# 4. Lambda関数の指定

```bash:変数の設定:
APIGW_INTEG_TYPE='AWS'
```


```bash:変数の設定:
APIGW_INTEG_URI="arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${LAMBDA_FUNC_ARN}/invocations" \
  && echo ${APIGW_INTEG_URI}
```

```text:結果(例):
arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName
```

```bash:変数の設定:
APIGW_INTEG_METHOD='POST'
```




# 5. GETメソッドの作成


## 5.1. methodの作成

```bash:変数の設定:
HTTP_METHOD='GET'
AUTH_TYPE='NONE'
```

```bash:変数の確認:
cat << ETX

        APIGW_API_ID:      ${APIGW_API_ID}
        APIGW_RESOURCE_ID: ${APIGW_RESOURCE_ID}
        HTTP_METHOD:       ${HTTP_METHOD}
        AUTH_TYPE:         ${AUTH_TYPE}

ETX
```

```bash:コマンド:
aws apigateway put-method \
        --rest-api-id ${APIGW_API_ID} \
        --resource-id ${APIGW_RESOURCE_ID} \
        --http-method ${HTTP_METHOD} \
        --authorization-type ${AUTH_TYPE}
```

```json:結果(例):
      {
        "apiKeyRequired": false,
        "httpMethod": "GET",
        "authorizationType": "NONE"
      }
```

```bash:コマンド:
aws apigateway get-method \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD}
```


```json:結果(例):
```


## 5.2. integrationの作成


```bash:コマンド:
aws apigateway get-integration \
        --rest-api-id ${APIGW_API_ID} \
        --resource-id ${APIGW_RESOURCE_ID} \
        --http-method ${HTTP_METHOD}
```

```text:結果(例)
A client error (NotFoundException) occurred when calling the GetIntegration operation: No integration defined for method
```


```bash:変数の確認
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
```

```bash:コマンド:
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}
```

```json:結果(例):
{
    "httpMethod": "GET", 
    "type": "AWS", 
    "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName/invocations", 
    "cacheNamespace": "xxxxxx"
}
```


```bash:コマンド:
aws apigateway get-integration \
        --rest-api-id ${APIGW_API_ID} \
        --resource-id ${APIGW_RESOURCE_ID} \
        --http-method ${HTTP_METHOD}
```

```json:結果(例):
{
    "httpMethod": "POST", 
    "cacheKeyParameters": [], 
    "type": "AWS", 
    "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName/invocations", 
    "cacheNamespace": "5toub6"
}
```


## 5.3. Integration Responseの作成

GETメソッドのリザルトコード200でのIntegration Responseが存在作成しないことを確認します。

```bash:変数の設定:
HTTP_STATUS_CODE='200'
```

```bash:コマンド:
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}
```

```text:結果:
A client error (NotFoundException) occurred when calling the GetMethodResponse operation: Invalid Response status code specified
```

GETメソッドのリザルトコード200でのIntegration Responseを作成します。

```bash:変数の確認:
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
```



```bash:コマンド:
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} \
  --response-templates '{"application/json":""}'
```

```json:結果(例):
{
    "statusCode": "200", 
    "responseTemplates": {
        "application/json": null
    }
}
```

GETメソッドのリザルトコード200でのIntegration Responseを確認します。

```bash:コマンド:
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}
```

```json:結果(例):
{
    "statusCode": "200", 
    "responseTemplates": {
        "application/json": null
    }
}
```

GETメソッドのIntegrationにリザルトコード200でのIntegration Responseが存在することを確認します。

```bash:コマンド:
aws apigateway get-integration \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD}
```

```json:結果(例):
{
    "httpMethod": "POST",
    "integrationResponses": {
          "200": {
              "responseTemplates": {
                  "application/json": null
              },
              "statusCode": "200"
          }
    },
    "cacheKeyParameters": [],
    "type": "AWS",
    "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName/invocations",
    "cacheNamespace": "xxxxxx"
}
```



## 5.4. lambda関数の実行権限付与

GETメソッドのリザルトコード200でのIntegration Responseに、Lambda関数を実行する権限を付与します。


Statement IDを乱数32桁で生成します。
(もっとスマートな方法があれば教えてください...)

```bash:変数の設定:
LAMBDA_STAT_ID=$(od -vAn -N16 -tx < /dev/urandom |sed 's/ //g')
```

```bash:変数の設定:
LAMBDA_ACTION='lambda:InvokeFunction'
AWS_PRINCIPAL='apigateway.amazonaws.com'
RESOURCE_PATH="${APIGW_RESOURCE_PATH}"
```

```bash:変数の設定:
SOURCE_ARN="arn:aws:execute-api:${AWS_REGION}:${AWS_ID}:${APIGW_API_ID}/*/${HTTP_METHOD}${RESOURCE_PATH}" \
  && echo ${SOURCE_ARN}
```


```bash:変数の確認:
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
```

```bash:コマンド:
aws lambda add-permission \
   --function-name ${LAMBDA_FUNC_NAME} \
   --statement-id ${LAMBDA_STAT_ID} \
   --action ${LAMBDA_ACTION} \
   --principal ${AWS_PRINCIPAL} \
   --source-arn ${SOURCE_ARN}
```

```json:結果(例):
{
    "Statement": "{\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:ap-northeast-1::xxxxxxxxxx/*/GET/mydemoresource\"}},\"Action\":[\"lambda:InvokeFunction\"],\"Resource\":\"arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Sid\":\"da0d644756f42dd8ccf455176c560b8c\"}"
}
```

```bash:コマンド:
aws lambda get-policy \
  --function-name ${LAMBDA_FUNC_NAME} |\
  sed 's/\\//g' | sed 's/\"{/{/' | sed 's/\"$//' |\
  jq --arg sid ${LAMBDA_STAT_ID} '.Policy.Statement[]|select(.Sid == $sid)'
```

```json:結果(例)
{
  "Condition": {
    "ArnLike": {
      "AWS:SourceArn": "arn:aws:execute-api:ap-northeast-1::xxxxxxxxxx/*/GET/mydemoresource"
    }
  },
  "Action": "lambda:InvokeFunction",
  "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName",
  "Effect": "Allow",
  "Principal": {
    "Service": "apigateway.amazonaws.com"
  },
  "Sid": "da0d644756f42dd8ccf455176c560b8c"
}

```

## 5.5. Method Responseの作成

```bash:コマンド:
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}
```

```text:結果:
A client error (NotFoundException) occurred when calling the GetIntegrationResponse operation: Invalid Response status code specified
```


```bash:コマンド:
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 '{"application/json": "Empty"}'
```


```json:結果(例):
{
  "responseModels": {
    "application/json": "Empty"
  },
  "statusCode": "200"
}
```


```bash:コマンド:
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}
```


```json:結果(例):
{
  "responseModels": {
    "application/json": "Empty"
  },
  "statusCode": "200"
}
```


```bash:コマンド:
aws apigateway get-method \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD}
```


```json:結果(例):
{
    "apiKeyRequired": false, 
    "httpMethod": "GET", 
    "methodIntegration": {
        "integrationResponses": {
            "200": {
                "responseTemplates": {
                    "application/json": null
                }, 
                "statusCode": "200"
            }
        }, 
        "cacheKeyParameters": [], 
        "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName/invocations", 
        "httpMethod": "POST", 
        "cacheNamespace": "xxxxxx", 
        "type": "AWS"
    }, 
    "methodResponses": {
        "200": {
            "responseModels": {
                "application/json": "Empty"
            }, 
            "statusCode": "200"
        }
    }, 
    "authorizationType": "NONE"
}
```



## 5.6. GETメソッドのテスト

```bash:変数の設定:
PATH_WITH_QUERY_STRING=''
```

```bash:変数の確認:
cat << ETX

  APIGW_API_ID:           ${APIGW_API_ID}
  APIGW_RESOURCE_ID:      ${APIGW_RESOURCE_ID}
  HTTP_METHOD:            ${HTTP_METHOD}
  PATH_WITH_QUERY_STRING: "${PATH_WITH_QUERY_STRING}"

ETX
```

```bash:コマンド:
aws apigateway test-invoke-method \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD} \
  --path-with-query-string "${PATH_WITH_QUERY_STRING}"
```


```json:結果(例):
{
    "status": 200, 
    "body": "{\"Hello\":\"No-Name\"}", 
    "log": "Execution log for request test-request\nSun Nov 22 05:19:22 UTC 2015 : Starting execution for request: test-invoke-request\nSun Nov 22 05:19:22 UTC 2015 : API Key: test-invoke-api-key\nSun Nov 22 05:19:22 UTC 2015 : Method request path: {}\nSun Nov 22 05:19:22 UTC 2015 : Method request query string: {}\nSun Nov 22 05:19:22 UTC 2015 : Method request headers: {}\nSun Nov 22 05:19:22 UTC 2015 : Method request body before transformations: null\nSun Nov 22 05:19:22 UTC 2015 : Endpoint request URI: https://lambda.ap-northeast-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName/invocations\nSun Nov 22 05:19:22 UTC 2015 : Endpoint request headers: {Authorization=************************************************************************************************************************************************************************************************************************************619f32, X-Amz-Date=20151122T051922Z, X-Amz-Source-Arn=arn:aws:execute-api:ap-northeast-1:XXXXXXXXXXXX:xxxxxxxxxx/null/GET/mydemoresource, Accept=application/json, User-Agent=AmazonAPIGateway_xxxxxxxxxx, Host=lambda.ap-northeast-1.amazonaws.com}\nSun Nov 22 05:19:22 UTC 2015 : Endpoint request body after transformations: \nSun Nov 22 05:19:22 UTC 2015 : Endpoint response body before transformations: {\"Hello\":\"No-Name\"}\nSun Nov 22 05:19:22 UTC 2015 : Endpoint response headers: {x-amzn-Remapped-Content-Length=0, x-amzn-RequestId=96d204f3-90d8-11e5-8336-4109c0d3fc68, Connection=keep-alive, Content-Length=19, Date=Sun, 22 Nov 2015 05:19:21 GMT, Content-Type=application/json}\nSun Nov 22 05:19:22 UTC 2015 : Method response body after transformations: {\"Hello\":\"No-Name\"}\nSun Nov 22 05:19:22 UTC 2015 : Method response headers: {Content-Type=application/json}\nSun Nov 22 05:19:22 UTC 2015 : Successfully completed execution\n", 
    "latency": 79, 
    "headers": {
        "Content-Type": "application/json"
    }
}
```


# 6. POSTメソッドの作成

## 6.1. methodの作成

```bash:変数の設定:
HTTP_METHOD='POST'
AUTH_TYPE='NONE'
```

```bash:変数の確認:
cat << ETX

  APIGW_API_ID:      ${APIGW_API_ID}
  APIGW_RESOURCE_ID: ${APIGW_RESOURCE_ID}
  HTTP_METHOD:       ${HTTP_METHOD}
  AUTH_TYPE:         ${AUTH_TYPE}

ETX
```


```bash:コマンド:
aws apigateway put-method \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD} \
  --authorization-type ${AUTH_TYPE}
```


```json:結果(例):
{
        "apiKeyRequired": false,
        "httpMethod": "POST",
        "authorizationType": "NONE"
}
```

```bash:コマンド:
aws apigateway get-method \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD}
```


```json:結果(例):
{
    "apiKeyRequired": false, 
    "httpMethod": "POST", 
    "authorizationType": "NONE"
}
```

## 6.2. integrationの作成

```bash:コマンド:
aws apigateway get-integration \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD}
```


```text:結果(例)
A client error (NotFoundException) occurred when calling the GetIntegration operation: No integration defined for method
```



```bash:変数の確認
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
```


```bash:コマンド:
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}
```


```json:結果(例):
{
        "httpMethod": "POST",
        "type": "AWS",
        "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName/invocations",
        "cacheNamespace": "xxxxxx"
}
```

```bash:コマンド:
aws apigateway get-integration \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD}
```

```json:結果(例)
{
    "httpMethod": "POST", 
    "cacheKeyParameters": [], 
    "type": "AWS", 
    "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName/invocations", 
    "cacheNamespace": "xxxxxx"
}
```

## 6.3. Integration Responseの作成

POSTメソッドのリザルトコード200でのIntegration Responseが存在作成しないことを確認します。

```bash:変数の設定:
HTTP_STATUS_CODE='200'
```


```bash:コマンド:
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}
```


```text:結果:
A client error (NotFoundException) occurred when calling the GetMethodResponse operation: Invalid Response status code specified
```

POSTメソッドのリザルトコード200でのIntegration Responseを作成します。

```bash:変数の確認:
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
```


```bash:コマンド:
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} \
  --response-templates '{"application/json":""}'
```


```json:結果(例):
{
        "statusCode": "200",
        "responseTemplates": {
          "application/json": null
        }
}
```

POSTメソッドのリザルトコード200でのIntegration Responseを確認します。


```bash:コマンド:
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}
```


```json:結果(例):
{
        "statusCode": "200",
        "responseTemplates": {
          "application/json": null
        }
}
```


```bash:コマンド:
aws apigateway get-integration \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD}
```


```json:結果(例):
{
        "httpMethod": "POST",
        "integrationResponses": {
          "200": {
              "responseTemplates": {
                  "application/json": null
              },
              "statusCode": "200"
          }
        },
        "cacheKeyParameters": [],
        "type": "AWS",
        "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName/invocations",
        "cacheNamespace": "xxxxxx"
}
```



## 6.4. Lambda関数の実行権限付与

POSTメソッドのリザルトコード200でのIntegration Responseに、Lambda関数を実行する権限を付与します。

Statement IDを乱数32桁で生成します。

```bash:変数の設定:
LAMBDA_STAT_ID=$(od -vAn -N16 -tx < /dev/urandom |sed 's/ //g')
```


```bash:変数の設定
LAMBDA_ACTION='lambda:InvokeFunction'
AWS_PRINCIPAL='apigateway.amazonaws.com'
RESOURCE_PATH="${APIGW_RESOURCE_PATH}"
```

```bash:変数の設定:
SOURCE_ARN="arn:aws:execute-api:${AWS_REGION}:${AWS_ID}:${APIGW_API_ID}/*/${HTTP_METHOD}${RESOURCE_PATH}" \
  && echo ${SOURCE_ARN}
```


```bash:変数の確認:
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
```

```bash:コマンド:
aws lambda add-permission \
  --function-name ${LAMBDA_FUNC_NAME} \
  --statement-id ${LAMBDA_STAT_ID} \
  --action ${LAMBDA_ACTION} \
  --principal ${AWS_PRINCIPAL} \
  --source-arn ${SOURCE_ARN}
```

```json:結果(例):
{
    "Statement": "{\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:ap-northeast-1::1afbnp37t7/*/POST/mydemoresource\"}},\"Action\":[\"lambda:InvokeFunction\"],\"Resource\":\"arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Sid\":\"2555f27b3ed0ee871d38925d7e052e96\"}"
}
```


```bash:コマンド:
aws lambda get-policy \
  --function-name ${LAMBDA_FUNC_NAME} |\
  sed 's/\\//g' | sed 's/\"{/{/' | sed 's/\"$//' |\
  jq --arg sid ${LAMBDA_STAT_ID} '.Policy.Statement[]|select(.Sid == $sid)'
```


```json:結果(例)
{
  "Condition": {
    "ArnLike": {
      "AWS:SourceArn": "arn:aws:execute-api:ap-northeast-1::1afbnp37t7/*/POST/mydemoresource"
    }
  },
  "Action": "lambda:InvokeFunction",
  "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName",
  "Effect": "Allow",
  "Principal": {
    "Service": "apigateway.amazonaws.com"
  },
  "Sid": "2555f27b3ed0ee871d38925d7e052e96"
}
```




## 6.5. Method Responseの作成

```bash:コマンド:
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}
```


```text:結果:
A client error (NotFoundException) occurred when calling the GetIntegrationResponse operation: Invalid Response status code specified
```


```bash:コマンド:
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 '{"application/json": "Empty"}'
```


```json:結果(例):
{
        "responseModels": {
          "application/json": "Empty"
        },
        "statusCode": "200"
}
```


```bash:コマンド:
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}
```


```json:結果(例):
{
        "responseModels": {
          "application/json": "Empty"
        },
        "statusCode": "200"
}
```


```bash:コマンド:
aws apigateway get-method \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD}
```


```json:結果(例):
      {
        "apiKeyRequired": false,
        "httpMethod": "POST",
        "methodIntegration": {
          "integrationResponses": {
              "200": {
                  "responseTemplates": {
                      "application/json": null
                  },
                  "statusCode": "200"
              }
          },
          "cacheKeyParameters": [],
          "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:GetHelloWithName/invocations",
          "httpMethod": "POST",
          "cacheNamespace": "xxxxxx",
          "type": "AWS"
        },
        "methodResponses": {
          "200": {
              "responseModels": {
                  "application/json": "Empty"
              },
              "statusCode": "200"
          }
        },
        "authorizationType": "NONE"
      }
```




## 6.6. POSTメソッドのテスト (bodyなし)

```bash:変数の確認
cat << ETX

  APIGW_API_ID:      ${APIGW_API_ID}
  APIGW_RESOURCE_ID: ${APIGW_RESOURCE_ID}
  HTTP_METHOD:       ${HTTP_METHOD}

ETX
```

```bash:コマンド:
aws apigateway test-invoke-method \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD} \
  --path-with-query-string '' \
  --query 'body' |\
  sed 's/\\//g' | sed 's/^\"//g' | sed 's/\"$//' |\
  jq .
```

```json:結果(例):
{
  "Hello": "No-Name"
}
```

## 6.6. POSTメソッドのテスト (bodyあり)

```bash:変数の確認
cat << ETX

  APIGW_API_ID:      ${APIGW_API_ID}
  APIGW_RESOURCE_ID: ${APIGW_RESOURCE_ID}
  HTTP_METHOD:       ${HTTP_METHOD}

ETX
```

```bash:コマンド:
aws apigateway test-invoke-method \
  --rest-api-id ${APIGW_API_ID} \
  --resource-id ${APIGW_RESOURCE_ID} \
  --http-method ${HTTP_METHOD} \
  --path-with-query-string '' \
  --body '{"name": "User"}' \
  --query 'body' |\
  sed 's/\\//g' | sed 's/^\"//g' | sed 's/\"$//' |\
  jq .
```

```json:結果(例):
{
  "Hello": "User"
}
```


# 7. APIのデプロイ

## 7.1. APIのデプロイ

```bash:コマンド:
aws apigateway get-deployments \
  --rest-api-id ${APIGW_API_ID}
```


```text:結果:
{
          "items": []
}
```



```bash:変数の設定:
APIGW_STAGE_NAME='test'
APIGW_STAGE_DESC='This is a test.'
APIGW_DEPLOY_DESC='Calling Lambda functions walkthrough.'
```


```bash:変数の確認:
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
```


```bash:コマンド:
aws apigateway create-deployment \
  --rest-api-id ${APIGW_API_ID} \
  --stage-name ${APIGW_STAGE_NAME} \
  --stage-description "${APIGW_STAGE_DESC}" \
  --description "${APIGW_DEPLOY_DESC}"
```


```json:結果(例):
{
        "description": "Calling Lambda functions walkthrough.",
        "id": "n5ston",
        "createdDate": 1448115971
}
```


```bash:コマンド:
aws apigateway get-deployments \
  --rest-api-id ${APIGW_API_ID}
```


```json:結果(例):
{
        "items": [
          {
              "createdDate": 1448115971,
              "id": "xxxxxx",
              "description": "Calling Lambda functions walkthrough."
          }
        ]
}
```

## 7.2. API IDの取得

```bash:コマンド:
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}
```


```text:結果(例)
xxxxxx
```


## 7.3. APIの情報の取得

```bash:コマンド:
aws apigateway get-deployment \
  --rest-api-id ${APIGW_API_ID} \
  --deployment-id ${APIGW_DEPLOY_ID}
```


```json:結果(例):
{
        "description": "Calling Lambda functions walkthrough.",
        "id": "xxxxxx",
        "createdDate": 1448115971
}
```


## 7.4. APIのステージ名の取得

```bash:コマンド:
aws apigateway get-stages \
  --rest-api-id ${APIGW_API_ID}
```


```json:結果(例):
{
        "item": [
          {
              "description": "This is a test.",
              "stageName": "test",
              "cacheClusterEnabled": false,
              "cacheClusterStatus": "NOT_AVAILABLE",
              "deploymentId": "xxxxxx",
              "lastUpdatedDate": 1448115971,
              "createdDate": 1448115971,
              "methodSettings": {}
          }
        ]
}
```


```bash:コマンド:
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}
```


```json:結果(例):
{
        "item": [
          {
              "description": "This is a test.",
              "stageName": "test",
              "cacheClusterEnabled": false,
              "cacheClusterStatus": "NOT_AVAILABLE",
              "deploymentId": "xxxxxx",
              "lastUpdatedDate": 1448115971,
              "createdDate": 1448115971,
              "methodSettings": {}
          }
        ]
}
```


```bash:コマンド:
aws apigateway get-stage \
  --rest-api-id ${APIGW_API_ID} \
  --stage-name ${APIGW_STAGE_NAME}
```


```json:結果(例):
{
        "stageName": "test",
        "description": "This is a test.",
        "cacheClusterEnabled": false,
        "cacheClusterStatus": "NOT_AVAILABLE",
        "deploymentId": "xxxxxx",
        "lastUpdatedDate": 1448115971,
        "createdDate": 1448115971,
        "methodSettings": {}
}
```



# 8 .APIのテスト

## 8.1. GETメソッドのテスト (ブラウザ)

```bash:変数の設定:
APIGW_URI="https://${APIGW_API_ID}.execute-api.${AWS_REGION}.amazonaws.com/${APIGW_STAGE_NAME}${APIGW_RESOURCE_PATH}" \
  && echo ${APIGW_URI}
```

表示されたURLをブラウザで開いて、以下のJSONファイルが表示されればOKです。

```json:ブラウザ表示の結果:
{"Hello":"No-Name"}
```

## 8.2. POSTメソッドのテスト (curlコマンド)

```bash:コマンド:
curl \
  -H "Content-Type: application/json" \
  -X POST -d "{\"name\": \"User\"}" \
  ${APIGW_URI}
```

```json:結果(例):
{"Hello":"User"}
```



# 完了