コンテンツにスキップ

基本例

lambapi の基本的な使用例を紹介します。これらの例は実際のコードをコピー&ペーストして試すことができます。

Hello World

最もシンプルな例から始めましょう。

hello_world.py
from lambapi import API, create_lambda_handler

def create_app(event, context):
    app = API(event, context)

    @app.get("/")
    def hello():
        return {"message": "Hello, World!"}

    return app

lambda_handler = create_lambda_handler(create_app)

パスパラメータ

URL の一部をパラメータとして受け取る例です。

path_parameters.py
from lambapi import API, create_lambda_handler

def create_app(event, context):
    app = API(event, context)

    @app.get("/hello/{name}")
    def hello_name(name: str):
        return {"message": f"Hello, {name}!"}

    @app.get("/users/{user_id}")
    def get_user(user_id: str):
        return {
            "user_id": user_id,
            "name": f"User {user_id}",
            "profile_url": f"/users/{user_id}/profile"
        }

    @app.get("/users/{user_id}/posts/{post_id}")
    def get_user_post(user_id: str, post_id: str):
        return {
            "user_id": user_id,
            "post_id": post_id,
            "title": f"Post {post_id} by User {user_id}"
        }

    return app

lambda_handler = create_lambda_handler(create_app)

クエリパラメータ

URL のクエリパラメータを関数引数として受け取る例です。

query_parameters.py
from lambapi import API, create_lambda_handler

def create_app(event, context):
    app = API(event, context)

    @app.get("/search")
    def search(q: str = "", limit: int = 10, sort: str = "relevance"):
        return {
            "query": q,
            "limit": limit,
            "sort": sort,
            "results": [f"result-{i}" for i in range(1, min(limit, 5) + 1)]
        }

    @app.get("/products")
    def get_products(
        category: str = "all",
        min_price: float = 0.0,
        max_price: float = 1000.0,
        in_stock: bool = True,
        page: int = 1
    ):
        return {
            "category": category,
            "price_range": {"min": min_price, "max": max_price},
            "in_stock_only": in_stock,
            "page": page,
            "products": []
        }

    return app

lambda_handler = create_lambda_handler(create_app)

HTTP メソッド

すべての HTTP メソッドの使用例です。

http_methods.py
from lambapi import API, Response, create_lambda_handler

def create_app(event, context):
    app = API(event, context)

    # データストア(実際にはデータベースを使用)
    items = {}

    @app.get("/items")
    def list_items():
        return {"items": list(items.values())}

    @app.get("/items/{item_id}")
    def get_item(item_id: str):
        if item_id not in items:
            return Response({"error": "Item not found"}, status_code=404)
        return {"item": items[item_id]}

    @app.post("/items")
    def create_item(request):
        data = request.json()
        item_id = str(len(items) + 1)

        item = {
            "id": item_id,
            "name": data.get("name"),
            "description": data.get("description"),
            "price": data.get("price")
        }

        items[item_id] = item

        return Response(
            {"message": "Item created", "item": item},
            status_code=201
        )

    @app.put("/items/{item_id}")
    def update_item(item_id: str, request):
        if item_id not in items:
            return Response({"error": "Item not found"}, status_code=404)

        data = request.json()
        items[item_id].update(data)

        return {"message": "Item updated", "item": items[item_id]}

    @app.delete("/items/{item_id}")
    def delete_item(item_id: str):
        if item_id not in items:
            return Response({"error": "Item not found"}, status_code=404)

        deleted_item = items.pop(item_id)
        return {"message": "Item deleted", "deleted_item": deleted_item}

    @app.patch("/items/{item_id}")
    def patch_item(item_id: str, request):
        if item_id not in items:
            return Response({"error": "Item not found"}, status_code=404)

        data = request.json()

        # PATCH は部分更新
        for key, value in data.items():
            if key in items[item_id]:
                items[item_id][key] = value

        return {"message": "Item patched", "item": items[item_id]}

    return app

lambda_handler = create_lambda_handler(create_app)

