L14 ch01 — CORS Middleware
テクノロジ系 / L14 middleware — ミドルウェア
L14 ch01 — CORS Middleware
フロント (別ポート) からの fetch を許可する
ゴール
- CORS の仕組みを理解
- CORSMiddleware の設定
- Vue + FastAPI 連携で必須
CORS とは
Cross-Origin Resource Sharing
ブラウザのセキュリティ機能:
- ページのオリジン (http://localhost:5173) と
- API のオリジン (http://localhost:8000) が違う
- → デフォルトで ブロック
→ サーバー側で「許可」を明示する必要
設定 (最小)
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"],
allow_methods=["*"],
allow_headers=["*"],
)各設定の意味
| 設定 | 内容 |
|---|---|
allow_origins | 許可するフロント URL |
allow_methods | 許可する HTTP メソッド (["GET", "POST", ...] or ["*"]) |
allow_headers | 許可するリクエストヘッダ |
allow_credentials | Cookie 送信を許可 (True にする場合 origins は ["*"] 不可) |
本番設定
app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://my-app.example.com", # ← 具体的に指定
],
allow_credentials=True,
allow_methods=["GET", "POST", "PATCH", "DELETE"],
allow_headers=["Content-Type", "Authorization"],
)→ 本番では allow_origins=["*"] 禁止 (セキュリティ)
preflight (OPTIONS)
ブラウザは POST 前に OPTIONS リクエストを送って確認:
- サーバーが OPTIONS を許可するか
- 許可レスポンスを受けてから本番 POST 実行
CORSMiddleware が自動処理してくれる。
エラー時の確認方法
ブラウザ DevTools → Network タブ:
- ステータスコード
- Response Headers の
Access-Control-Allow-*
Console:
Blocked by CORS policyメッセージ
drill
drill/ — fill-middleware
ハンズオン
ch01-cors 演習ガイド
受講生向け演習問題集
採点の仕組み (読んでから始めてください)
採点テストは 「お題の通りに動くか」 を機械的にチェックします。
ドリルごとに 3つのタイプ があるので、各ドリル冒頭の 【タイプ】 を確認してください。
タイプ fill (穴埋め問題) — 文法・APIを知っているか
___(3個並んだアンダースコア) の空欄を埋める- 既存の構造は そのまま
- ロジック自由度: 低 (お題どおりに直す)
タイプ add (機能追加問題) — 既存コードに機能を足せるか
- 既存コードを残したまま、新しいエンドポイント/機能を 追加 する
- 実装方法は自由 (関数名・変数名・内部ロジックは好きに)
- ただしテストが要求する I/F (URL・HTTPメソッド・レスポンスのキー名) は守る
- 既存テストを壊さないこと
タイプ build (ゼロベース実装問題) — 仕様から実装を組み立てられるか
- ほぼ空の
main.pyから 自力で全部書く - ファイル構造・関数分割・命名・内部ロジック: 完全に自由
- 守るのはインターフェースだけ: URL・HTTP メソッド・レスポンス JSON 形式
- 一番ハードだが、実装力が一番つくタイプ
3タイプ共通で守ること
- ファイル名 (
main.py) は変えない tests/フォルダは触らない (採点ロジック)
このガイドのドリル一覧
| # | ドリル名 | タイトル | タイプ | 難易度 |
|---|---|---|---|---|
| 1 | 01-fill-middleware | CORSMiddleware - クロスオリジンを許可する | 🔧 穴埋め | ★ |
> 詰まったら ヒント ページを開く。それでも分からなければ講師に質問。
ドリル 1: CORSMiddleware - クロスオリジンを許可する
ドリル名: 01-fill-middleware
> 🔧 【タイプ: 穴埋め問題】 ___ の部分を埋めて完成させてください。既存のコード構造は変えないこと。
問題
___ を埋めて、Vue(http://localhost:5173)からのリクエストを許可する設定を完成させよ。
from fastapi.middleware.cors import ___ # クラス名を埋める
app = FastAPI()
app.add_middleware(
___, # クラス名を埋める
allow_origins=["http://localhost:5173"],
allow_methods=["*"],
allow_headers=["*"],
)確認方法
- FastAPI を起動して
http://localhost:8000/docsが開くこと - Vue(
:5173)からfetch('http://localhost:8000/tasks')を実行してブラウザコンソールに CORS エラーが出ないこと
ドリル 1: ヒント
ドリル名: 01-fill-middleware
> ⚠️ 自力で考えてから読んでください
> FastAPI の CORS ミドルウェアのクラス名は CORSMiddleware。import と add_middleware の両方に同じクラス名を書く。
考えてみよう
既定では正解・不正解の判定はしません。自分のペースで「答えを見る」を。採点してほしい場合だけ「採点してほしい」を押してください。
ch01-cors 演習ガイド
受講生向け演習問題集
採点の仕組み (読んでから始めてください)
採点テストは 「お題の通りに動くか」 を機械的にチェックします。
ドリルごとに 3つのタイプ があるので、各ドリル冒頭の 【タイプ】 を確認してください。
タイプ fill (穴埋め問題) — 文法・APIを知っているか
___(3個並んだアンダースコア) の空欄を埋める- 既存の構造は そのまま
- ロジック自由度: 低 (お題どおりに直す)
タイプ add (機能追加問題) — 既存コードに機能を足せるか
- 既存コードを残したまま、新しいエンドポイント/機能を 追加 する
- 実装方法は自由 (関数名・変数名・内部ロジックは好きに)
- ただしテストが要求する I/F (URL・HTTPメソッド・レスポンスのキー名) は守る
- 既存テストを壊さないこと
タイプ build (ゼロベース実装問題) — 仕様から実装を組み立てられるか
- ほぼ空の
main.pyから 自力で全部書く - ファイル構造・関数分割・命名・内部ロジック: 完全に自由
- 守るのはインターフェースだけ: URL・HTTP メソッド・レスポンス JSON 形式
- 一番ハードだが、実装力が一番つくタイプ
3タイプ共通で守ること
- ファイル名 (
main.py) は変えない tests/フォルダは触らない (採点ロジック)
このガイドのドリル一覧
| # | ドリル名 | タイトル | タイプ | 難易度 |
|---|---|---|---|---|
| 1 | 01-fill-middleware | CORSMiddleware - クロスオリジンを許可する | 🔧 穴埋め | ★ |
> 詰まったら ヒント ページを開く。それでも分からなければ講師に質問。
ドリル 1: CORSMiddleware - クロスオリジンを許可する
ドリル名: 01-fill-middleware
> 🔧 【タイプ: 穴埋め問題】 ___ の部分を埋めて完成させてください。既存のコード構造は変えないこと。
問題
___ を埋めて、Vue(http://localhost:5173)からのリクエストを許可する設定を完成させよ。
from fastapi.middleware.cors import ___ # クラス名を埋める
app = FastAPI()
app.add_middleware(
___, # クラス名を埋める
allow_origins=["http://localhost:5173"],
allow_methods=["*"],
allow_headers=["*"],
)確認方法
- FastAPI を起動して
http://localhost:8000/docsが開くこと - Vue(
:5173)からfetch('http://localhost:8000/tasks')を実行してブラウザコンソールに CORS エラーが出ないこと
ドリル 1: ヒント
ドリル名: 01-fill-middleware
> ⚠️ 自力で考えてから読んでください
> FastAPI の CORS ミドルウェアのクラス名は CORSMiddleware。import と add_middleware の両方に同じクラス名を書く。
ch01-cors 演習解説
⚠️ 自力でドリルを解いてから読んでください
ドリル 1: CORSMiddleware - クロスオリジンを許可する — 模範解答
ドリル名: 01-fill-middleware
import json
from pathlib import Path
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"],
allow_methods=["*"],
allow_headers=["*"],
)
DB_FILE = Path("tasks.json")
class Task(BaseModel):
title: str
done: bool = False
def load() -> list[dict]:
if not DB_FILE.exists():
return []
return json.loads(DB_FILE.read_text(encoding="utf-8"))
def save(tasks: list[dict]) -> None:
DB_FILE.write_text(
json.dumps(tasks, ensure_ascii=False, indent=2),
encoding="utf-8"
)
@app.get("/tasks")
def get_tasks():
return load()
@app.get("/tasks/{task_id}")
def get_task(task_id: int):
tasks = load()
for task in tasks:
if task["id"] == task_id:
return task
raise HTTPException(status_code=404, detail="Task not found")
@app.post("/tasks", status_code=201)
def create_task(task: Task):
tasks = load()
new_task = {"id": len(tasks) + 1, **task.model_dump()}
tasks.append(new_task)
save(tasks)
return new_task
@app.patch("/tasks/{task_id}")
def update_task(task_id: int, task: Task):
tasks = load()
for t in tasks:
if t["id"] == task_id:
t.update(task.model_dump())
save(tasks)
return t
raise HTTPException(status_code=404, detail="Task not found")
@app.delete("/tasks/{task_id}", status_code=204)
def delete_task(task_id: int):
tasks = load()
tasks = [t for t in tasks if t["id"] != task_id]
save(tasks)ドリル 1: CORSMiddleware - クロスオリジンを許可する — 解説
ドリル名: 01-fill-middleware
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"],
allow_methods=["*"],
allow_headers=["*"],
)> ポイント: add_middleware は app = FastAPI() の直後に書く。後ろに書いても動くが、エンドポイント定義より前に設定するのが慣例。allow_origins に指定するのは Vue の開発サーバーのオリジン(スキーム+ホスト+ポート)。