2026.06.04(木) / 08:37
FastAPIのトップページが表示されるまでのルーティングの仕組み
- ID
- 37152
- Published
- 2026-06-04 08:37
- Modified
- 2026-07-11 21:08
- Author
- khiro
- Categories
- 技術ブログ
- Tags
- FastAPI, Jinja2, My Portfolio, Python
My Portfolioは、PythonのWebフレームワークであるFastAPIを使用して開発しています。
本記事では、トップページのURL(http://127.0.0.1:8000/)にアクセスしてから、
HTMLが画面に表示されるまでの処理の流れを整理します。
全体の処理の流れ
トップページが表示されるまでの流れは、次の5段階です。
- ブラウザからトップページのURLにアクセスする
- FastAPIが
top_page関数を実行する - セッションとデータベースから必要な情報を取得する
- 取得した情報を
top.htmlへ渡す - Jinja2がHTMLを生成し、ブラウザに表示する
1.トップページのURLにアクセスする
ブラウザから以下のURLへアクセスします。
http://127.0.0.1:8000/
URLのパスは/です。

この/へのGETリクエストを受け取る処理が、app/routers/top.pyに定義されています。
2. URLとtop_page関数を関連付ける
FastAPIのAPIRouterを使用して、URLと処理を行う関数を関連付けます。
from fastapi import APIRouter
router = APIRouter()
@router.get("/")をtop_page関数の上に記述することで、トップページへのGETリクエストを登録しています。
@router.get("/")
def top_page(
request: Request,
db: Session = Depends(get_db)
):
これにより、ブラウザから/へアクセスしたときに、top_page関数が実行されます。
3.トップページに必要な情報を取得する
top_page関数では、主に次の情報を取得しています。
- ユーザーID
- ログイン状態
- 最近の制作物
- 最近の技術ブログ
- 最近の職務経歴
実際のコードは次のとおりです。
from fastapi import APIRouter, Depends, Request
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session
from app import models
from app.database import get_db
router = APIRouter()
templates = Jinja2Templates(directory="app/templates")
@router.get("/")
def top_page(
request: Request,
db: Session = Depends(get_db)
):
user_id = request.session.get("user_id")
is_logged_in = "user_id" in request.session
works = (
db.query(models.Work)
.order_by(models.Work.id.desc())
.limit(2)
.all()
)
blogs = (
db.query(models.Blog)
.order_by(models.Blog.published_at.desc())
.limit(2)
.all()
)
recent_careers = (
db.query(models.Career)
.order_by(models.Career.id.desc())
.limit(2)
.all()
)
return templates.TemplateResponse(
request,
"top.html",
{
"works": works,
"blogs": blogs,
"recent_careers": recent_careers,
"user_id": user_id,
"is_logged_in": is_logged_in
}
)
3-1. ログイン状態を取得する
セッションからuser_idを取得します。
user_id = request.session.get("user_id")
さらに、セッション内にuser_idが存在するかどうかを確認し、ログイン状態を判定します。
is_logged_in = "user_id" in request.session
ログインしている場合はTrue、ログインしていない場合はFalseになります。
3-2. 最近の制作物を取得する
Workテーブルから、IDの大きい順に2件取得しています。
works = (
db.query(models.Work)
.order_by(models.Work.id.desc())
.limit(2)
.all()
)
処理内容は次のとおりです。
db.query(models.Work):制作物を検索するorder_by(models.Work.id.desc()):IDの降順に並べるlimit(2):取得件数を2件に制限するall():組み立てたクエリを実行し、検索結果をリストで取得する
補足 : 組み立てたクエリ
SELECT *
FROM works
ORDER BY id DESC
LIMIT 2;

3-3. 最近の技術ブログを取得する
Blogテーブルから、公開日時の新しい順に2件取得しています。
blogs = (
db.query(models.Blog)
.order_by(models.Blog.published_at.desc())
.limit(2)
.all()
)
3-4. 最近の職務経歴を取得する
Careerテーブルから、IDの大きい順に2件取得しています。
recent_careers = (
db.query(models.Career)
.order_by(models.Career.id.desc())
.limit(2)
.all()
)
4. 取得した情報をtop.htmlへ渡す
取得した情報は、TemplateResponseを使用してトップページのテンプレート(app/templates/top.html)へ渡します。
return templates.TemplateResponse(
request,
"top.html",
{
"works": works,
"blogs": blogs,
"recent_careers": recent_careers,
"user_id": user_id,
"is_logged_in": is_logged_in
}
第2引数の"top.html"が、表示するテンプレートファイルです。
辞書のキーは、top.html内で使用する変数名になります。
| Python側の変数 | テンプレート内の変数 | 内容 |
|---|---|---|
works | works | 最近の制作物 |
blogs | blogs | 最近の技術ブログ |
recent_careers | recent_careers | 最近の職務経歴 |
user_id | user_id | ログインユーザーのID |
is_logged_in | is_logged_in | ログイン状態 |
5. top.htmlで受け取った情報を表示する
top.htmlでは、Jinja2の記法を使用して、受け取った情報をHTMLに埋め込みます。
5-1. ログイン状態によってボタンの表示を切り替える
{% if is_logged_in %}
<a
href="/works-page/new"
class="btn-outline"
>
新規制作物を登録する
</a>
{% endif %}
is_logged_inがTrueの場合だけ、「新規制作物を登録する」ボタンが表示されます。
ログインしていない場合は、このHTML自体が出力されません。
5-2. 最近の制作物を表示する
<section class="top-section">
<div class="section-header">
<h2 class="section-title">
最近の制作物
</h2>
<a
href="/works-page"
class="primary-button view-all-btn view-all-btn-pc"
>
すべて見る
</a>
</div>
<div class="top-grid">
{% for work in works %}
<a
href="/works-page/{{ work.id }}"
class="work-card"
>
{% if work.image_url %}
<img
src="{% if work.image_url.startswith('/') %}{{ work.image_url }}{% else %}/{{ work.image_url }}{% endif %}"
alt="{{ work.title }}"
class="work-thumbnail"
>
{% endif %}
<h2>
{{ work.title }}
</h2>
<p class="work-description">
{{ work.description }}
</p>
<div class="tech-tags">
{% for tech in work.tech_stack.split(",") %}
<span class="tech-tag">
{{ tech.strip() }}
</span>
{% endfor %}
</div>
</a>
{% endfor %}
</div>
</section>
{% for work in works %}によって、Python側から渡された制作物を1件ずつ取り出しています。
各制作物について、次の情報を表示しています。
- 画像
- タイトル
- 説明
- 使用技術
- 詳細ページへのリンク
5-3. 最近の技術ブログを表示する
<section class="top-section">
<div class="section-header">
<h2 class="section-title">
最近の技術ブログ
</h2>
<a
href="/blogs-page"
class="primary-button view-all-btn view-all-btn-pc"
>
すべて見る
</a>
</div>
<div class="top-grid">
{% for blog in blogs %}
<a
href="/blogs-page/{{ blog.id }}"
class="work-card"
>
<h2>
{{ blog.title }}
</h2>
<div class="blog-meta">
{% if blog.published_at %}
<span>
{{ blog.published_at }}
</span>
{% endif %}
</div>
<p class="work-description">
{{ blog.summary }}
</p>
{% if blog.tags %}
<div class="tech-tags">
{% for tag in blog.tags.split(",") %}
<span class="tech-tag">
{{ tag.strip() }}
</span>
{% endfor %}
</div>
{% endif %}
</a>
{% endfor %}
</div>
</section>
{% for blog in blogs %}によって、技術ブログを1件ずつ取り出しています。
各記事について、次の情報を表示しています。
- タイトル
- 公開日時
- 概要
- タグ
- 詳細ページへのリンク
図にするとこんな感じ(is_logged_inの場合)
① トップページへアクセス
② セッションにuser_idがあるか確認

③ is_logged_inをtop.htmlへ渡す
④ top.htmlでログイン状態を判定

⑤ ログイン中の場合だけ登録ボタンを表示

まとめ
FastAPIでトップページを表示する処理は、次の役割に分かれています。
@router.get("/")
URLとPythonの関数を関連付けるtop_page関数
セッションやデータベースから必要な情報を取得するTemplateResponse
取得した情報をテンプレートへ渡すtop.html
受け取った情報をJinja2でHTMLに埋め込む
このように、FastAPI側ではデータの取得や画面表示に必要な情報の準備を行い、Jinja2側では受け取った情報を使ってHTMLを生成しています。