採点されません。匿名です。 間違えることは学習の一部です。読むだけでもかまいません。

L11 ch02 — パスパラメータ

テクノロジ系 / L11 fastapi-basic — FastAPI 入門

L11 ch02 — パスパラメータ

URL の一部を関数引数として受け取る

ゴール

  • @app.get("/items/{item_id}") の構文
  • 型ヒントによる自動バリデーション
  • 422 エラー (型違反) の挙動

基本

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
def get_item(item_id: int):
    return {"item_id": item_id}
GET /items/42  → {"item_id": 42}
GET /items/abc → 422 Unprocessable Entity

仕組み

  • URL の {item_id} 部分が関数引数 item_id にマッピング
  • 型ヒント : int自動的に整数バリデーション
  • 失敗時は 422 + エラーメッセージ JSON

複数パラメータ

@app.get("/users/{user_id}/items/{item_id}")
def get_user_item(user_id: int, item_id: int):
    return {"user_id": user_id, "item_id": item_id}

順序は URL の出現順と一致。

クエリパラメータも

@app.get("/items/")
def list_items(skip: int = 0, limit: int = 10):
    return items[skip:skip+limit]
GET /items/?skip=20&limit=5
  • パスにない引数 = クエリパラメータ扱い
  • デフォルト値あり = optional

文字列を受け取る

@app.get("/users/{username}")
def get_user(username: str):
    return {"username": username}
GET /users/alice → {"username": "alice"}
GET /users/田中 → {"username": "田中"}  (URL エンコード自動デコード)

見つからない時の 404

存在しない item_id を渡されたとき、何も返さない or 適当な値を返すと呼び出し側が困る

こういう「異常系」は HTTPException明示的にエラーを投げるのがパターン。

from fastapi import FastAPI, HTTPException

app = FastAPI()

items = {1: "apple", 2: "banana"}

@app.get("/items/{item_id}")
def get_item(item_id: int):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="not found")
    return {"item_id": item_id, "name": items[item_id]}
GET /items/1   → 200 {"item_id":1,"name":"apple"}
GET /items/99  → 404 {"detail":"not found"}
GET /items/abc → 422 (型違反 / FastAPI が自動で返す)
  • raise HTTPException(status_code=404, detail="...")処理を中断してエラーを返す感覚
  • detail がそのままレスポンスJSONの detail フィールドになる
  • 422 (型違反) は FastAPI が自動で出す。404 (見つからない) は自分で書く

> 「型は合っているが、データが存在しない」ケースは 404 を自分で返す。次の章 CRUD でも頻出パターン。

drill

drill/ — パスパラメータエンドポイントの追加

ハンズオン

ch02-path-params 演習ガイド

受講生向け演習問題集

採点の仕組み (読んでから始めてください)

採点テストは 「お題の通りに動くか」 を機械的にチェックします。

ドリルごとに 3つのタイプ があるので、各ドリル冒頭の 【タイプ】 を確認してください。

タイプ fill (穴埋め問題) — 文法・APIを知っているか

  • ___ (3個並んだアンダースコア) の空欄を埋める
  • 既存の構造は そのまま
  • ロジック自由度: 低 (お題どおりに直す)

タイプ add (機能追加問題) — 既存コードに機能を足せるか

  • 既存コードを残したまま、新しいエンドポイント/機能を 追加 する
  • 実装方法は自由 (関数名・変数名・内部ロジックは好きに)
  • ただしテストが要求する I/F (URL・HTTPメソッド・レスポンスのキー名) は守る
  • 既存テストを壊さないこと

タイプ build (ゼロベース実装問題) — 仕様から実装を組み立てられるか

  • ほぼ空の main.py から 自力で全部書く
  • ファイル構造・関数分割・命名・内部ロジック: 完全に自由
  • 守るのはインターフェースだけ: URL・HTTP メソッド・レスポンス JSON 形式
  • 一番ハードだが、実装力が一番つくタイプ

3タイプ共通で守ること

  • ファイル名 (main.py) は変えない
  • tests/ フォルダは触らない (採点ロジック)

このガイドのドリル一覧

#ドリル名タイトルタイプ難易度
101-fill-path-paramパスパラメータ {item_id} - 空欄を埋める🔧 穴埋め
202-type-annotation型ヒント item_id: int - 自動バリデーション🔧 穴埋め
303-add-path-paramパスパラメータ - 新しいエンドポイントを追加➕ 機能追加

> 詰まったら ヒント ページを開く。それでも分からなければ講師に質問。

ドリル 1: パスパラメータ {item_id} - 空欄を埋める

ドリル名: 01-fill-path-param

> 🔧 【タイプ: 穴埋め問題】 ___ の部分を埋めて完成させてください。既存のコード構造は変えないこと。

問題

___ を埋めて GET /items/{item_id}{"item_id": <整数>} を返すエンドポイントを完成させよ。

@app.get("/items/{___}")
def get_item(item_id: int):
    return {"item_id": item_id}

確認方法

http://localhost:8000/items/5{"item_id": 5} が返ること。

ドリル 1: ヒント

