クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

関数の HTTP の玄関

このレッスンのあとで: API Gateway が関数に期待するレスポンスを、書くことができる。

60分のレッスンコマンドなし

関数を動かす、ウェブのアドレス

お店が、/orders/sato というウェブのアドレスで、佐藤さんの注文を答えたいとします。そのためだけに、サーバーを動かしたくはありません。

API Gateway は、ウェブのリクエストを受けて、Lambda 関数に渡せます。関数は、ゲートウェイが期待する形で答えなければなりません。リクエストが間違っているときも、同じです。

このレッスンのゴール

メモ

API Gateway が関数に期待するレスポンスを、書くことができる。

キーワード

ことばいみれい
リクエスト呼ぶ側が、ウェブのアドレスに送るもの
レスポンス関数が返す答え
ステータスコードリクエストの結果を言う数404
ヘッダー本文の横に送る、名前つきの情報content-type
ボディリクエストやレスポンスの、本文の文字列

学生が入力するセルは、このプレビューでは空白です。

リクエストが入り、レスポンスが出る

ゲートウェイは、ウェブのリクエストをイベントにします。GET などのメソッドは requestContext.http.method にあり、パスは rawPath にあります。

関数は、statusCode、headers、body の3つを持つ辞書を返します。body は文字列でなければならないので、json.dumps を使います。これらは文書にある形で、あなたのスタックの出力ではありません。

実行: いちばん小さな玄関

コード: python
import json

# HTTP API のリクエストの、文書にある形。削ってあります。
event = {
    "requestContext": {"http": {"method": "GET"}},
    "rawPath": "/orders/sato",
    "headers": {"accept": "application/json"},
}


def handler(event, context):
    method = event["requestContext"]["http"]["method"]
    path = event["rawPath"]
    data = {"you_asked": method + " " + path}
    return {"statusCode": 200,
            "headers": {"content-type": "application/json"},
            "body": json.dumps(data)}


answer = handler(event, None)
print(answer["statusCode"])
print(answer["body"])
print(type(answer["body"]).__name__)
# event の "GET" を "POST" に変えて、もう一度実行しましょう。

ステータスコードは、誰が間違ったかを言う

2 で始まる 200 や 201 は、成功です。4 で始まる 400 や 404 は、呼ぶ側が間違ったものを求めた、という意味です。5 で始まるものは、関数のほうが失敗したときです。

間違ったリクエストは、故障ではありません。短いエラーを body に入れて、4 のコードを返します。関数がエラーで落ちると、呼ぶ側には、曖昧な 5 が届くだけです。直せることは何も伝わりません。

例: このレッスンで使うコード

コード意味使うとき
200OKデータを見つけて返したとき
201Created新しい注文を保存したとき
400Bad request項目が足りない、間違っている、または body が JSON として読めないとき
404Not foundそのパスや注文がないとき
405Method not allowedパスはあるが、そのメソッドはないとき
415Unsupported media typecontent-type が application/json でないとき

学生が入力するセルは、このプレビューでは空白です。

よくある間違い

注意

悪い入力のとき、関数をそのまま落とす人が多いです。呼ぶ側には、曖昧なサーバーのエラーが届きます。先に入力を調べます。間違っているのが呼ぶ側なら、4 のコードを返し、何を直すかを言います。5 は、こちらの失敗のためにとっておきます。

実行: エラーをレスポンスにする

コード: python
import json


def reply(status, data):
    return {"statusCode": status,
            "headers": {"content-type": "application/json"},
            "body": json.dumps(data)}


def handler(event, context):
    # キーがないのは呼ぶ側の間違いです。落とさずに 400 を返します。
    if "queryStringParameters" not in event:
        return reply(400, {"error": "add ?customer=name"})
    name = event["queryStringParameters"]["customer"]
    return reply(200, {"hello": name})


print(handler({"queryStringParameters": {"customer": "sato"}}, None)["statusCode"])
print(handler({}, None)["statusCode"])
print(handler({}, None)["body"])
# {"queryStringParameters": {}} で handler を呼ぶ3行目を足しましょう。何が起きますか。

リクエストを丁寧に読む

どのキーも、いつもあるとは限りません。クエリ文字列がないと、queryStringParameters はイベントに入りません。読む前に、in で調べます。

body は文字列で届きます。isBase64Encoded が true なら、文字列は符号化されているので、先に復号します。ヘッダーの名前は小文字で届くので、content-type を探します。

実行: base64 の body を読む

コード: python
import json
import base64

event = {
    "body": base64.b64encode(b'{"item": "tea"}').decode("utf-8"),
    "isBase64Encoded": True,
}

text = event["body"]
print(text)
if event["isBase64Encoded"] is True:
    text = base64.b64decode(text).decode("utf-8")
print(text)
print(json.loads(text)["item"])
# isBase64Encoded を False にして、もう一度実行しましょう。何がうまくいきませんか。

このモジュールで教えなかったこと

メモ

ここでの作業は、本物に似せた答えを使い、Python でオフラインで行いました。何もデプロイせず、本物のアカウントにも入らず、請求も見ていません。サービスを動かし続ける費用にも出会っていません。それらは次の段階で、アカウントの設定を確かめてくれる人と学ぶのが、いちばんです。

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。