FastAPI¶
PyJinHx integrates seamlessly with FastAPI for building web applications with server-side rendered components.
Setup¶
Install the required packages:
Project Structure¶
my_app/
├── components/
│ └── ui/
│ ├── button.py
│ ├── button.html
│ ├── card.py
│ └── card.html
├── main.py
└── pyproject.toml
Basic Example¶
Component Class¶
# components/ui/button.py
from pyjinhx import BaseComponent
class Button(BaseComponent):
id: str
text: str
variant: str = "primary"
Component Template¶
<!-- components/ui/button.html -->
<button
id="{{ id }}"
class="btn btn-{{ variant }}"
>
{{ text }}
</button>
FastAPI App¶
# main.py
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from pyjinhx import Renderer
from components.ui.button import Button
# Configure template path
Renderer.set_default_environment("./components")
app = FastAPI()
@app.get("/", response_class=HTMLResponse)
def index() -> str:
return f"""
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<style>
.btn {{
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
}}
.btn-primary {{
background: #007bff;
color: white;
}}
.btn-secondary {{
background: #6c757d;
color: white;
}}
</style>
</head>
<body>
<h1>Welcome</h1>
{Button(id="submit-btn", text="Submit", variant="primary").render()}
{Button(id="cancel-btn", text="Cancel", variant="secondary").render()}
</body>
</html>
"""
Run with:
Card Component Example¶
A more complete example with nested components.
Card Component¶
# components/ui/card.py
from pyjinhx import BaseComponent
class Card(BaseComponent):
id: str
title: str
content: str
<!-- components/ui/card.html -->
<div id="{{ id }}" class="card">
<div class="card-header">
<h3>{{ title }}</h3>
</div>
<div class="card-body">
<p>{{ content }}</p>
</div>
</div>
FastAPI Routes¶
from components.ui.card import Card
@app.get("/dashboard", response_class=HTMLResponse)
def dashboard() -> str:
cards = [
Card(
id="card-1",
title="Users",
content="Total users: 1,234"
),
Card(
id="card-2",
title="Revenue",
content="Total revenue: $45,678"
),
Card(
id="card-3",
title="Orders",
content="Total orders: 567"
),
]
cards_html = "\n".join([card.render() for card in cards])
return f"""
<!DOCTYPE html>
<html>
<head>
<title>Dashboard</title>
<style>
.card {{
border: 1px solid #ddd;
border-radius: 8px;
padding: 1rem;
margin: 1rem 0;
}}
.card-header h3 {{
margin: 0 0 0.5rem 0;
}}
</style>
</head>
<body>
<h1>Dashboard</h1>
{cards_html}
</body>
</html>
"""
Using Jinja Templates¶
For larger applications, combine PyJinHx components with Jinja2 base templates:
from jinja2 import Environment, FileSystemLoader
from pyjinhx import Renderer
env = Environment(loader=FileSystemLoader("./templates"))
Renderer.set_default_environment(env)
@app.get("/", response_class=HTMLResponse)
def index():
template = env.get_template("index.html")
return template.render(
button=Button(id="main-btn", text="Click Me"),
card=Card(id="main-card", title="Welcome", content="Hello, World!")
)
<!-- templates/index.html -->
{% extends "base.html" %}
{% block content %}
<h1>My App</h1>
{{ card }}
{{ button }}
{% endblock %}
<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My App{% endblock %}</title>
{% block head %}{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
Tips¶
Component JavaScript¶
Components can include JavaScript files that are automatically collected:
# components/ui/modal.py
class Modal(BaseComponent):
id: str
title: str
content: str
js: list[str] = ["components/ui/modal.js"]
The JavaScript file will be automatically injected when the component is rendered.
Form Handling¶
Use FastAPI's form handling with PyJinHx components:
from fastapi import Form
@app.post("/submit", response_class=HTMLResponse)
def submit_form(
name: str = Form(...),
email: str = Form(...)
) -> str:
# Process form data
return f"""
<div class="success">
<p>Thank you, {name}!</p>
<p>We'll contact you at {email}.</p>
</div>
"""
Response Types¶
FastAPI's HTMLResponse works seamlessly with PyJinHx's render() method, which returns Markup objects that are automatically converted to strings.