レスポンスのカスタマイズ

さまざまなレスポンス形式の例です。

custom_responses.py
from lambapi import API, Response, create_lambda_handler
import json

def create_app(event, context):
    app = API(event, context)

    @app.get("/simple")
    def simple_response():
        # 辞書はそのまま JSON になる
        return {"message": "Simple response"}

    @app.get("/custom-status")
    def custom_status():
        # カスタムステータスコード
        return Response(
            {"message": "Created successfully"},
            status_code=201
        )

    @app.get("/custom-headers")
    def custom_headers():
        # カスタムヘッダー
        return Response(
            {"message": "Response with custom headers"},
            headers={
                "X-Custom-Header": "Custom Value",
                "Cache-Control": "no-cache"
            }
        )

    @app.get("/text-response")
    def text_response():
        # テキストレスポンス
        return Response(
            "This is a plain text response",
            headers={"Content-Type": "text/plain"}
        )

    @app.get("/xml-response")
    def xml_response():
        xml_content = '''<?xml version="1.0" encoding="UTF-8"?>
<response>
    <message>This is XML response</message>
    <status>success</status>
</response>'''

        return Response(
            xml_content,
            headers={"Content-Type": "application/xml"}
        )

    @app.get("/download")
    def download_file():
        # ファイルダウンロード
        file_content = "Hello, this is a downloadable file!"

        return Response(
            file_content,
            headers={
                "Content-Type": "application/octet-stream",
                "Content-Disposition": "attachment; filename=sample.txt"
            }
        )

    @app.get("/redirect")
    def redirect_response():
        # リダイレクト
        return Response(
            "",
            status_code=302,
            headers={"Location": "https://example.com"}
        )

    return app

lambda_handler = create_lambda_handler(create_app)

エラーハンドリング

エラー処理の基本例です。

error_handling.py
from lambapi import API, Response, create_lambda_handler
from lambapi.exceptions import ValidationError, NotFoundError

def create_app(event, context):
    app = API(event, context)

    @app.get("/error-demo/{error_type}")
    def error_demo(error_type: str):
        if error_type == "validation":
            raise ValidationError(
                "Invalid input data",
                field="name",
                value="invalid_value"
            )
        elif error_type == "not-found":
            raise NotFoundError("Resource", "123")
        elif error_type == "custom":
            return Response(
                {"error": "CUSTOM_ERROR", "message": "This is a custom error"},
                status_code=422
            )
        elif error_type == "server":
            raise Exception("Simulated server error")
        else:
            return {"message": f"No error for type: {error_type}"}

    # カスタムエラーハンドラー
    class BusinessError(Exception):
        def __init__(self, message: str, code: str):
            self.message = message
            self.code = code

    @app.error_handler(BusinessError)
    def handle_business_error(error, request, context):
        return Response({
            "error": "BUSINESS_ERROR",
            "message": error.message,
            "code": error.code,
            "request_id": context.aws_request_id
        }, status_code=400)

    @app.get("/business-error")
    def trigger_business_error():
        raise BusinessError("Insufficient funds", "INSUFFICIENT_FUNDS")

    return app

lambda_handler = create_lambda_handler(create_app)

データバリデーション

データクラスを使用したバリデーションの例です。

validation.py
from lambapi import API, Response, create_lambda_handler
from dataclasses import dataclass
from typing import Optional

@dataclass
class CreateUserRequest:
    name: str
    email: str
    age: int
    bio: Optional[str] = None

@dataclass
class UserResponse:
    id: str
    name: str
    email: str
    age: int
    bio: Optional[str] = None

def create_app(event, context):
    app = API(event, context)

    users = {}

    @app.post("/users", request_format=CreateUserRequest, response_format=UserResponse)
    def create_user(user_data: CreateUserRequest):
        # user_data は自動的に CreateUserRequest インスタンスに変換される
        user_id = str(len(users) + 1)

        user = {
            "id": user_id,
            "name": user_data.name,
            "email": user_data.email,
            "age": user_data.age,
            "bio": user_data.bio
        }

        users[user_id] = user

        # 戻り値は UserResponse として検証される
        return user

    @app.get("/users/{user_id}", response_format=UserResponse)
    def get_user(user_id: str):
        if user_id not in users:
            return Response({"error": "User not found"}, status_code=404)

        return users[user_id]

    return app

