FastAPIでJinja2を使用してHTMLを返し、CSSとJavaScriptを読み込む方法

以下は、FastAPIでJinja2を使用してHTMLを返し、CSSとJavaScriptを読み込む方法の例です。

- 前提
  - python、Fast API、uvicornがインストールされていること。

FastAPIアプリケーションのルートディレクトリに、templatesとstaticという名前のディレクトリを作成します。
templatesディレクトリに、`index.html`というHTMLファイルを作成します。
staticディレクトリに、cssとjsという名前のディレクトリを作成し、それぞれ`styles.css`と`script.js`という名前のファイルを作成します。（中身は適用に書いて）
```:フォルダ構成
myapp/
├─ main.py
└─ templates/
│   └─ index.html
└─ static/
    ├─ css/
    │   └─ style.css
    └─ js/
        └─ script.js
```
次に、FastAPIでJinja2を使用するために、jinja2パッケージをインストールします。
```:
pip install jinja2
```
Jinja2（ジンジャー・ツー）は、Python製のテンプレートエンジンで、Webアプリケーションにおいて、HTMLを動的に変化する内容を埋め込んだり、条件分岐やループ処理などの制御フローを記述することができます。
<br></br>

main.pyには以下のように記載します。(コードの説明は後述)
```python:main.py
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

app = FastAPI()
app.mount(path="/static", app=StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")

@app.get("/", response_class=HTMLResponse)
async def read_root(request: Request):
    context = {"request": request}
    return templates.TemplateResponse("index.html", context)
```

`app.mount`の`path引数`を "/static" として指定した場合、HTML内の静的ファイルへのリンクは次のようになります。
```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <title>My App</title>
    <link rel="stylesheet" href="/static/css/styles.css">
  </head>
  <body>
    <script src="/static/js/script.js"></script>
  </body>
</html>
```
アプリケーションを起動して、

```:
uvicorn main:app --reload
```

`http://127.0.0.1:8000/static/js/script.js`にアクセスするとファイルの中身が表示されるはずです。
また、cssやjavascriptに記載したコードも適用されていると思います。

## コードの説明
### マウント
```python:app.mount
app.mount("/static", StaticFiles(directory="static"), name="static")
```
このコードはFastAPIのルーティングで、`"/static"`というURLパスがリクエストされた場合に、"static"というディレクトリ内の静的ファイルを提供するために使用します。
ここでは、"static"ディレクトリ内のファイルを提供するように指定しています。

`name="static`は、FastAPI が内部で使用できる名前を付けます。
jinja2の`url_for`を用いてhtmlにcssやjavascript等の読み込みでよく取り沙汰されていますが、構文が長いし使わなくても読み込めるので今回は使いません。
`name="static_name"`にした場合、htmlではこう呼ぶ↓
```html:html例
<link rel="stylesheet" href="{{ url_for('static_name', path='/style/style.css') }}">
```
***
### Jinja2 テンプレート
```python:templates
templates = Jinja2Templates(directory="templates")
```
Jinja2テンプレートを使用するには、Jinja2Templatesクラスをインスタンス化する必要があります。
directory引数には、Jinja2テンプレートが保存されているディレクトリのパスを指定します。
***
### パス操作
```python:main.py
@app.get("/", response_class=HTMLResponse)
async def read_root(request: Request):
    context = {"request": request}
    return templates.TemplateResponse("index.html", context)
```
`@app.get("/")`は、FastAPIにおいてGETリクエストを受け付けるエンドポイントのデコレーターを設定している部分で、"/"はエンドポイントのパスを指定しています。

`response_class=HTMLResponse`は、レスポンスの形式をHTML形式に指定しています。

`async def read_root(request: Request)`は、関数定義であり、asyncを付けることで非同期関数として定義しています。requestはHTTPリクエストのデータを受け取るためのパラメーターであり、Requestクラスを指定しています。

`context = {"request": request}`は、テンプレートエンジンであるJinja2に渡すコンテキストの辞書型変数を定義しています。ここではrequestを含めています。

`return templates.TemplateResponse("index.html", context)`は、Jinja2テンプレートエンジンを使ってHTMLを生成するためのレスポンスを返す部分です。
TemplateResponseはFastAPIが提供するレスポンスクラスの1つで、"index.html"はHTMLテンプレートのファイル名を指定しています。
contextはテンプレートに渡すデータの辞書型変数を指定しています。
***
以上が、FastAPIでJinja2を使用してHTMLを返し、CSSとJavaScriptを読み込む方法でした。