GitHubじゃ!Pythonじゃ!

GitHubからPython関係の優良リポジトリを探したかったのじゃー、でも英語は出来ないから日本語で読むのじゃー、英語社会世知辛いのじゃー

aws

chalice – Python Serverlessマイクロフレームワークfor AWS

投稿日:

Python Serverlessマイクロフレームワークfor AWS

Python Serverlessマイクロフレームワークfor AWS

Chaliceは、AWS用のPythonサーバーレスマイクロフレームワークです。 Amazon API GatewayとAWS Lambdaを使用するアプリケーションをすばやく作成して展開できます。 それは提供する:

  • アプリケーションの作成、配備、および管理を行うためのコマンドラインツール
  • Pythonコードでビューを宣言するための使い慣れた使いやすいAPI
  • 自動IAMポリシーの生成
$ pip install chalice
$ chalice new-project helloworld && cd helloworld
$ cat app.py

from chalice import Chalice

app = Chalice(app_name="helloworld")

@app.route("/")
def index():
    return {"hello": "world"}

$ chalice deploy
...
https://endpoint/dev

$ curl https://endpoint/api
{"hello": "world"}

30秒以内に起動して実行できます。

このプロジェクトを試してみて、Githubのあなたの意見をここで共有してください。

マニュアルは読書台で入手できます。

クイックスタート

このチュートリアルでは、 chaliceコマンドラインユーティリティを使用して、基本的なREST APIを作成してデプロイします。 まず、 chaliceをインストールする必要があります。 virtualenvの使用をお勧めします:

$ pip install virtualenv
$ virtualenv ~/.virtualenvs/chalice-demo
$ source ~/.virtualenvs/chalice-demo/bin/activate

注: python2.7またはpython3.6を使用していることを確認してください chalice CLIとchalice pythonパッケージは、AWS LambdaがサポートするPythonのバージョンをサポートします。 現在、AWS Lambdaはpython2.7とpython3.6をサポートしているので、このプロジェクトがサポートしています。 以下を実行することで、python3.6でvirtualenvを作成していることを保証することができます:

# Double check you have python3.6
$ which python3.6
/usr/local/bin/python3.6
$ virtualenv --python $(which python3.6) ~/.virtualenvs/chalice-demo
$ source ~/.virtualenvs/chalice-demo/bin/activate

次に、あなたのvirtualenvに、chaliceをインストールします:

$ pip install chalice

次のコマンドを実行して、あなたが魔法使いをインストールしていることを確認できます。

$ chalice --help
Usage: chalice [OPTIONS] COMMAND [ARGS]...
...

資格情報

アプリケーションを展開する前に、資格情報が設定されていることを確認してください。 以前にboto3(AWS SDK for Python)またはAWS CLIを実行するようにマシンを設定している場合は、このセクションをスキップできます。

AWSの資格情報を初めて設定する場合は、次の手順を実行してすぐに開始できます。

$ mkdir ~/.aws
$ cat >> ~/.aws/config
[default]
aws_access_key_id=YOUR_ACCESS_KEY_HERE
aws_secret_access_key=YOUR_SECRET_ACCESS_KEY
region=YOUR_REGION (such as us-west-2, us-west-1, etc)

資格情報を設定するためにサポートされているすべての方法の詳細については、 boto3のドキュメントを参照してください。

プロジェクトの作成

次は、 chaliceコマンドを使って新しいプロジェクトを作成します。

$ chalice new-project helloworld

helloworldディレクトリが作成されます。 Cdをこのディレクトリにコピーします。 いくつかのファイルが作成されています:

$ cd helloworld
$ ls -la
drwxr-xr-x   .chalice
-rw-r--r--   app.py
-rw-r--r--   requirements.txt

ここでは.chaliceディレクトリを無視することができrequirements.txtapp.pyでは主に2つの主なファイルはapp.pyrequirements.txt

app.pyファイルを見てみましょう:

from chalice import Chalice

app = Chalice(app_name='helloworld')


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

new-projectコマンドは、呼び出されたときにJSON本体{"hello": "world"}を返す単一のビュー/を定義するサンプルアプリケーションを作成しました。

