Skip to content

Commit 2756472

Browse files
Move htmx.py into core
1 parent 1c3dac3 commit 2756472

11 files changed

Lines changed: 13 additions & 13 deletions

File tree

docs/architecture.qmd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ description: "Overview of the FastAPI webapp template architecture including dat
88
This application uses a **hybrid Post-Redirect-Get (PRG) + HTMX** architecture. Every mutating endpoint supports both paths simultaneously:
99

1010
- **Non-HTMX path (PRG):** A standard browser form submission sends a POST request. On success the server issues a `303 See Other` redirect to a GET endpoint, which re-renders the full page with updated data. On error a full-page error template is returned.
11-
- **HTMX path:** When the browser sends the `HX-Request: true` header (added automatically by [htmx.org](https://htmx.org)), the same POST endpoint detects the header via `utils/htmx.py:is_htmx_request()` and instead returns a `200` HTML partial that HTMX swaps into the relevant section of the page. On error a toast partial is returned and swapped into `#toast-container` via out-of-band (OOB) swap.
11+
- **HTMX path:** When the browser sends the `HX-Request: true` header (added automatically by [htmx.org](https://htmx.org)), the same POST endpoint detects the header via `utils/core/htmx.py:is_htmx_request()` and instead returns a `200` HTML partial that HTMX swaps into the relevant section of the page. On error a toast partial is returned and swapped into `#toast-container` via out-of-band (OOB) swap.
1212

1313
The HTMX rollout keeps the existing POST route contract intact — dedicated `PUT`/`PATCH`/`DELETE` routes may be introduced in a future iteration.
1414

@@ -129,7 +129,7 @@ Toast partials are rendered from `templates/base/partials/toast.html` and inject
129129

130130
### HTMX request detection
131131

132-
All HTMX-aware endpoints use the `is_htmx_request()` helper from `utils/htmx.py`:
132+
All HTMX-aware endpoints use the `is_htmx_request()` helper from `utils/core/htmx.py`:
133133

134134
```python
135135
def is_htmx_request(request: Request) -> bool:

docs/customization.qmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ Middleware functions are decorated with `@app.exception_handler(ExceptionType)`
173173
Here's a middleware for handling the `PasswordValidationError` exception, which returns a toast partial for HTMX requests or a full error page for non-HTMX requests:
174174

175175
```python
176-
from utils.htmx import is_htmx_request
176+
from utils.core.htmx import is_htmx_request
177177

178178
@app.exception_handler(PasswordValidationError)
179179
async def password_validation_exception_handler(request: Request, exc: PasswordValidationError):

docs/static/documentation.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ description: "Overview of the FastAPI webapp template architecture including dat
229229
This application uses a **hybrid Post-Redirect-Get (PRG) + HTMX** architecture. Every mutating endpoint supports both paths simultaneously:
230230

231231
- **Non-HTMX path (PRG):** A standard browser form submission sends a POST request. On success the server issues a `303 See Other` redirect to a GET endpoint, which re-renders the full page with updated data. On error a full-page error template is returned.
232-
- **HTMX path:** When the browser sends the `HX-Request: true` header (added automatically by [htmx.org](https://htmx.org)), the same POST endpoint detects the header via `utils/htmx.py:is_htmx_request()` and instead returns a `200` HTML partial that HTMX swaps into the relevant section of the page. On error a toast partial is returned and swapped into `#toast-container` via out-of-band (OOB) swap.
232+
- **HTMX path:** When the browser sends the `HX-Request: true` header (added automatically by [htmx.org](https://htmx.org)), the same POST endpoint detects the header via `utils/core/htmx.py:is_htmx_request()` and instead returns a `200` HTML partial that HTMX swaps into the relevant section of the page. On error a toast partial is returned and swapped into `#toast-container` via out-of-band (OOB) swap.
233233

234234
The HTMX rollout keeps the existing POST route contract intact — dedicated `PUT`/`PATCH`/`DELETE` routes may be introduced in a future iteration.
235235

@@ -350,7 +350,7 @@ Toast partials are rendered from `templates/base/partials/toast.html` and inject
350350

351351
### HTMX request detection
352352

353-
All HTMX-aware endpoints use the `is_htmx_request()` helper from `utils/htmx.py`:
353+
All HTMX-aware endpoints use the `is_htmx_request()` helper from `utils/core/htmx.py`:
354354

355355
```python
356356
def is_htmx_request(request: Request) -> bool:
@@ -843,7 +843,7 @@ Middleware functions are decorated with `@app.exception_handler(ExceptionType)`
843843
Here's a middleware for handling the `PasswordValidationError` exception, which returns a toast partial for HTMX requests or a full error page for non-HTMX requests:
844844

845845
```python
846-
from utils.htmx import is_htmx_request
846+
from utils.core.htmx import is_htmx_request
847847

848848
@app.exception_handler(PasswordValidationError)
849849
async def password_validation_exception_handler(request: Request, exc: PasswordValidationError):

main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
require_unauthenticated_client
1414
)
1515
from utils.core.auth import COOKIE_SECURE
16-
from utils.htmx import is_htmx_request, toast_response
16+
from utils.core.htmx import is_htmx_request, toast_response
1717
from exceptions.http_exceptions import (
1818
AlreadyAuthenticatedError,
1919
AuthenticationError,

routers/core/account.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
check_forgot_password_email_rate_limit,
5252
login_email_limiter,
5353
)
54-
from utils.htmx import is_htmx_request, toast_response, set_flash_cookie
54+
from utils.core.htmx import is_htmx_request, toast_response, set_flash_cookie
5555
logger = getLogger("uvicorn.error")
5656

5757
router = APIRouter(prefix="/account", tags=["account"])

routers/core/invitation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
InvalidInvitationTokenError,
2121
)
2222
from exceptions.exceptions import EmailSendFailedError
23-
from utils.htmx import is_htmx_request, append_toast
23+
from utils.core.htmx import is_htmx_request, append_toast
2424
# Import the account router to generate URLs for login/register
2525
from routers.core.account import router as account_router
2626
from routers.core.organization import router as org_router # Already imported, check usage

routers/core/organization.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
UserNotFoundError, UserAlreadyMemberError, DataIntegrityError
1616
)
1717
from pydantic import EmailStr
18-
from utils.htmx import is_htmx_request, set_flash_cookie
18+
from utils.core.htmx import is_htmx_request, set_flash_cookie
1919

2020
logger = getLogger("uvicorn.error")
2121

routers/core/role.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from utils.core.models import Role, Permission, ValidPermissions, utc_now, User, DataIntegrityError, Organization
1313
from exceptions.http_exceptions import InsufficientPermissionsError, InvalidPermissionError, RoleAlreadyExistsError, RoleNotFoundError, RoleHasUsersError, CannotModifyDefaultRoleError
1414
from routers.core.organization import router as organization_router
15-
from utils.htmx import is_htmx_request, append_toast
15+
from utils.core.htmx import is_htmx_request, append_toast
1616

1717
logger = getLogger("uvicorn.error")
1818

routers/core/user.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
OrganizationNotFoundError
1515
)
1616
from routers.core.organization import router as organization_router
17-
from utils.htmx import is_htmx_request, append_toast
17+
from utils.core.htmx import is_htmx_request, append_toast
1818

1919
router = APIRouter(prefix="/user", tags=["user"])
2020
templates = Jinja2Templates(directory="templates")

tests/test_htmx.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from starlette.requests import Request
1212
from fastapi.templating import Jinja2Templates
1313
from tests.conftest import htmx_headers
14-
from utils.htmx import is_htmx_request, toast_response, append_toast
14+
from utils.core.htmx import is_htmx_request, toast_response, append_toast
1515
from utils.core.rate_limit import (
1616
login_ip_limiter,
1717
login_email_limiter,

0 commit comments

Comments
 (0)