LocalStack でAWSのサービスを試してみる

##概要

LocalStackとは・・・提供しているGithubによると以下のようなものです。 

[LocalStack - Github](https://github.com/localstack/localstack)
>LocalStackは、クラウドアプリケーションを開発するための使いやすいテスト/モッキングフレームワークを提供する。
>現在、主にAWSクラウドスタックのサポートに注力している。

AWSのサービスを個人で実際に使う前に試してみたいと常々思っていたのですが、これを使えばAWSのテスト環境を構築できそうです。
今回はAPI GatewayとLambdaを使って簡易APIを作ってみようと思います。

##実行環境

macOS Mojave 10.4.4
Docker version 18.09.2

##手順

###AWS CLI のインストール

下記のコマンドでAWSをコマンドラインから操作する AWS CLI をインストールします。

```
$ pip install awscli
```

###AWS CLI - Credentialの設定

AWSをCLIから使うにはCredentialが必要になるが、LocalStackではダミー値を入力します。

```
$ aws configure --profile localstack
AWS Access Key ID [None]: dummy
AWS Secret Access Key [None]: dummy
Default region name [None]: us-east-1
Default output format [None]: json

$ tree .aws
.aws
├── config
└── credentials
```

このままでもいいのですが、しばらくはAWSサービスはLocalStackしか使わないので、今作成した値をデフォルト値としてcredentialとconfigに設定しました。設定しない場合はオプションで毎回指定する必要があります。

```:~/.aws/credentials
[localstack]
aws_access_key_id = dummy
aws_secret_access_key = dummy

[default]
aws_access_key_id = dummy
aws_secret_access_key = dummy

```


```:~/.aws/config                                                                                      
[profile localstack]
region = us-east-1
output = json

[default]
region = us-east-1
output = json
```



### LocalStackをGithubからクローン

```
$ git clone https://github.com/atlassian/localstack.git
```

### LocalStack起動

```
$ docker-compose up
```

これでdocker上にサーバが立ち上がります。
**※私はMacで試しているのですが、このコマンドではエラーになりました。対策は別の記事で書くのでそちらを参照してください。**
→[localstack がエラーで起動できない](https://qiita.com/libra_lt/items/2e53ea1b523f8f9e089b)

立ち上げるといろいろなサービスがローカル上に構築されています。詳しくはこちら↓
https://github.com/localstack/localstack#overview

### Lambdaの作成

API Gatewayを通して呼び出されるLambda Functionを作成します。

下記のPythonファイルをzipにして、アップロードします。

```:api_practice.py
import json

def lambda_handler(event, context):
    return response({'message': 'Hello LocalStack!!'}, 200)

def response(message, status_code):
    return {
        'statusCode': str(status_code),
        'body': json.dumps(message),
        'headers': {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*'
            },
        }
```

Lambda作成コマンドを実行
※Roleを指定していますが、ダミー値でいいようです。適当に入力します。

```
$ aws lambda create-function \
--function-name api_practice_handler \
--runtime python3.7 \
--handler api_practice.lambda_handler \
--memory-size 128 \
--zip-file fileb://api_practice.zip \
--role arn:aws:iam::123456:role/role-name \
--endpoint-url=http://localhost:4574
```

Lambdaについてはここまでです。


### API Gateway - REST API を作成

まず適当な名前のREST API を作成します。

```
$ aws apigateway create-rest-api --name 'API Test' --endpoint-url=http://localhost:4567
{
    "id": "7979083004",
    "name": "API Test",
    "createdDate": "2019-06-29T06:40:44.481Z"
}
```

REST API のルートリソースIDを取得する。
 
```
aws apigateway get-resources --rest-api-id 7979083004 --endpoint-url=http://localhost:4567
{
    "items": [
        {
            "id": "A-Z259839A-Z48",
            "path": "/",
            "resourceMethods": {
                "GET": {}
            }
        }
    ]
}
```

ルート配下に子リソースを追加する。
今回は/helloでアクセスできるように作ってみます。

```
$ aws apigateway create-resource --rest-api-id 7979083004 \  
--parent-id A-Z259839A-Z48 \
--path-part hello \
--endpoint-url=http://localhost:4567
{
    "id": "925142460A-Z",
    "parentId": "A-Z259839A-Z48",
    "pathPart": "hello",
    "path": "/hello",
    "resourceMethods": {
        "GET": {}
    }
}
```

作成したリソースを以下のコマンドを実行し、GETメソッドで参照できるようにします。

```
$ aws apigateway put-method \
 --rest-api-id 7979083004 \
 --resource-id 925142460A-Z \
 --http-method GET \
 --authorization-type "NONE" \
 --endpoint-url=http://localhost:4567
{
    "httpMethod": "GET",
    "authorizationType": "NONE"
}
```

###API Gateway - Lambda の設定

LambdaのARNを使うため、下記のコマンドを実行し確認する。

```
$ aws lambda list-functions --endpoint-url=http://localhost:4574
{
    "Functions": [
        {
            "FunctionName": "api_practice_handler",
            "FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:api_practice_handler",
            "Runtime": "python3.7",
            "Handler": "api_practice.lambda_handler",
            "Timeout": 60,
            "Version": "$LATEST"
        }
    ]
}
```

#### API Gateway と Lambda の設定

```
$ aws apigateway put-integration \
 --rest-api-id 7979083004 \
 --resource-id 925142460A-Z \
 --http-method GET \
 --type AWS_PROXY \
 --integration-http-method POST \
 --uri arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:000000000000:function:api_practice_handler/invocations \
 --passthrough-behavior WHEN_NO_MATCH \
 --endpoint-url=http://localhost:4567
{
    "type": "AWS_PROXY",
    "httpMethod": "GET",
    "uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:000000000000:function:api_practice_handler/invocations",
    "integrationResponses": {
        "200": {
            "statusCode": 200,
            "responseTemplates": {
                "application/json": null
            }
        }
    }
}
```

#### デプロイ
ここまでの設定をデプロイする。これで最後です。

```
$ aws apigateway create-deployment \
 --rest-api-id 7979083004 \
 --stage-name test \
 --endpoint-url=http://localhost:4567
{
    "id": "6164761A-Z90",
    "description": "",
    "createdDate": "2019-06-29T11:07:13.214Z"
}
```

####確認コマンド
長かったですが、最後に公開されているか確認しましょう。


```
$ curl http://localhost:4567/restapis/7979083004/test/_user_request_/hello
{"body": "{\"message\": \"Hello LocalStack!!\"}", "headers": {"Access-Control-Allow-Origin": "*", "Content-Type": "application/json"}, "statusCode": "200"}
```

レスポンスもちゃんと返ってきました！

##終わりに

今回、LocalStackというサービスでAWSのサービスを疑似体験できることがわかりました。実際の業務ではAWSを使っているので、利用方法も同じなのでサービスを試すのにはとてもよさそう！


##参考
https://stackoverflow.com/questions/44547574/create-api-gateway-in-localstack/48682628