展開

このアプリを展開しよう。 あなたがhelloworldディレクトリにいて、 chalice deployを実行していることを確認してhelloworld

$ chalice deploy
...
Initiating first time deployment...
https://qxea58oupc.execute-api.us-west-2.amazonaws.com/api/

API GatewayとLambdaを使用してAPIを起動して実行するようになりました。

$ curl https://qxea58oupc.execute-api.us-west-2.amazonaws.com/api/
{"hello": "world"}

index()関数から返された辞書に変更を加えてみてください。 chalice deploy実行して、変更を再chalice deployます。

これらのチュートリアルの残りの部分では、 curlhttps://github.com/jakubroztocil/httpie )の代わりにhttpieを使用してAPIをテストします。 あなたはpip install httpie install httpieを使ってhttpieをインストールすることができます。あるいは、Macならbrew install httpie実行brew install httpieことができます。 Githubのリンクには、インストール手順の詳細があります。 次に、 httpieを使用して、作成したばかりのAPIのルートリソースをリクエストする例をhttpieます。 コマンド名はhttp

$ http https://qxea58oupc.execute-api.us-west-2.amazonaws.com/api/
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 18
Content-Type: application/json
Date: Mon, 30 May 2016 17:55:50 GMT
X-Cache: Miss from cloudfront

{
    "hello": "world"
}

さらに、簡潔さのため、APIゲートウェイのエンドポイントはhttps://endpoint/api/に短縮されhttps://endpoint/api/ APIをデプロイするときにhttps://abcdefg.execute-api.us-west-2.amazonaws.com/api/ CLIが表示する実際のエンドポイントには、 https://abcdefg.execute-api.us-west-2.amazonaws.com/api/ように見えるhttps://endpoint/api/を代用してくださいhttps://abcdefg.execute-api.us-west-2.amazonaws.com/api/

次のステップ

あなたは今、 chaliceを使って最初のアプリを作成しました。

次のいくつかのセクションでは、このクイックスタートセクションを基に、URLパラメータのキャプチャ、エラー処理、高度なルーティング、現在の要求メタデータ、自動ポリシー生成などの追加機能について説明します。

チュートリアル:URLパラメータ

今度は、 app.pyファイルを少し変更して、AWSのpython app.py提供する追加の機能をapp.pyます。

これまでのアプリケーションでは、 /へのHTTP GET要求を行うことができる単一のビューがあります。 次に、URIの一部を取得するとします。

from chalice import Chalice

app = Chalice(app_name='helloworld')

CITIES_TO_STATE = {
    'seattle': 'WA',
    'portland': 'OR',
}


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

@app.route('/cities/{city}')
def state_of_city(city):
    return {'state': CITIES_TO_STATE[city]}

上記の例では、ユーザーが都市名を指定できるstate_of_cityビューを追加しました。 ビュー関数は都市名をとり、都市がある州の名前を返します。 @app.routeデコレータのURLパターンは/cities/{city}です。 つまり、 {city}値が取得され、ビュー関数に渡されます。 state_of_cityが単一の引数を取ることもわかります。 この引数は、ユーザーが提供する都市の名前です。 例えば:

GET /cities/seattle   --> state_of_city('seattle')
GET /cities/portland  --> state_of_city('portland')

app.pyファイルをこの新しいビュー関数で更新したapp.py 、アプリケーションを再デプロイしましょう。 helloworldディレクトリからchalice deployを実行すると、アプリケーションが展開されます:

$ chalice deploy

それを試してみましょう。 以下の例では、 httpieパッケージのhttpコマンドを使用しています。 これをインストールするには、 pip install httpie

$ http https://endpoint/api/cities/seattle
HTTP/1.1 200 OK

{
    "state": "WA"
}

$ http https://endpoint/api/cities/portland
HTTP/1.1 200 OK

{
    "state": "OR"
}

CITIES_TO_STATEマップにない都市をリクエストしようとするとどうなりますか?

$ http https://endpoint/api/cities/vancouver
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
X-Cache: Error from cloudfront

