爆速API構築〜chalice編〜

爆速でAPIをリリースしたい方へ送ります

https://github.com/awslabs/chalice

# chaliceとは

聖杯の名を冠するこのchaliceはフレームワークというよりはツールで、アプリケーションコードさえあれば、AWS Lambda、AWS APIGateway、IAMRoleなどの設定をよしなにやって、AWS上にデプロイをキメてくれるという活かしたシロモノです。これにより爆速でAPIを構築して、プロダクションリリースを実現します。

# まずはじめに

兎にも角にもAWSのサービスをフルフル使ってAPI構築していきますので、credentialの設定をまずはじめに行っておく必要があります。

```
$ mkdir ~/.aws
$ cat >> ~/.aws/config
[default]
aws_access_key_id=YOUR_ACCESS_KEY_HERE
aws_secret_access_key=YOUR_SECRET_ACCESS_KEY
region=ap-northeast-1
```

複数のAWSアカウントを切り替えてお使いの方は、[direnv](https://github.com/direnv/direnv)などで環境変数にてACCESSKEYを設定しておくことをオススメいたします。SDKによりますが、今回使うboto3に関してはAWSCliとコンパチな感じの優先度でcredentialや環境変数の読んでいるっぽいので、[ここらへん](http://dev.classmethod.jp/cloud/aws/how-to-configure-aws-cli/)の記事を参照されると幸せになれるかもしれません。

# プロジェクト作成からのデプロイキメる方法

下記のようにコマンドラインにぶち込んでみましょう

```
$ pip install chalice
$ chalice new-project helloworld && cd helloworld
Initial creation of lambda function.
Creating role
Creating deployment package.
Lambda deploy done.
Initiating first time deployment...
Deploying to: dev
https://endpoint/dev/

$ curl https://endpoint/dev
{"hello": "world"}
```

上記の一連の作業は、プロジェクトを新規作成後、すぐデプロイをしています。
`chalice deploy` という魔法の一言で、プロジェクトを　`AWS Lambda` にデプロイして、 `AWS API Gateway` と `AWS Lambda` の紐付けをよしなにやってパブリックにアクセス可能な状態にデプロイしてくれるのです。

APIの内容をごちゃごちゃしたい場合は、 新規作成時に作成される　`app.py` の中身を本能のままにいじっていきましょう

# S3にログを吐き出すAPIを作る方法

自分の周りだととりあえずログを溜めておくAPIが欲しい、みたいな要件が多いです
とりあえずS3にJSONで保存しておいて後でサルベージするなりなんなり、というケースが多々あります
特に今は[AWS Athena](https://aws.amazon.com/jp/blogs/news/amazon-athena-interactive-sql-queries-for-data-in-amazon-s3/)でJSONの集計が対話的にできたりみたいな事があったりしてことさらその要件でのお話を頂くことが多いです

ではAPIにJSONをPOSTするとその形式でJSONをS3に書いてくれるようなAPIを作成してみましょう

まずS3上にbucketを作っておきましょう(これは手動で作業が必要です)
そしてAWSSDKをinstallしましょう

```
$ pip install boto3
```

`app.py` を下記のように書き換えてみましょう

```python:app.py
from chalice import Chalice

app = Chalice(app_name='helloworld')
import json
import boto3
from botocore.exceptions import ClientError

from chalice import NotFoundError

S3 = boto3.client('s3', region_name='ap-northeast-1')
BUCKET = 'your-bucket-name'

@app.route('/objects/{key}', methods=['GET', 'PUT'])
def s3objects(key):
    request = app.current_request
    if request.method == 'PUT':
        S3.put_object(Bucket=BUCKET, Key=key,
                      Body=json.dumps(request.json_body))
    elif request.method == 'GET':
        try:
            response = S3.get_object(Bucket=BUCKET, Key=key)
            return json.loads(response['Body'].read())
        except ClientError as e:
            raise NotFoundError(key)
```

書き換えたらデプロイしてみましょう

```
$ chalice deploy
Updating IAM policy.

The following actions will be added to the execution policy:

s3:GetObject
s3:PutObject

Would you like to continue?  [Y/n]: Y
Updating lambda function...
Regen deployment package...
Sending changes to lambda.
Lambda deploy done.
API Gateway rest API already found.
Deleting root resource id
Done deleting existing resources.
Deploying to: dev
https://endpoint/dev/
```

サラッとYを入力してデプロイしてしまいましたが、実はここでIAMRoleの設定を `chalice` がよしなにやってくれています
詳しく説明すると、デプロイ時にデプロイ対象のソースコードをパースして、必要な権限を割り出して、その権限、つまり下記の二つの権限を設定しても良いか聞いてくれています

- s3:GetObject
- s3:PutObject

そしてその権限をIAMに設定して、LambdaからS3へアクセスできるような状態でデプロイをキメてくれます
つまりアプリケーション構築する人間はIAMの設定を意識することなく、IAMの設定がなされた上でデプロイされます

なんて~~恐ろしい~~素晴らしい気の利かせ方でしょうか！！
IAMの設定はすごいめんどくさいですし、えーいAdminつけとけみたいな話にもなりかねないので、自動で適切に設定してくれるとなると嬉しい限りです

# 補足〜健康的なPythonでの開発のために〜

Pythonは2.X系と3.X系の乖離があり世界に深い悲しみがあります
AWS Lambda上のPythonは2.7系なので3.X系と違います
そのため、手元の環境を合わせた方が良い、というケースが多々生じます

そんな深い悲しみから決別するために手元の開発環境を任意の環境に切り替えるために
[pyenv](https://github.com/pyenv/pyenv)を入れておきましょう