Skip to content

Commit 332722c

Browse files
authored
Merge pull request #13 from volfpeter/docs/custom-applications-guide
Add custom applications guide
2 parents 434300b + 34c1a00 commit 332722c

File tree

5 files changed

+83
-2
lines changed

5 files changed

+83
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ If you prefer to learn through examples, the [Quick start guide](https://volfpet
7676

7777
To learn about creating rendering APIs and adding HTMX to your application, you should have a look at the [Rendering APIs with HTMX](https://volfpeter.github.io/holm/rendering-apis-with-htmx) guide.
7878

79+
The [Custom applications](https://volfpeter.github.io/holm/custom-applications) guide shows you how to customize the FastAPI application instance as well as HTML rendering.
80+
7981
For error handling examples, you should check out the [Error Handling](https://volfpeter.github.io/holm/error-handling) guide.
8082

8183
You can discover even more features by exploring the [test application](https://github.com/volfpeter/holm/tree/main/test_app) of the project.

docs/custom-applications.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Custom applications
2+
3+
This guide demonstrates how to use a custom FastAPI application and `fasthx.htmy.HTMY` instance (HTML renderer) in your `holm` application. This allows you to leverage `holm`'s features while keeping full control over all underlying software components.
4+
5+
In the vast majority of applications, using a default FastAPI application (one created by simply calling `FastAPI()`, as `holm` internally does) is not enough. Exception handlers, for example, can be registered with `holm`, but you often need to set up a lifespan method, register middlewares, or customize the OpenAPI documentation to your needs. As a matter of fact, you could even add routes to your application manually, just make sure their paths don't conflict with the routes `holm` registers for you automatically!
6+
7+
When it comes to HTML rendering, you may occasionally need to configure the `fasthx.htmy.HTMY` instance with [custom request processors](https://volfpeter.github.io/fasthx/examples/htmy/), formatters, translation utilities, or global rendering context.
8+
9+
Doing all of this in `holm` is very straightforward, all you need to do is:
10+
11+
1. Create a `FastAPI` instance somewhere in your codebase and configure it, just like you would do in any FastAPI project.
12+
2. Create a `fasthx.htmy.HTMY` instance and configure it.
13+
3. Pass the created instances to the `holm.App()` function as `App(app=my_fastapi_instance, htmy=my_htmy_instance)`.
14+
15+
The below example demonstrates these steps as simply as possible, through creating:
16+
17+
- a `FastAPI` instance with a `/health-check` route, and
18+
- a `fasthx.htmy.HTMY` instance with a request processor.
19+
20+
If you followed the [quick-start-guide](quick-start-guide.md), then you can make these changes in the `main.py` file and immediately see the result in action.
21+
22+
```python
23+
from fastapi import FastAPI
24+
from fasthx.htmy import HTMY
25+
26+
from holm import App
27+
28+
app = FastAPI()
29+
htmy = HTMY(
30+
request_processors=[
31+
# Add a request processor that inserts an "is_htmx_request" key
32+
# into htmy rendering contexts, making this information available
33+
# to htmy components as `context["is_htmx_request"]`.
34+
lambda request: {"is_htmx_request": request.headers.get("HX-Request") == "true"}
35+
]
36+
)
37+
38+
39+
@app.get("/health-check")
40+
def health_check() -> dict[str, str]:
41+
"""Health check route registered directly on the FastAPI application."""
42+
return {"status": "ok"}
43+
44+
45+
# If holm.App() receives a FastAPI application instance, then it does its job and
46+
# returns the same object. This means you don't need to keep a separate reference
47+
# to the returned value, the already existing app variable is enough.
48+
App(app=app, htmy=htmy)
49+
```
50+
51+
That's it! If you start the application and open its OpenAPI documentation (`http://localhost:8000/docs`) in your browser, you will see the health check route you registered, in addition to all the routes `holm` discovered and registered automatically for you.
52+
53+
Note: If you return a `htmy` component from a manually registered route, it will **not** be rendered as HTML automatically! The reason for this is simple: `holm` must not modify the behavior of user-defined application parts in any way. You can still do HTML rendering manually using the `htmy` instance in the same way as in `holm` API modules (see the [Rendering APIs with HTMX guide](rendering-apis-with-htmx.md)).

docs/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ If you prefer to learn through examples, the [Quick start guide](quick-start-gui
6767

6868
To learn about creating rendering APIs and adding HTMX to your application, you should have a look at the [Rendering APIs with HTMX](rendering-apis-with-htmx.md) guide.
6969

70+
The [Custom applications](custom-applications.md) guide shows you how to customize the FastAPI application instance as well as HTML rendering.
71+
7072
For error handling examples, you should check out the [Error Handling](error-handling.md) guide.
7173

7274
You can discover even more features by exploring the [test application](https://github.com/volfpeter/holm/tree/main/test_app) of the project.

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,6 @@ nav:
4747
- Guides:
4848
- quick-start-guide.md
4949
- rendering-apis-with-htmx.md
50+
- custom-applications.md
5051
- error-handling.md
5152
- API Reference: api.md

test_app/main.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1-
from holm.app import App
1+
from fastapi import FastAPI
2+
from fasthx.htmy import HTMY
23

3-
app = App()
4+
from holm import App
5+
6+
app = FastAPI()
7+
htmy = HTMY(
8+
request_processors=[
9+
# Add a request processor that inserts an "is_htmx_request" key
10+
# into htmy rendering contexts, making this information available
11+
# to htmy components as `context["is_htmx_request"]`.
12+
lambda request: {"is_htmx_request": request.headers.get("HX-Request") == "true"}
13+
]
14+
)
15+
16+
17+
@app.get("/health-check")
18+
def health_check() -> dict[str, str]:
19+
"""Health check route registered directly on the FastAPI application."""
20+
return {"status": "ok"}
21+
22+
23+
# If holm.App() receives a FastAPI application instance, then it does its job and
24+
# returns the same object. This means you don't need to keep a separate reference
25+
# to the returned value, the already existing app variable is enough.
26+
App(app=app, htmy=htmy)

0 commit comments

Comments
 (0)