{
    "Code": "ChaliceViewError",
    "Message": "ChaliceViewError: An internal server error occurred."
}

次のセクションでは、これを修正し、より良いエラーメッセージを提供する方法を見ていきます。

チュートリアル:エラーメッセージ

上記の例では、アプリケーションがキャッチされない例外を発生させたときに500の内部サーバーエラーが返されたことがわかります。

このセクションでは、これらのエラーメッセージをデバッグして改善する方法を示します。

まず最初に、この問題をデバッグする方法を見ていきます。 デフォルトでは、デバッグはオフになっていますが、詳細情報を得るためにデバッグを有効にすることができます。

from chalice import Chalice

app = Chalice(app_name='helloworld')
app.debug = True

app.debug = Trueを指定すると、アプリのデバッグが可能になります。 このファイルを保存して、変更を再デプロイします。

$ chalice deploy
...
https://endpoint/api/

ここで、内部サーバーエラーを返した同じURLを要求すると、元のスタックトレースが返されます。

$ http https://endpoint/api/cities/vancouver
Traceback (most recent call last):
  File "/var/task/chalice/app.py", line 304, in _get_view_function_response
    response = view_function(*function_args)
  File "/var/task/app.py", line 18, in state_of_city
    return {'state': CITIES_TO_STATE[city]}
KeyError: u'vancouver'

このエラーは、 vancouverキーにアクセスしようとした結果、キャッチされていないKeyErrorが原因であることがわかります。

エラーが分かったので、コードを修正することができます。 私たちがやりたいことは、この例外をキャッチし、代わりにユーザーにもっと役に立つエラーメッセージを返すことです。 更新されたコードは次のとおりです。

from chalice import BadRequestError

@app.route('/cities/{city}')
def state_of_city(city):
    try:
        return {'state': CITIES_TO_STATE[city]}
    except KeyError:
        raise BadRequestError("Unknown city '%s', valid choices are: %s" % (
            city, ', '.join(CITIES_TO_STATE.keys())))

これらの変更を保存して展開します。

$ chalice deploy
$ http https://endpoint/api/cities/vancouver
HTTP/1.1 400 Bad Request

{
    "Code": "BadRequestError",
    "Message": "Unknown city 'vancouver', valid choices are: portland, seattle"
}

BadRequestErrorに渡した値であるCodeMessageキーを受け取ったことがBadRequestError ビュー関数からBadRequestErrorを呼び出すと、フレームワークはHTTPステータスコード400とCodeMessageを含むJSON本体を返します。 Pythonコードからいくつか例外を追加することができます:

* BadRequestError - return a status code of 400
* UnauthorizedError - return a status code of 401
* ForbiddenError - return a status code of 403
* NotFoundError - return a status code of 404
* ConflictError - return a status code of 409
* UnprocessableEntityError - return a status code of 422
* TooManyRequestsError - return a status code of 429
* ChaliceViewError - return a status code of 500

これらは、 chaliceパッケージから直接インポートできます。

from chalice import UnauthorizedError

チュートリアル:追加ルーティング

これまでの例では、GET要求のみが許可されています。 実際には、追加のHTTPメソッドをサポートすることは可能です。 次に、PUTをサポートするビュー関数の例を示します。

@app.route('/resource/{value}', methods=['PUT'])
def put_test(value):
    return {"value": value}

httpコマンドを使用してこのメ​​ソッドをテストできます。

$ http PUT https://endpoint/api/resource/foo
HTTP/1.1 200 OK

{
    "value": "foo"
}

methods kwargはmethodsのリストを受け入れることに注意してください。 特定のHTTPメソッドが指定されたリソースに使用されると、ビュー関数が呼び出されます。 例えば:

@app.route('/myview', methods=['POST', 'PUT'])
def myview():
    pass

上記のビュー関数は、HTTP POSTまたはPUTのいずれかが/myview送られたときに呼び出されます。

また、同じルートURLに対して複数のHTTPメソッド間で同じビュー関数を共有したくない場合は、同じルートURLに対して別々のビュー関数を定義できますが、ビューの機能はHTTPメソッドによって異なります。 例えば:

@app.route('/myview', methods=['POST'])
def myview_post():
    pass

@app.route('/myview', methods=['PUT'])
def myview_put():
    pass

この設定では、すべてのHTTP POSTの/myview myview_post()ビュー関数にルーティングし、すべてのHTTP PUTを/myview myview_put()ビュー関数にmyview_put()ます。 また、ビュー関数には一意の名前が必要であることに注意することも重要です。 たとえば、両方のビュー関数にmyview()という名前をmyview()ことはできません。

次のセクションでは、さまざまなHTTPメソッドを区別するために、指定された要求をイントロスペクションする方法について説明します。

チュートリアル:メタデータの要求

上記の例では、HTTP PUT要求をサポートするビュー関数を作成する方法と、同じビュー関数を介してPOSTとPUTの両方をサポートするビュー関数を作成する方法を説明しました。 しかし、特定のリクエストについてもっと必要な情報があります:

  • PUT / POSTでは、リクエスト本体を頻繁に送信します。 リクエストボディの内容にアクセスするには、何らかの方法が必要です。
  • 複数のHTTPメソッドをサポートするビュー関数では、どのHTTPメソッドが使用されたかを検出して、PUTとPOSTのコードパスを異ならせることができます。

これ以上のことは、 chaliceライブラリが呼び出されたときに各ビュー関数が利用できるようにする現在のリクエストオブジェクトによって処理されます。

これの例を見てみましょう。 オブジェクトにデータをPUTし、対応するGETを介してそのデータを取得できるビュー関数を作成するとします。 次のビュー関数を使用してこれを達成できます。

from chalice import NotFoundError

OBJECTS = {
}

@app.route('/objects/{key}', methods=['GET', 'PUT'])
def myobject(key):
    request = app.current_request
    if request.method == 'PUT':
        OBJECTS[key] = request.json_body
    elif request.method == 'GET':
        try:
            return {key: OBJECTS[key]}
        except KeyError:
            raise NotFoundError(key)

これをapp.pyファイルに保存し、 app.py chalice deployを再実行してください。 今度は、リクエスト本体で/objects/your-key PUTリクエストを行い、同じリソースに対して後続のGETリクエストを行うことでそのボディの値を取得できます。 その使用例を以下に示します。

# First, trying to retrieve the key will return a 404.
$ http GET https://endpoint/api/objects/mykey
HTTP/1.1 404 Not Found

{
    "Code": "NotFoundError",
    "Message": "mykey"
}

# Next, we'll create that key by sending a PUT request.
$ echo '{"foo": "bar"}' | http PUT https://endpoint/api/objects/mykey
HTTP/1.1 200 OK

null

# And now we no longer get a 404, we instead get the value we previously
# put.
$ http GET https://endpoint/api/objects/mykey
HTTP/1.1 200 OK

{
    "mykey": {
        "foo": "bar"
    }
}

オブジェクトをモジュールレベルのOBJECTS変数に格納する際に問題が発生することがあります。 次のセクションでこれについて説明します。

