|
| 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)). |
0 commit comments