You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-**Correct typing** makes it possible to apply other (typed) decorators to your routes.
23
23
- Works with both **sync** and **async routes**.
24
24
25
+
## Testimonials
26
+
27
+
"Thank you for your work on `fasthx`, as well as `htmy`! I've never had an easier time developing with another stack." ([ref](https://github.com/volfpeter/fasthx/discussions/77))
28
+
29
+
"One of the main parts of the `FastAPI` -> `fasthx` -> `htmy` integration I'm falling in love with is its explicitness, and not too much magic happening." ([ref](https://github.com/volfpeter/fasthx/issues/54))
30
+
31
+
"Thank you for your work on `htmy` and `fasthx`, both have been very pleasant to use, and the APIs are both intuitive and simple. Great work." ([ref](https://github.com/volfpeter/fasthx/issues/54))
32
+
25
33
## Support
26
34
27
35
Consider supporting the development and maintenance of the project through [sponsoring](https://buymeacoffee.com/volfpeter), or reach out for [consulting](https://www.volfp.com/contact?subject=Consulting%20-%20FastHX) so you can get the most out of the library.
@@ -41,10 +49,9 @@ The package has optional dependencies for the following **official integrations*
41
49
42
50
## Core concepts
43
51
44
-
The core concept of FastHX is to let FastAPI routes do their usual job of handling the business logic and returning the result, while the FastHX decorators take care
45
-
of the entire rendering / presentation layer using a declarative, decorator-based approach.
52
+
The core concept of FastHX is to let FastAPI routes do their usual job of handling the business logic and returning the result, while the FastHX decorators take care of the entire rendering and presentation layer using a declarative, decorator-based approach.
46
53
47
-
Interally, FastHX decorators always have access to the decorated route's result, all of its arguments (sometimes called the request context), and the current request. Integrations convert these values into data that can be consumed by the used rendering engine (for example `htmy` or `jinja`), run the rendering engine with the selected component (more on this below) and the created data, and return the result to the client. For more details on how data conversion works and how it can be customized, please see the API documentation of the rendering engine integration of your choice.
54
+
Internally, FastHX decorators always have access to the decorated route's result, all of its arguments (sometimes called the request context), and the current request. Integrations convert these values into data that can be consumed by the used rendering engine (for example `htmy` or `jinja`), run the rendering engine with the selected component (more on this below) and the created data, and return the result to the client. For more details on how data conversion works and how it can be customized, please see the API documentation of the rendering engine integration of your choice.
48
55
49
56
The `ComponentSelector` abstraction makes it possible to declaratively specify and dynamically select the component that should be used to render the response to a given request. It is also possible to define an "error" `ComponentSelector` that is used if the decorated route raises an exception -- a typical use-case being error rendering for incorrect user input.
50
57
@@ -98,12 +105,12 @@ def index() -> None: ...
98
105
99
106
Requires: `pip install fasthx[jinja]`.
100
107
101
-
To start serving HTML and HTMX requests, all you need to do is create an instance of `fasthx.Jinja` and use its `hx()` or `page()` methods as decorators on your routes. `hx()` only triggers HTML rendering for HTMX requests, while `page()` unconditionally renders HTML. See the example code below:
108
+
To start serving HTML and HTMX requests, all you need to do is create an instance of `fasthx.jinja.Jinja` and use its `hx()` or `page()` methods as decorators on your routes. `hx()` only triggers HTML rendering for HTMX requests, while `page()` unconditionally renders HTML. See the example code below:
102
109
103
110
```python
104
111
from fastapi import FastAPI
105
112
from fastapi.templating import Jinja2Templates
106
-
from fasthx import Jinja
113
+
from fasthx.jinjaimport Jinja
107
114
from pydantic import BaseModel
108
115
109
116
# Pydantic model of the data the example API is using.
@@ -145,7 +152,7 @@ See the full working example [here](https://github.com/volfpeter/fasthx/tree/mai
145
152
146
153
Requires: `pip install fasthx`.
147
154
148
-
If you would like to use a rendering engine without FastHX integration, you can easily build on the `hx()` and `page()` decorators which give you all the functionality you will need. All you need to do is implement the `HTMLRenderer` protocol.
155
+
If you would like to use a rendering engine without FastHX integration, you can easily build on the `hx()` and `page()` decorators which give you all the functionality you will need. All you need to do is implement the `RenderFunction` protocol.
149
156
150
157
Similarly to the Jinja case, `hx()` only triggers HTML rendering for HTMX requests, while `page()` unconditionally renders HTML. See the example code below:
151
158
@@ -158,7 +165,7 @@ from fasthx import hx, page
158
165
# Create the app.
159
166
app = FastAPI()
160
167
161
-
# Create a dependecy to see that its return value is available in the render function.
168
+
# Create a dependency to see that its return value is available in the render function.
Copy file name to clipboardExpand all lines: docs/examples/custom-templating.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Custom Templating
2
2
3
-
If you're not into Jinja templating, the `hx()` and `page()` decorators give you all the flexibility you need: you can integrate any HTML rendering or templating engine into `fasthx` simply by implementing the `HTMLRenderer` protocol. Similarly to the Jinja case, `hx()` only triggers HTML rendering for HTMX requests, while `page()` unconditionally renders HTML. See the example code below:
3
+
If you're not into Jinja templating, the `hx()` and `page()` decorators give you all the flexibility you need: you can integrate any HTML rendering or templating engine into `fasthx` simply by implementing the `RenderFunction` protocol. Similarly to the Jinja case, `hx()` only triggers HTML rendering for HTMX requests, while `page()` unconditionally renders HTML. See the example code below:
4
4
5
5
```python
6
6
from typing import Annotated, Any
@@ -11,7 +11,7 @@ from fasthx import hx, page
11
11
# Create the app.
12
12
app = FastAPI()
13
13
14
-
# Create a dependecy to see that its return value is available in the render function.
14
+
# Create a dependency to see that its return value is available in the render function.
Copy file name to clipboardExpand all lines: docs/examples/htmy.md
+38-47Lines changed: 38 additions & 47 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,13 +8,13 @@ First, let's create an `htmy_app.py` file, import everything that is required fo
8
8
import random
9
9
from dataclasses import dataclass
10
10
from datetime import date
11
+
from typing import Any
11
12
12
13
from fastapi import FastAPI
14
+
from fasthx.htmy importHTMY, ComponentHeader, CurrentRequest, RouteParams
13
15
from htmy import Component, Context, html
14
16
from pydantic import BaseModel
15
17
16
-
from fasthx.htmy importHTMY, ComponentHeader, CurrentRequest, RouteParams
17
-
18
18
19
19
classUser(BaseModel):
20
20
"""User model."""
@@ -23,24 +23,19 @@ class User(BaseModel):
23
23
birthday: date
24
24
```
25
25
26
-
The main content on the user interface will be a user list, so let's start by creating a simple `UserListItem` component:
26
+
The main content on the user interface will be a user list, so let's start by creating a simple `user_list_item` component factory (see the [htmy components guide](https://volfpeter.github.io/htmy/components-guide/) for more information):
@@ -107,37 +102,33 @@ Most of this code is basic Python and `htmy` usage (including the `hx_*` `HTMX`
107
102
- The use of `RouteParams.from_context()` to get access to every route parameter (resolved FastAPI dependency) as a mapping.
108
103
- The `context["user-agent"]` lookup that accesses a value from the context which will be added by a _request processor_ later in the example.
109
104
110
-
We need one last `htmy` component, the index page. Most of this component is just the basic HTML document structure with some TailwindCSS styling and metadata. There is also a bit of `HTMX` in the `body` for lazy loading the actual page content, the user list we just created.
105
+
We need one last `htmy` component, the index page. Most of this component (component factory to be more precise) is just the basic HTML document structure with some TailwindCSS styling and metadata. There is also a bit of `HTMX` in the `body` for lazy loading the actual page content, the user list we just created.
With all the components ready, we can now create the `FastAPI` and `fasthx.htmy.HTMY` instances:
@@ -159,11 +150,11 @@ Note how we added a _request processor_ function to the `HTMY` instance that tak
159
150
160
151
All that remains now is the routing. We need two routes: one that serves the index page, and one that renders the ordered or unordered user list.
161
152
162
-
The index page route is trivial. The `htmy.page()` decorator expects a component factory (well more precisely a `fasthx.ComponentSelector`) that accepts the route's return value and returns an `htmy` component. Since `IndexPage` has no properties, we use a simple `lambda` to create such a function:
153
+
The index page route is trivial. The `htmy.page()` decorator expects a component factory (well more precisely a `fasthx.ComponentSelector`) that accepts the route's return value and returns an `htmy` component. `index_page` is implemented exactly like this, so we can use it directly in the decorator:
Copy file name to clipboardExpand all lines: docs/examples/jinja-templating.md
+5-6Lines changed: 5 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,12 +2,12 @@
2
2
3
3
## Basics
4
4
5
-
To start serving HTML and HTMX requests, all you need to do is create an instance of `fasthx.Jinja` and use its `hx()` or `page()` methods as decorators on your routes. `hx()` only triggers HTML rendering for HTMX requests, while `page()` unconditionally renders HTML, saving you some boilerplate code. See the example code below:
5
+
To start serving HTML and HTMX requests, all you need to do is create an instance of `fasthx.jinja.Jinja` and use its `hx()` or `page()` methods as decorators on your routes. `hx()` only triggers HTML rendering for HTMX requests, while `page()` unconditionally renders HTML, saving you some boilerplate code. See the example code below:
6
6
7
7
```python
8
8
from fastapi import FastAPI
9
9
from fastapi.templating import Jinja2Templates
10
-
from fasthx import Jinja
10
+
from fasthx.jinjaimport ComponentHeader, Jinja
11
11
from pydantic import BaseModel
12
12
13
13
# Pydantic model of the data the example API is using.
In the basic example, routes always rendered a fixed HTML template. `TemplateHeader` lifts this restriction by letting the client submit the _key_ of the required template,
49
-
automatically looking up the corresponding template, and of course rendering it.
48
+
In the basic example, routes always rendered a fixed HTML template. `ComponentHeader` lifts this restriction by letting the client submit the _key_ of the required template, automatically looking up the corresponding template, and of course rendering it.
50
49
51
50
This can be particularly helpful when multiple templates/UI components require the same data and business logic.
0 commit comments