【FastAPI】テンプレートエンジンを使ってHTML・CSSを配信

FastAPIを使用してJSONではなく、テンプレートエンジンを用いてHTMLやCSSを返す方法をご紹介いたします。


FastAPIの基礎についての記事まとめ
テンプレートエンジン
テンプレートエンジンはjinjaを用います。
jinja2とは「python用の、htmlを動的作成できるテンプレートエンジン」です。
djangoやflaskでも用いられている一般的なもので、データベースの値を埋め込んだり、ifやfor文などもテンプレートに埋め込めます。
https://jinja.palletsprojects.com/en/3.0.x/
例えば、下記のようにhtmlファイルを記述できます。
<h1>Hello {{ name }}</h1>
{% if name %} is_name {% endif %}
{% for object in object_list %}
{{ object }}
{% endfor %}pip install jinja2テンプレートの作成
まずは、テンプレート用のディレクトリを作成します。
ここでは、templates/とします。ここにhtmlやcssファイルを保管していきます。
Jinja2Templatesとは?
router/templates.pyにJinja2Templatesのインスタンスを作成します。
from fastapi.templating import Jinja2Templates
~~~
templates = Jinja2Templates(directory='templates')先程作成したtemplatesディレクトリを指定しています。
簡単なエンドポイントの作成
まずは基本的なエンドポイントから作成します。
response_classにはHTMLResponseを指定しており、返り値には
product.html- テンプレートに渡す値
を渡しています。

from fastapi.responses import HTMLResponse
from fastapi.requests import Request
~~~
@router.get("/products/{id}", response_class=HTMLResponse)
def get_product(id: str, request: Request):
return templates.TemplateResponse(
"product.html",
{
"request": request,
"id": id
}
)product.htmlには下記のような簡単なhtmlを作成しました。
<div>Product ID is {{ id }}</div>{{ id }}はテンプレートタグと呼ばれており、返り値のidに対応しています。
https://jinja.palletsprojects.com/en/3.0.x/templates/
確認してみましょう。

Response bodyの値を確認すると、無事値が埋め込まれていることが確認できました。
POSTされた値を利用
より実践的な内容で、POSTで受け取ったから値をテンプレートに記述してみます。
まずは、schemas.pyを作成してBaseModelの型を作成します。


from pydantic import BaseModel
class ProductBase(BaseModel):
title: str
description: str
price: floatりクエストボディの型を作成し、受け取った値をテンプレートに記述できるように追加しました。
@router.post("/products/{id}", response_class=HTMLResponse)
def get_product(id: str, product: ProductBase ,request: Request):
return templates.TemplateResponse(
"product_post.html",
{
"request": request,
"id": id,
"title": product.description,
"price": product.price
}
)指定したhtmlファイルの中身は下記になります。
<div>
<li>id : {{ id }}</li>
<li>title : {{ title }}</li>
<li>price : {{ price }}</li>
</div>実際にAPIを確認してみましょう。

うまく反映されていますね。

テンプレートの値は、下記の様にまとめることも可能です。
@router.post("/products/{id}", response_class=HTMLResponse)
def get_product(id: str, product: ProductBase ,request: Request):
return templates.TemplateResponse(
"product_post.html",
{
"request": request,
"id": id,
"product": product
}
)<div>
<li>id : {{ id }}</li>
<li>title : {{ product.title }}</li>
<li>price : {{ product.price }}</li>
</div>CSSファイルなどの静的ファイルの配信
htmlファイルだけではなくcssファイルも一緒に配信するには静的ファイルを配信できるようにします。

main.pyにtemplates/static以下を配信できるように設定しました。
from fastapi.staticfiles import StaticFiles
~~~
app.mount(
'/templates/static',
StaticFiles(directory="templates/static"),
name='static'
)
templates/static配下にcssファイルを作成して反映させてみましょう。
product_post.htmlとproduct.cssを編集します。
<head>
<link rel="stylesheet" href="{{ url_for('static', path='/product.css') }}">
</head>
<div class="list">
<li>id : {{ id }}</li>
<li>title : {{ product.title }}</li>
<li>price : {{ product.price }}</li>
</div>href=にはファイルパスを指定しています。
.list {
background-color: red;
}実際に確認します。

受けとったレスポンスを確認してみましょう。CSSが反映されていればOKです。
htmlのプレビューは下記サイトで行いました。
https://htmledit.squarefree.com/

無事反映されていますね!
この他にもデータベースの値を持ってきたり、テンプレート内でfor文やif文での処理も可能です。
データベースとの連携も、CRUD処理での値を持ってくるだけです。


FastAPIの基礎についての記事まとめ

コメント