AWS ChaliceでS3に画像をアップロードしてみた

## はじめに
「自分のAWSアカウント作成してlambdaの勉強してみよう！」と思っていたところ、lambdaやAPI Gatewayなどの設定やら何やらでかなり苦労し挫折しかけていました。。。そんな時に「AWS Chalice」というかなり便利なフレームワークがあることを知り、希望が見えてきました!!!
もし、私と同じような状況の方がの記事を読んでいただけると嬉しいです！！！
## AWS Chaliceとは
Amazon API Gateway と AWS Lambda による API 環境を実現してくれる、 AWS 製のサーバーレスアプリケーションのフレームワークのこと。
一応以下に、LambdaとAPI Gatewayについても記載します。
#### AWS Lambda
- クラウド上にプログラムを定義し、インターネットを通じて実行できるサービス
- サーバーやミドルウェアの管理はAWSが行ってくれるので、プログラムのことだけを考えれば良いというサービス
#### AWS API Gateway
- あらゆる規模の REST、HTTP、および WebSocket API を作成、公開、維持、モニタリング、およびセキュア化するための AWS のサービス
- HTTPベースで、標準のHTTTPメソッドを実装し、ステートレスなクライアント/サーバー通信を有効にするRestfulなAPIを作成するサービス

## Chaliceのインストール
今回はローカル環境にpythonの仮想環境を作成し、Chaliceをインストールしました。
```bash
$ python3 --version
Python 3.9.7
$ python3 -m venv venv37
$ . venv37/bin/activate
$ python3 -m pip install chalice
$ chalice new-project chalice-sample
$ cd chalice-sample
# デプロイ時に設定が必要なため
$ aws configure
```
S3にテスト用のバケットを作成しておいてください。
これでChaliceの開発環境の構築は完了です。

## S3に画像をアップロードする実装
実装についての説明はソース中にコメント記載してあるため割愛します。
```python:app.py
import boto3
import os
import io
import cgi
from chalice import Chalice
from dotenv import load_dotenv
load_dotenv()

app = Chalice(app_name='chalice-sample')
app.debug = True
# s3関連設定
s3 = boto3.client('s3', region_name='ap-northeast-1')
BUCKET_NAME = os.getenv('BUCKET_NAME')

# test
@app.route('/')
def index():
    return {'hello': 'world'}

# API Gateway に multipart/form-data をバイナリとして扱うように指示する設定 
app.api.binary_types.append('multipart/form-data')

@app.route('/upload',methods=['POST'],content_types=['multipart/form-data'],cors=True)
def upload_file():
    # HTTPのボディをバイナリとして受け取る。
    body_to_binary = io.BytesIO(app.current_request.raw_body)

    # form解析
    environ = {'REQUEST_METHOD': 'POST'}
    headers = {'content-type': app.current_request.headers['content-type']}
    """
    - cgi.FieldStorageの引数の説明
     - fp : file pointerのことでボディ本体を表す。io.BytesIO(）で読み込む必要あり。
     - environ : メソッドの操作
     - headers : リクエストで受け取ったヘッダー
    """
    form = cgi.FieldStorage(fp=body_to_binary, environ=environ, headers=headers)
    if len(form.list) > 0:
        try:
            for f in form.list:
                print("filename=",f.filename)
                s3.put_object(Bucket=BUCKET_NAME,Key=f.filename,Body=f.value)
                return {
                    'statusCode': 200,
                    'body': 'アップロード完了'
                }
        except:
            return {
                'statusCode': 500,
                'body': 'システム内部エラー発生'
            }

    else:
        return {
            'statusCode': 202,
            'body': 'アップロードするファイルを選択してください。'
        }
```

## ファイルアップロードできるか試してみよう
まずは、Chaliceをローカルで動かす。
```bash
$ chalice local

Found credentials in shared credentials file: ~/.aws/credentials
Serving on http://127.0.0.1:8000
```
あとはGoogleの拡張機能であるTalend API Tasterを使ってテストしてみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699848/947d75d2-53f7-c367-47a2-e645aab1a0e8.png)

アップロードが完了していることがわかる。S3の方はどうなっているかというと、、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699848/de774cc2-895f-24eb-b9eb-5023a83a159c.png)

無事アップロードできていますね！よかった！

## アプリをデプロイしてみよう
```bash
$ chalice deploy
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699848/491818c3-2117-06b7-3959-e2898019ed5d.png)
無事、lambda関数とAPI Gatewayがデプロイされていることが分かります！

## 最後に
最後まで読んでいただき、ありがとうございます！今回はAWS ChaliceでS3に画像をアップロードしてみました。ChaliceがなかったらlambdaやAPI Gatewayの設定で挫折してここまで辿り着けなかったと思います。本当に助かった、、、、笑
まだまだAWSのことはわからないことだらけですが、せっかく自分のアカウントも作成したのでこれからどんどん勉強して色々な記事を投稿できたらなと思います。