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/フォルダは触らない (採点ロジック)
このガイドのドリル一覧
| # | ドリル名 | タイトル | タイプ | 難易度 |
|---|---|---|---|---|
| 1 | 01-fill-path-param | パスパラメータ {item_id} - 空欄を埋める | 🔧 穴埋め | ★ |
| 2 | 02-type-annotation | 型ヒント item_id: int - 自動バリデーション | 🔧 穴埋め | ★ |
| 3 | 03-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_idはintで受け取ってみる
採点ロジックは元のテストのままです。拡張部分を実装してもテストは 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/フォルダは触らない (採点ロジック)
このガイドのドリル一覧
| # | ドリル名 | タイトル | タイプ | 難易度 |
|---|---|---|---|---|
| 1 | 01-fill-path-param | パスパラメータ {item_id} - 空欄を埋める | 🔧 穴埋め | ★ |
| 2 | 02-type-annotation | 型ヒント item_id: int - 自動バリデーション | 🔧 穴埋め | ★ |
| 3 | 03-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_idはintで受け取ってみる
採点ロジックは元のテストのままです。拡張部分を実装してもテストは 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 は何でも文字列として受け取る。整数・記号も全て文字列になる。