ドリル名: 01-fill-path-param

> ⚠️ 自力で考えてから読んでください

デコレータの {} 内の名前と、関数の引数名を一致させる必要がある。

@app.get("/items/{item_id}")   # ← {} 内の名前
def get_item(item_id: int):    # ← 引数名(同じにする)
    ...

ドリル 2: 型ヒント item_id: int - 自動バリデーション

ドリル名: 02-type-annotation

> 🔧 【タイプ: 穴埋め問題】 ___ の部分を埋めて完成させてください。既存のコード構造は変えないこと。

問題

___ を埋めて、/scores/{score} で整数を受け取り {"score": <整数>, "doubled": <2倍>} を返すエンドポイントを完成させよ。

@app.get("/scores/{score}")
def get_score(score: ___):
    return {"score": score, "doubled": score * 2}

確認方法

  • http://localhost:8000/scores/10{"score": 10, "doubled": 20} が返ること
  • http://localhost:8000/scores/abc → 422 エラーが返ること

ドリル 2: ヒント

ドリル名: 02-type-annotation

> ⚠️ 自力で考えてから読んでください

score * 2 を計算するには score が整数でなければならない。

def get_score(score: int):   # ← int にすると整数として受け取れる
    return {"score": score, "doubled": score * 2}

str にすると "10" * 2 = "1010" になってしまう。

ドリル 3: パスパラメータ - 新しいエンドポイントを追加

ドリル名: 03-add-path-param

> ➕ 【タイプ: 機能追加問題】 既存コードを残したまま新しい機能を追加してください。実装は自由ですが、テストが要求する I/F・表示テキストは守ること。

問題

/users/{username} にアクセスしたとき、以下の JSON を返すエンドポイントを追加せよ。

入力

GET /users/{username}(username は文字列)

出力例

{"username": "alice"}

確認方法

Swagger UI → GET /users/{username} → Try it out → alice を入力 → Execute で上記が返ること。

★ 余裕がある人向け: 拡張課題

このドリルが PASS したら、以下の発展課題に挑戦してみてください (採点はなし、自由演習)。

  • /users/{username} にクエリパラメータ lang (ja / en) を追加し、lang=ja のときは {"username": "alice", "greeting": "こんにちは、alice さん"} を返すようにする
  • username が空文字や3文字未満のとき 400 を返す簡易バリデーションを追加する
  • /users/{username}/posts/{post_id} のような複数階層のパスパラメータを試して、post_idint で受け取ってみる

採点ロジックは元のテストのままです。拡張部分を実装してもテストは PASS のまま、自分の力試しになります。

ドリル 3: ヒント

ドリル名: 03-add-path-param

> ⚠️ 自力で考えてから読んでください

パスパラメータを文字列として受け取るには型を : str にする。

@app.get("/users/{username}")
def get_user(username: str):
    ...

考えてみよう

既定では正解・不正解の判定はしません。自分のペースで「答えを見る」を。採点してほしい場合だけ「採点してほしい」を押してください。

ch02-path-params 演習ガイド

受講生向け演習問題集

採点の仕組み (読んでから始めてください)

採点テストは 「お題の通りに動くか」 を機械的にチェックします。

ドリルごとに 3つのタイプ があるので、各ドリル冒頭の 【タイプ】 を確認してください。

タイプ fill (穴埋め問題) — 文法・APIを知っているか

  • ___ (3個並んだアンダースコア) の空欄を埋める
  • 既存の構造は そのまま
  • ロジック自由度: 低 (お題どおりに直す)

タイプ add (機能追加問題) — 既存コードに機能を足せるか

  • 既存コードを残したまま、新しいエンドポイント/機能を 追加 する
  • 実装方法は自由 (関数名・変数名・内部ロジックは好きに)
  • ただしテストが要求する I/F (URL・HTTPメソッド・レスポンスのキー名) は守る
  • 既存テストを壊さないこと

タイプ build (ゼロベース実装問題) — 仕様から実装を組み立てられるか

  • ほぼ空の main.py から 自力で全部書く
  • ファイル構造・関数分割・命名・内部ロジック: 完全に自由
  • 守るのはインターフェースだけ: URL・HTTP メソッド・レスポンス JSON 形式
  • 一番ハードだが、実装力が一番つくタイプ

3タイプ共通で守ること

  • ファイル名 (main.py) は変えない
  • tests/ フォルダは触らない (採点ロジック)

このガイドのドリル一覧

#ドリル名タイトルタイプ難易度
101-fill-path-paramパスパラメータ {item_id} - 空欄を埋める🔧 穴埋め
202-type-annotation型ヒント item_id: int - 自動バリデーション🔧 穴埋め
303-add-path-paramパスパラメータ - 新しいエンドポイントを追加➕ 機能追加

> 詰まったら ヒント ページを開く。それでも分からなければ講師に質問。

ドリル 1: パスパラメータ {item_id} - 空欄を埋める

ドリル名: 01-fill-path-param

> 🔧 【タイプ: 穴埋め問題】 ___ の部分を埋めて完成させてください。既存のコード構造は変えないこと。

問題