app.current_requestオブジェクトには、次のプロパティもあります。

  • current_request.query_params – リクエストのクエリーparamsのdictです。
  • current_request.headers – 要求ヘッダーのdictです。
  • current_request.uri_params – キャプチャされたURI paramsのdict。
  • current_request.method – HTTPメソッド(文字列として)。
  • current_request.json_body – 解析されたJSON本体( json.loads(raw_body)
  • current_request.raw_body – 生のHTTPボディーをバイト数で表したもの。
  • current_request.context – 追加のコンテキスト情報の要点
  • current_request.stage_vars – APIゲートウェイステージのコンフィグレーション

contextstage_varsは今のstage_vars気にしないでください。 私たちはまだそれらの概念について議論していません。 current_requestオブジェクトにはto_dictメソッドもあり、現在のリクエストに関するすべての情報を辞書として返します。 このメソッドを使用して、リクエストに関するすべての情報を返すビュー関数を作成しましょう。

@app.route('/introspect')
def introspect():
    return app.current_request.to_dict()

これをapp.pyファイルに保存し、 app.pyを再chalice deployます。 /introspect URLにヒットする例を示します。 カスタムX-TestHeaderヘッダーと同様に、クエリ文字列を送信する方法に注意してください。

$ http 'https://endpoint/api/introspect?query1=value1&query2=value2' 'X-TestHeader: Foo'
HTTP/1.1 200 OK

{
    "context": {
        "apiId": "apiId",
        "httpMethod": "GET",
        "identity": {
            "accessKey": null,
            "accountId": null,
            "apiKey": null,
            "caller": null,
            "cognitoAuthenticationProvider": null,
            "cognitoAuthenticationType": null,
            "cognitoIdentityId": null,
            "cognitoIdentityPoolId": null,
            "sourceIp": "1.1.1.1",
            "userAgent": "HTTPie/0.9.3",
            "userArn": null
        },
        "requestId": "request-id",
        "resourceId": "resourceId",
        "resourcePath": "/introspect",
        "stage": "dev"
    },
    "headers": {
        "accept": "*/*",
        ...
        "x-testheader": "Foo"
    },
    "method": "GET",
    "query_params": {
        "query1": "value1",
        "query2": "value2"
    },
    "raw_body": null,
    "stage_vars": null,
    "uri_params": null
}

チュートリアル:コンテンツタイプのリクエスト

ビュー関数のデフォルトの動作は、 application/json要求本体をサポートしていapplication/json application/json Content-Type application/json Content-Typeでリクエストが行われると、 app.current_request.json_body属性が自動的に設定されます。 この値は、解析されたJSON本体です。

他のコンテンツタイプをサポートするようにビュー機能を設定することもできます。 これを行うには、 app.route関数にcontent_typesパラメータ値を指定します。 このパラメータは、受け入れ可能なコンテンツタイプのリストです。 この機能の例を次に示します。

import sys

from chalice import Chalice
if sys.version_info[0] == 3:
    # Python 3 imports.
    from urllib.parse import urlparse, parse_qs
else:
    # Python 2 imports.
    from urlparse import urlparse, parse_qs


app = Chalice(app_name='helloworld')


@app.route('/', methods=['POST'],
           content_types=['application/x-www-form-urlencoded'])
def index():
    parsed = parse_qs(app.current_request.raw_body.decode())
    return {
        'states': parsed.get('states', [])
    }

このビュー機能には注目すべき点がいくつかあります。 まず、 application/x-www-form-urlencodedコンテンツタイプのみを受け入れるように指定しました。 application/jsonでリクエストを送信しようとすると、 415 Unsupported Media Typeレスポンスが返されます:

$ http POST https://endpoint/api/ states=WA states=CA --debug
...
>>> requests.request(**{'allow_redirects': False,
 'headers': {'Accept': 'application/json',
             'Content-Type': 'application/json',
...


HTTP/1.1 415 Unsupported Media Type

{
    "message": "Unsupported Media Type"
}

httpieContent-Typeヘッダーをapplication/x-www-form-urlencoded設定するため、– --form引数を使用すると、このビュー関数の予想される動作を確認できます。

$ http --form POST https://endpoint/api/formtest states=WA states=CA --debug
...
>>> requests.request(**{'allow_redirects': False,
 'headers': {'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
...

HTTP/1.1 200 OK
{
    "states": [
        "WA",
        "CA"
    ]
}

次に注目すべき点は、 app.current_request.json_body はapplication / jsonコンテンツタイプでのみ利用可能であることです。 上記の例では、 app.current_request.raw_bodyを使用してapp.current_request.raw_bodyバイトにアクセスしました。

parsed = parse_qs(app.current_request.raw_body)

Content-Typeapplication/jsonないapplication/jsonは、 app.current_request.json_bodyNone設定されapplication/json つまり、 app.current_request.raw_bodyを使用し、必要に応じてリクエスト本文を解析する必要があります。

チュートリアル:HTTPレスポンスのカスタマイズ

チャリスビュー関数からの戻り値は、応答本体が呼び出し元に返されるときにJSONとしてシリアル化されます。 これにより、JSON応答本体を返す残りのAPIを簡単に作成できます。

Chaliceでは、シャリス固有のResponseクラスのインスタンスを返すことで、この動作を制御できます。 この動作により、次のことが可能になります。

  • 戻る状態コードを指定する
  • 応答に追加するカスタムヘッダーを指定する
  • application/jsonないレスポンスボディを指定する

ここにその例を示します:

from chalice import Chalice, Response

app = Chalice(app_name='custom-response')


@app.route('/')
def index():
    return Response(body='hello world!',
                    status_code=200,
                    headers={'Content-Type': 'text/plain'})

これにより、プレーンテキストの応答本体が生成されます。

$ http https://endpoint/api/
HTTP/1.1 200 OK
Content-Length: 12
Content-Type: text/plain

hello world!

チュートリアル:CORSサポート

@app.route()呼び出しに@app.route() cors=Trueパラメータを追加することで、ビューがCORSをサポートするかどうかを指定できます。 デフォルトでは、この値はfalseです。

@app.route('/supports-cors', methods=['PUT'], cors=True)
def supports_cors():
    return {}

設定cors=Trueは、AW​​S Consoleを使用してCORSを有効にするのと同様の動作をします。 これも:

  • あなたが返すことができるすべてのエラー応答を含む、あなたの応答にAccess-Control-Allow-Origin: *ヘッダを注入する。
  • プリフライトリクエストをサポートするOPTIONSメソッドを自動的に追加しました。

プリフライトリクエストは以下を含むレスポンスを返します:

  • Access-Control-Allow-Origin: *
  • Access-Control-Allow-Methodsヘッダーは、ビュー機能で呼び出したすべてのHTTPメソッドのリストを返します。 上記の例では、これはPUT,OPTIONSます。
  • Access-Control-Allow-Headers: Content-Type,X-Amz-Date,Authorization, X-Api-Key,X-Amz-Security-Token

CORSヘッダーの細かい制御が必要な場合は、 CORSConfigパラメーターをTrue代わりにCORSConfigインスタンスに設定します。 CORSConfigオブジェクトは、 CORSConfigパッケージからインポートできます。コンストラクタは、CORSヘッダーにマップされる次のキーワード引数を取ります。

引数 タイプ ヘッダ
allow_origin str アクセス制御 – 許可元
allow_headers リスト アクセス制御許可ヘッダー
expose_headers リスト アクセスコントロールの公開ヘッダー
max_age int アクセス制御 – 最大時代
allow_credentials ブール アクセス制御許可の資格情報

より多くのCORSヘッダーを定義するコードサンプル:

from chalice import CORSConfig
cors_config = CORSConfig(
    allow_origin='https://foo.example.com',
    allow_headers=['X-Special-Header'],
    max_age=600,
    expose_headers=['X-Special-Header'],
    allow_credentials=True
)
@app.route('/custom_cors', methods=['GET'], cors=cors_config)
def supports_custom_cors():
    return {'cors': True}

ビューにcorsを有効にするときは、次の点に留意してください。

  • プリフライトのためのOPTIONSメソッドは、常に注入されます。 ビュー関数のmethods=[...]リストにOPTIONSがないことを確認してください。
  • Access-Control-Allow-Originヘッダーは、スペースで区切られたAccess-Control-Allow-Originリストである文字列に設定できますが、この動作はCORSを実装するすべてのクライアントでは機能しません。 CORSConfigオブジェクトには、単一の起点だけを指定する必要がCORSConfigます。 複数の原点を指定する必要がある場合は、 OPTIONS要求を受け取り、 OriginのホワイトリストとOriginヘッダを照合するカスタムハンドラを定義する必要があります。 一致した場合は、 Origin Access-Control-Allow-Originヘッダーに戻します。
  • すべてのビュー機能はCORSサポートを明示的に有効にする必要があります。

最後のポイントは将来変更されます。 詳細については、 この問題を参照してください。

チュートリアル:ポリシーの生成

前のセクションでは、HTTP PUTリクエストの本体にあるJSONを/objects/{name}送信することで、JSONオブジェクトを格納できる基本的な残りのAPIを作成しました。 次に、 /objects/{name} GETリクエストを送信してオブジェクトを取得できます。

しかし、私たちが書いたコードには問題があります:

OBJECTS = {
}

@app.route('/objects/{key}', methods=['GET', 'PUT'])
def myobject(key):
    request = app.current_request
    if request.method == 'PUT':
        OBJECTS[key] = request.json_body
    elif request.method == 'GET':
        try:
            return {key: OBJECTS[key]}
        except KeyError:
            raise NotFoundError(key)

キー値のペアをモジュールレベルのOBJECTS変数に格納しています。 このようにローカルストレージに依存することはできません。

より良い解決策は、この情報をAmazon S3に保存することです。 これを行うには、Python用のAWS SDKであるboto3を使用します。 まず、boto3をインストールします。

$ pip install boto3

次に、requirements.txtファイルにboto3を追加します。

$ echo 'boto3==1.3.1' >> requirements.txt

requirements.txtファイルは、 app.pyファイルを含むディレクトリと同じディレクトリにある必要があります。 次に、boto3を使用するようにビューコードを更新しましょう:

import json
import boto3
from botocore.exceptions import ClientError

from chalice import NotFoundError


S3 = boto3.client('s3', region_name='us-west-2')
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)

あなたが所有するS3バケットの名前でバケツを変更してください。 chalice deployて変更を再デプロイします。 さて、 /objects/keynameへのPUTリクエストを行うたびに、データ送信がS3に保存されます。 それ以降のGETリクエストはこのデータをS3から取得します。

手動でポリシーを提供する

IAMパーミッションは、手動で提供される自動生成、または事前に作成して明示的に設定することができます。 チャリスにあらかじめ設定されたIAMロールARNを使用するには、これらの2つのキーをあなたのシャリス設定に追加します。 manage_iam_roleをfalseに設定すると、Chaliceはポリシーの生成とIAMロールの作成を行わないように指示します。

"manage_iam_role":false
"iam_role_arn":"arn:aws:iam::<account-id>:role/<role-name>"

Whenever your application is deployed using chalice , the auto generated policy is written to disk at <projectdir>/.chalice/policy.json . When you run the chalice deploy command, you can also specify the --no-autogen-policy option. Doing so will result in the chalice CLI loading the <projectdir>/.chalice/policy.json file and using that file as the policy for the IAM role. You can manually edit this file and specify --no-autogen-policy if you’d like to have full control over what IAM policy to associate with the IAM role.

You can also run the chalice gen-policy command from your project directory to print the auto generated policy to stdout. You can then use this as a starting point for your policy.

$ chalice gen-policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:ListAllMyBuckets"
      ],
      "Resource": [
        "*"
      ],
      "Effect": "Allow",
      "Sid": "9155de6ad1d74e4c8b1448255770e60c"
    }
  ]
}

Experimental Status

The automatic policy generation is still in the early stages, it should be considered experimental. You can always disable policy generation with --no-autogen-policy for complete control.

Additionally, you will be prompted for confirmation whenever the auto policy generator detects actions that it would like to add or remove:

$ chalice deploy
Updating IAM policy.

The following action will be added to the execution policy:

s3:ListBucket

Would you like to continue?  [Y/n]:

Tutorial: Using Custom Authentication

AWS API Gateway routes can be authenticated in multiple ways:

  • API Key
  • AWS IAM
  • Cognito User Pools
  • Custom Auth Handler

API Key

@app.route('/authenticated', methods=['GET'], api_key_required=True)
def authenticated():
    return {"secure": True}

Only requests sent with a valid X-Api-Key header will be accepted.

Using AWS IAM

authorizer = IAMAuthorizer()

@app.route('/iam-role', methods=['GET'], authorizer=authorizer)
def authenticated():
    return {"secure": True}

Using Amazon Cognito User Pools

To integrate with cognito user pools, you can use the CognitoUserPoolAuthorizer object:

authorizer = CognitoUserPoolAuthorizer(
    'MyPool', header='Authorization',
    provider_arns=['arn:aws:cognito:...:userpool/name'])

@app.route('/user-pools', methods=['GET'], authorizer=authorizer)
def authenticated():
    return {"secure": True}

Note, earlier versions of chalice also have an app.define_authorizer method as well as an authorizer_name argument on the @app.route(...) method. This approach is deprecated in favor of CognitoUserPoolAuthorizer and the authorizer argument in the @app.route(...) method. app.define_authorizer will be removed in future versions of chalice.

Using Custom Authorizers

To integrate with custom authorizers, you can use the CustomAuthorizer method on the app object. You’ll need to set the authorizer_uri to the URI of your lambda function.

authorizer = CustomAuthorizer(
    'MyCustomAuth', header='Authorization',
    authorizer_uri=('arn:aws:apigateway:region:lambda:path/2015-03-01'
                    '/functions/arn:aws:lambda:region:account-id:'
                    'function:FunctionName/invocations'))

@app.route('/custom-auth', methods=['GET'], authorizer=authorizer)
def authenticated():
    return {"secure": True}

Tutorial: Local Mode

As you develop your application, you may want to experiment locally before deploying your changes. You can use chalice local to spin up a local HTTP server you can use for testing.

For example, if we have the following app.py file:

from chalice import Chalice

app = Chalice(app_name='helloworld')


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

We can run chalice local to test this API locally:

$ chalice local Serving on localhost:8000

We can override the port using:

$ chalice local –port=8080

We can now test our API using localhost:8000 :

$ http localhost:8000/
HTTP/1.0 200 OK
Content-Length: 18
Content-Type: application/json
Date: Thu, 27 Oct 2016 20:08:43 GMT
Server: BaseHTTP/0.3 Python/2.7.11

{
    "hello": "world"
}

The chalice local command does not assume the role associated with your lambda function, so you’ll need to use an AWS_PROFILE that has sufficient permissions to your AWS resources used in your app.py .

Deleting Your App

You can use the chalice delete command to delete your app. Similar to the chalice deploy command, you can specify which chalice stage to delete. By default it will delete the dev stage:

$ chalice delete --stage dev
Deleting rest API duvw4kwyl3
Deleting lambda function helloworld-dev
Delete the role helloworld-dev? [y/N]: y
Deleting role name helloworld-dev

フィードバック

We’also love to hear from you. Please create any Github issues for additional features you’d like to see over at https://github.com/aws/chalice/issues . You can also chat with us on gitter: https://gitter.im/awslabs/chalice

よくある質問

Q: How does the Python Serverless Microframework for AWS compare to other similar frameworks?

The biggest difference between this framework and others is that the Python Serverless Microframework for AWS is singularly focused on using a familiar, decorator-based API to write python applications that run on Amazon API Gateway and AWS Lambda. You can think of it as Flask / Bottle for serverless APIs. Its goal is to make writing and deploying these types of applications as simple as possible specifically for Python developers.

To achieve this goal, it has to make certain tradeoffs. Python will always remain the only supported language in this framework. Not every feature of API Gateway and Lambda is exposed in the framework. It makes assumptions about how applications will be deployed, and it has restrictions on how an application can be structured. It does not address the creation and lifecycle of other AWS resources your application may need (Amazon S3 buckets, Amazon DynamoDB tables, etc.). The feature set is purposefully small.

Other full-stack frameworks offer a lot more features and configurability than what this framework has and likely will ever have. Those frameworks are excellent choices for applications that need more than what is offered by this microframework. If all you need is to create a simple rest API in Python that runs on Amazon API Gateway and AWS Lambda, consider giving the Python Serverless Microframework for AWS a try.

関連プロジェクト

  • serverless – Build applications comprised of microservices that run in response to events, auto-scale for you, and only charge you when they run.
  • Zappa – Deploy python WSGI applications on AWS Lambda and API Gateway.
  • claudia – Deploy node.js projects to AWS Lambda and API Gateway.
  • Domovoi – An extension to Chalice that handles a variety of AWS Lambda event sources such as SNS push notifications, S3 events, and Step Functions state machines.







-aws
-, , , , , , , , ,

執筆者: