2026.06.04(木) / 08:37

FastAPIのトップページが表示されるまでのルーティングの仕組み

ID
37152
Published
2026-06-04 08:37
Modified
2026-07-11 21:08
Author
khiro
Categories
技術ブログ
Tags
, , ,

My Portfolioは、PythonのWebフレームワークであるFastAPIを使用して開発しています。

本記事では、トップページのURL(http://127.0.0.1:8000/)にアクセスしてから、

HTMLが画面に表示されるまでの処理の流れを整理します。

全体の処理の流れ

トップページが表示されるまでの流れは、次の5段階です。

  1. ブラウザからトップページのURLにアクセスする
  2. FastAPIがtop_page関数を実行する
  3. セッションとデータベースから必要な情報を取得する
  4. 取得した情報をtop.htmlへ渡す
  5. 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側の変数テンプレート内の変数内容
worksworks最近の制作物
blogsblogs最近の技術ブログ
recent_careersrecent_careers最近の職務経歴
user_iduser_idログインユーザーのID
is_logged_inis_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_inTrueの場合だけ、「新規制作物を登録する」ボタンが表示されます。

ログインしていない場合は、この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を生成しています。