Skip to content

FastAPI

PyJinHx integrates seamlessly with FastAPI for building web applications with server-side rendered components.

Setup

Install the required packages:

pip install fastapi uvicorn pyjinhx

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:

uvicorn main:app --reload

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.