fasthx


Namefasthx JSON
Version 0.2403.1 PyPI version JSON
download
home_pageNone
SummaryFastAPI data APIs with HTMX support.
upload_time2024-03-26 19:57:16
maintainerNone
docs_urlNone
authorPeter Volf
requires_python<4.0,>=3.10
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ![Tests](https://github.com/volfpeter/fasthx/actions/workflows/tests.yml/badge.svg)
![Linters](https://github.com/volfpeter/fasthx/actions/workflows/linters.yml/badge.svg)
![Documentation](https://github.com/volfpeter/fasthx/actions/workflows/build-docs.yml/badge.svg)
![PyPI package](https://img.shields.io/pypi/v/fasthx?color=%2334D058&label=PyPI%20Package)

**Source code**: [https://github.com/volfpeter/fasthx](https://github.com/volfpeter/fasthx)

**Documentation and examples**: [https://volfpeter.github.io/fasthx](https://volfpeter.github.io/fasthx/)

# FastHX

FastAPI and HTMX, the right way.

Key features:

- **Decorator syntax** that works with FastAPI as one would expect, no need for unused or magic dependencies in routes.
- Works with **any templating engine** or server-side rendering library, e.g. `markyp-html` or `dominate`.
- Built-in **Jinja2 templating support** (even with multiple template folders).
- Gives the rendering engine **access to all dependencies** of the decorated route.
- FastAPI **routes will keep working normally by default** if they receive **non-HTMX** requests, so the same route can serve data and render HTML at the same time.
- **Response headers** you set in your routes are kept after rendering, as you would expect in FastAPI.
- **Correct typing** makes it possible to apply other (typed) decorators to your routes.
- Works with both **sync** and **async routes**.

## Installation

The package is available on PyPI and can be installed with:

```console
$ pip install fasthx
```

## Examples

For complete examples, please see the [examples](https://github.com/volfpeter/fasthx/tree/main/examples) folder.

### Jinja2 templating

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:

```python
from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
from fasthx import Jinja
from pydantic import BaseModel

# Pydantic model of the data the example API is using.
class User(BaseModel):
    first_name: str
    last_name: str

# Create the app.
app = FastAPI()

# Create a FastAPI Jinja2Templates instance and use it to create a
# FastHX Jinja instance that will serve as your decorator.
jinja = Jinja(Jinja2Templates("templates"))

@app.get("/")
@jinja.page("index.html")
def index() -> None:
    ...

@app.get("/user-list")
@jinja.hx("user-list.html")
async def htmx_or_data() -> list[User]:
    return [
        User(first_name="John", last_name="Lennon"),
        User(first_name="Paul", last_name="McCartney"),
        User(first_name="George", last_name="Harrison"),
        User(first_name="Ringo", last_name="Starr"),
    ]

@app.get("/admin-list")
@jinja.hx("user-list.html", no_data=True)
def htmx_only() -> list[User]:
    return [User(first_name="Billy", last_name="Shears")]
```

### Custom templating

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:

```python
from typing import Annotated, Any

from fastapi import Depends, FastAPI, Request
from fasthx import hx, page

# Create the app.
app = FastAPI()

# Create a dependecy to see that its return value is available in the render function.
def get_random_number() -> int:
    return 4  # Chosen by fair dice roll.

DependsRandomNumber = Annotated[int, Depends(get_random_number)]

# Create the render methods: they must always have these three arguments.
# If you're using static type checkers, the type hint of `result` must match
# the return type annotation of the route on which this render method is used.
def render_index(result: list[dict[str, str]], *, context: dict[str, Any], request: Request) -> str:
    return "<h1>Hello FastHX</h1>"

def render_user_list(result: list[dict[str, str]], *, context: dict[str, Any], request: Request) -> str:
    # The value of the `DependsRandomNumber` dependency is accessible with the same name as in the route.
    random_number = context["random_number"]
    lucky_number = f"<h1>{random_number}</h1>"
    users = "".join(("<ul>", *(f"<li>{u['name']}</li>" for u in result), "</ul>"))
    return f"{lucky_number}\n{users}"

@app.get("/")
@page(render_index)
def index() -> None:
    ...

@app.get("/htmx-or-data")
@hx(render_user_list)
def htmx_or_data(random_number: DependsRandomNumber) -> list[dict[str, str]]:
    return [{"name": "Joe"}]

@app.get("/htmx-only")
@hx(render_user_list, no_data=True)
async def htmx_only(random_number: DependsRandomNumber) -> list[dict[str, str]]:
    return [{"name": "Joe"}]
```

## Dependencies

The only dependency of this package is `fastapi`.

## Development

Use `ruff` for linting and formatting, `mypy` for static code analysis, and `pytest` for testing.

The documentation is built with `mkdocs-material` and `mkdocstrings`.

## Contributing

All contributions are welcome.

## Contributors

- [Peter Volf](https://github.com/volfpeter)
- [Hasan Sezer Taşan](https://github.com/hasansezertasan)

## License - MIT

The package is open-sourced under the conditions of the [MIT license](https://choosealicense.com/licenses/mit/).


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "fasthx",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.10",
    "maintainer_email": null,
    "keywords": null,
    "author": "Peter Volf",
    "author_email": "do.volfp@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/13/80/d4419776b04085b316d984545927ece16e94f6af81d5ea73c218a1d6b00c/fasthx-0.2403.1.tar.gz",
    "platform": null,
    "description": "![Tests](https://github.com/volfpeter/fasthx/actions/workflows/tests.yml/badge.svg)\n![Linters](https://github.com/volfpeter/fasthx/actions/workflows/linters.yml/badge.svg)\n![Documentation](https://github.com/volfpeter/fasthx/actions/workflows/build-docs.yml/badge.svg)\n![PyPI package](https://img.shields.io/pypi/v/fasthx?color=%2334D058&label=PyPI%20Package)\n\n**Source code**: [https://github.com/volfpeter/fasthx](https://github.com/volfpeter/fasthx)\n\n**Documentation and examples**: [https://volfpeter.github.io/fasthx](https://volfpeter.github.io/fasthx/)\n\n# FastHX\n\nFastAPI and HTMX, the right way.\n\nKey features:\n\n- **Decorator syntax** that works with FastAPI as one would expect, no need for unused or magic dependencies in routes.\n- Works with **any templating engine** or server-side rendering library, e.g. `markyp-html` or `dominate`.\n- Built-in **Jinja2 templating support** (even with multiple template folders).\n- Gives the rendering engine **access to all dependencies** of the decorated route.\n- FastAPI **routes will keep working normally by default** if they receive **non-HTMX** requests, so the same route can serve data and render HTML at the same time.\n- **Response headers** you set in your routes are kept after rendering, as you would expect in FastAPI.\n- **Correct typing** makes it possible to apply other (typed) decorators to your routes.\n- Works with both **sync** and **async routes**.\n\n## Installation\n\nThe package is available on PyPI and can be installed with:\n\n```console\n$ pip install fasthx\n```\n\n## Examples\n\nFor complete examples, please see the [examples](https://github.com/volfpeter/fasthx/tree/main/examples) folder.\n\n### Jinja2 templating\n\nTo 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:\n\n```python\nfrom fastapi import FastAPI\nfrom fastapi.templating import Jinja2Templates\nfrom fasthx import Jinja\nfrom pydantic import BaseModel\n\n# Pydantic model of the data the example API is using.\nclass User(BaseModel):\n    first_name: str\n    last_name: str\n\n# Create the app.\napp = FastAPI()\n\n# Create a FastAPI Jinja2Templates instance and use it to create a\n# FastHX Jinja instance that will serve as your decorator.\njinja = Jinja(Jinja2Templates(\"templates\"))\n\n@app.get(\"/\")\n@jinja.page(\"index.html\")\ndef index() -> None:\n    ...\n\n@app.get(\"/user-list\")\n@jinja.hx(\"user-list.html\")\nasync def htmx_or_data() -> list[User]:\n    return [\n        User(first_name=\"John\", last_name=\"Lennon\"),\n        User(first_name=\"Paul\", last_name=\"McCartney\"),\n        User(first_name=\"George\", last_name=\"Harrison\"),\n        User(first_name=\"Ringo\", last_name=\"Starr\"),\n    ]\n\n@app.get(\"/admin-list\")\n@jinja.hx(\"user-list.html\", no_data=True)\ndef htmx_only() -> list[User]:\n    return [User(first_name=\"Billy\", last_name=\"Shears\")]\n```\n\n### Custom templating\n\nIf 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:\n\n```python\nfrom typing import Annotated, Any\n\nfrom fastapi import Depends, FastAPI, Request\nfrom fasthx import hx, page\n\n# Create the app.\napp = FastAPI()\n\n# Create a dependecy to see that its return value is available in the render function.\ndef get_random_number() -> int:\n    return 4  # Chosen by fair dice roll.\n\nDependsRandomNumber = Annotated[int, Depends(get_random_number)]\n\n# Create the render methods: they must always have these three arguments.\n# If you're using static type checkers, the type hint of `result` must match\n# the return type annotation of the route on which this render method is used.\ndef render_index(result: list[dict[str, str]], *, context: dict[str, Any], request: Request) -> str:\n    return \"<h1>Hello FastHX</h1>\"\n\ndef render_user_list(result: list[dict[str, str]], *, context: dict[str, Any], request: Request) -> str:\n    # The value of the `DependsRandomNumber` dependency is accessible with the same name as in the route.\n    random_number = context[\"random_number\"]\n    lucky_number = f\"<h1>{random_number}</h1>\"\n    users = \"\".join((\"<ul>\", *(f\"<li>{u['name']}</li>\" for u in result), \"</ul>\"))\n    return f\"{lucky_number}\\n{users}\"\n\n@app.get(\"/\")\n@page(render_index)\ndef index() -> None:\n    ...\n\n@app.get(\"/htmx-or-data\")\n@hx(render_user_list)\ndef htmx_or_data(random_number: DependsRandomNumber) -> list[dict[str, str]]:\n    return [{\"name\": \"Joe\"}]\n\n@app.get(\"/htmx-only\")\n@hx(render_user_list, no_data=True)\nasync def htmx_only(random_number: DependsRandomNumber) -> list[dict[str, str]]:\n    return [{\"name\": \"Joe\"}]\n```\n\n## Dependencies\n\nThe only dependency of this package is `fastapi`.\n\n## Development\n\nUse `ruff` for linting and formatting, `mypy` for static code analysis, and `pytest` for testing.\n\nThe documentation is built with `mkdocs-material` and `mkdocstrings`.\n\n## Contributing\n\nAll contributions are welcome.\n\n## Contributors\n\n- [Peter Volf](https://github.com/volfpeter)\n- [Hasan Sezer Ta\u015fan](https://github.com/hasansezertasan)\n\n## License - MIT\n\nThe package is open-sourced under the conditions of the [MIT license](https://choosealicense.com/licenses/mit/).\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "FastAPI data APIs with HTMX support.",
    "version": "0.2403.1",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e7c7055deaf221fbe81cc6bc0fd84a958cc5f073dd4c661f67f093e57df0c84c",
                "md5": "26fb8aec20bbfc2a0052414f9b5b35fb",
                "sha256": "5ae31f31f6c10c83bdd68942f90bade1f67d3eabcb2991e82a1e490f98d0736c"
            },
            "downloads": -1,
            "filename": "fasthx-0.2403.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "26fb8aec20bbfc2a0052414f9b5b35fb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.10",
            "size": 10407,
            "upload_time": "2024-03-26T19:57:14",
            "upload_time_iso_8601": "2024-03-26T19:57:14.639884Z",
            "url": "https://files.pythonhosted.org/packages/e7/c7/055deaf221fbe81cc6bc0fd84a958cc5f073dd4c661f67f093e57df0c84c/fasthx-0.2403.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1380d4419776b04085b316d984545927ece16e94f6af81d5ea73c218a1d6b00c",
                "md5": "b165adb30ec71af2ed8eeb13a786851f",
                "sha256": "b227c92f344609f6264f6df5ec18c647fabed353dac0a50ff28b2aa7b8949642"
            },
            "downloads": -1,
            "filename": "fasthx-0.2403.1.tar.gz",
            "has_sig": false,
            "md5_digest": "b165adb30ec71af2ed8eeb13a786851f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.10",
            "size": 10556,
            "upload_time": "2024-03-26T19:57:16",
            "upload_time_iso_8601": "2024-03-26T19:57:16.292215Z",
            "url": "https://files.pythonhosted.org/packages/13/80/d4419776b04085b316d984545927ece16e94f6af81d5ea73c218a1d6b00c/fasthx-0.2403.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-26 19:57:16",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "fasthx"
}
        
Elapsed time: 0.19456s