___ を埋めて GET /items/{item_id}{"item_id": <整数>} を返すエンドポイントを完成させよ。

@app.get("/items/{___}")
def get_item(item_id: int):
    return {"item_id": item_id}

確認方法

http://localhost:8000/items/5{"item_id": 5} が返ること。

ドリル 1: ヒント

ドリル名: 01-fill-path-param

> ⚠️ 自力で考えてから読んでください

デコレータの {} 内の名前と、関数の引数名を一致させる必要がある。

@app.get("/items/{item_id}")   # ← {} 内の名前
def get_item(item_id: int):    # ← 引数名(同じにする)
    ...

ドリル 2: 型ヒント item_id: int - 自動バリデーション

ドリル名: 02-type-annotation

> 🔧 【タイプ: 穴埋め問題】 ___ の部分を埋めて完成させてください。既存のコード構造は変えないこと。

問題

___ を埋めて、/scores/{score} で整数を受け取り {"score": <整数>, "doubled": <2倍>} を返すエンドポイントを完成させよ。

@app.get("/scores/{score}")
def get_score(score: ___):
    return {"score": score, "doubled": score * 2}

確認方法

  • http://localhost:8000/scores/10{"score": 10, "doubled": 20} が返ること
  • http://localhost:8000/scores/abc → 422 エラーが返ること

ドリル 2: ヒント

ドリル名: 02-type-annotation

> ⚠️ 自力で考えてから読んでください

score * 2 を計算するには score が整数でなければならない。

def get_score(score: int):   # ← int にすると整数として受け取れる
    return {"score": score, "doubled": score * 2}

str にすると "10" * 2 = "1010" になってしまう。

ドリル 3: パスパラメータ - 新しいエンドポイントを追加

ドリル名: 03-add-path-param

> ➕ 【タイプ: 機能追加問題】 既存コードを残したまま新しい機能を追加してください。実装は自由ですが、テストが要求する I/F・表示テキストは守ること。

問題

/users/{username} にアクセスしたとき、以下の JSON を返すエンドポイントを追加せよ。

入力

GET /users/{username}(username は文字列)

出力例

{"username": "alice"}

確認方法

Swagger UI → GET /users/{username} → Try it out → alice を入力 → Execute で上記が返ること。

★ 余裕がある人向け: 拡張課題

このドリルが PASS したら、以下の発展課題に挑戦してみてください (採点はなし、自由演習)。

  • /users/{username} にクエリパラメータ lang (ja / en) を追加し、lang=ja のときは {"username": "alice", "greeting": "こんにちは、alice さん"} を返すようにする
  • username が空文字や3文字未満のとき 400 を返す簡易バリデーションを追加する
  • /users/{username}/posts/{post_id} のような複数階層のパスパラメータを試して、post_idint で受け取ってみる

採点ロジックは元のテストのままです。拡張部分を実装してもテストは PASS のまま、自分の力試しになります。

ドリル 3: ヒント

ドリル名: 03-add-path-param

> ⚠️ 自力で考えてから読んでください

パスパラメータを文字列として受け取るには型を : str にする。

@app.get("/users/{username}")
def get_user(username: str):
    ...

ch02-path-params 演習解説

⚠️ 自力でドリルを解いてから読んでください

ドリル 1: パスパラメータ {item_id} - 空欄を埋める — 模範解答

ドリル名: 01-fill-path-param

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
def get_item(item_id: int):
    return {"item_id": item_id}

ドリル 1: パスパラメータ {item_id} - 空欄を埋める — 解説

ドリル名: 01-fill-path-param

@app.get("/items/{item_id}")
def get_item(item_id: int):
    return {"item_id": item_id}

> ポイント: {} 内の名前と引数名が一致することで、FastAPI が URL から値を取り出して関数に渡す。

ドリル 2: 型ヒント item_id: int - 自動バリデーション — 模範解答

ドリル名: 02-type-annotation

from fastapi import FastAPI

app = FastAPI()

@app.get("/scores/{score}")
def get_score(score: int):
    return {"score": score, "doubled": score * 2}

ドリル 2: 型ヒント item_id: int - 自動バリデーション — 解説

ドリル名: 02-type-annotation

@app.get("/scores/{score}")
def get_score(score: int):
    return {"score": score, "doubled": score * 2}

> ポイント: : int を書くと FastAPI が文字列 "10" を整数 10 に自動変換する。str のままだと score * 2 が文字列の繰り返しになる。

ドリル 3: パスパラメータ - 新しいエンドポイントを追加 — 模範解答

ドリル名: 03-add-path-param

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
def get_item(item_id: int):
    return {"item_id": item_id}

@app.get("/users/{username}")
def get_user(username: str):
    return {"username": username}

ドリル 3: パスパラメータ - 新しいエンドポイントを追加 — 解説

ドリル名: 03-add-path-param

@app.get("/users/{username}")
def get_user(username: str):
    return {"username": username}

> ポイント: : str は何でも文字列として受け取る。整数・記号も全て文字列になる。

力試ししたい方は クイズ形式の演習(任意) もあります。読むだけでも十分です。