lambda_handler = create_lambda_handler(create_app)

ミドルウェア

ミドルウェアを使用した横断的関心事の処理例です。

middleware.py
from lambapi import API, Response, create_lambda_handler
import time
import json

def create_app(event, context):
    app = API(event, context)

    # ログミドルウェア
    def logging_middleware(request, response):
        print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {request.method} {request.path}")

        # レスポンスのログ
        if isinstance(response, Response):
            print(f"Response: {response.status_code}")

        return response

    # CORS ミドルウェア
    def cors_middleware(request, response):
        if isinstance(response, Response):
            response.headers.update({
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
                'Access-Control-Allow-Headers': 'Content-Type, Authorization'
            })
        return response

    # セキュリティヘッダーミドルウェア
    def security_headers_middleware(request, response):
        if isinstance(response, Response):
            response.headers.update({
                'X-Content-Type-Options': 'nosniff',
                'X-Frame-Options': 'DENY',
                'X-XSS-Protection': '1; mode=block'
            })
        return response

    # ミドルウェアを追加
    app.add_middleware(logging_middleware)
    app.add_middleware(cors_middleware)
    app.add_middleware(security_headers_middleware)

    @app.get("/")
    def hello():
        return {"message": "Hello with middleware!"}

    @app.get("/protected")
    def protected_endpoint():
        return {"message": "This endpoint has security headers"}

    return app

lambda_handler = create_lambda_handler(create_app)

ローカルでのテスト方法

CLI コマンドでのテスト

# ファイルを保存してローカルサーバーで起動
lambapi serve hello_world

# テスト
curl http://localhost:8000/
curl http://localhost:8000/hello/world
curl "http://localhost:8000/search?q=test&limit=5"

# POST リクエスト
curl -X POST http://localhost:8000/items \
  -H "Content-Type: application/json" \
  -d '{"name":"Test Item","price":100}'

Python での直接テスト

test_examples.py
import json

def test_api(lambda_handler, method, path, body=None, query_params=None):
    """API をテストするヘルパー関数"""
    event = {
        'httpMethod': method,
        'path': path,
        'headers': {'Content-Type': 'application/json'},
        'body': json.dumps(body) if body else None,
        'queryStringParameters': query_params
    }

    context = type('Context', (), {'aws_request_id': 'test-123'})()

    result = lambda_handler(event, context)

    print(f"{method} {path}")
    print(f"Status: {result['statusCode']}")
    print(f"Response: {result['body']}")
    print("-" * 50)

    return result

# 使用例
if __name__ == "__main__":
    from path_parameters import lambda_handler as path_handler
    from query_parameters import lambda_handler as query_handler

    # パスパラメータのテスト
    test_api(path_handler, 'GET', '/hello/world')
    test_api(path_handler, 'GET', '/users/123')

    # クエリパラメータのテスト
    test_api(query_handler, 'GET', '/search', query_params={'q': 'python', 'limit': '5'})
    test_api(query_handler, 'GET', '/products', query_params={
        'category': 'electronics',
        'min_price': '100',
        'in_stock': 'true'
    })

SAM でのローカル実行

SAM Local を使用してローカルでテストする場合の設定例です。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  lambapiFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: .
      Handler: hello_world.lambda_handler
      Runtime: python3.13
      Events:
        ApiGateway:
          Type: Api
          Properties:
            Path: /{proxy+}
            Method: ANY
# SAM Local を起動
sam local start-api

# テスト
curl http://localhost:3000/
curl http://localhost:3000/hello/world
curl "http://localhost:3000/search?q=test&limit=5"

これらの例を参考に、lambapi の様々な機能を試してみてください。各例は独立しているので、必要な部分だけを選んで使用することも可能です。