Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

half-orm-litestar

A halfORM extension that generates a Litestar REST API from your halfORM relation classes by decorating their methods.

Installation

pip install half-orm-litestar

Requires half-orm-dev to be installed (for project introspection):

pip install half-orm-dev

Quick start

1. Decorate your halfORM methods

In any halfORM relation class, import tools and annotate the methods you want to expose as API routes:

# myproject/actor/user.py

from half_orm_litestar import tools

class User(MODEL.get_relation_class('actor.user')):

    @tools.api_get('/user/{id: uuid}', guards=['public'])
    async def get_user(self, request: "Request"):
        actor_id = request.path_params['id']
        return self.load_user(actor_id)

    @tools.api_get('/user/{user_id: uuid}/group_accesses', guards=['has_user_access'])
    async def get_user_group_accesses(self, request: "Request"):
        actor_id = request.path_params['user_id']
        return [dict(row) for row in self.rfk_group_accesses(actor_id=actor_id)]

    @tools.api_post('/users', guards=['connected'])
    async def create_user(self, request: "Request"):
        data = await request.json()
        ...

The decorators accept the same arguments as the corresponding Litestar decorators (@get, @post, @put, @patch, @delete).

Available decorators:

Decorator HTTP method
tools.api_get GET
tools.api_post POST
tools.api_put PUT
tools.api_patch PATCH
tools.api_delete DELETE

2. Generate the API

From the root of your half-orm-dev project:

half_orm litestar generate

This command:

  1. Scans all halfORM relation classes for @api_* decorated methods.
  2. Creates missing scaffolding files in api/ (only on first run — existing files are never overwritten).
  3. Writes api/app.py, the ready-to-run Litestar application.

3. Run the API

uvicorn api.app:application --reload

Project structure after generate

myproject/
├── api/
│   ├── __init__.py
│   ├── guards.py                        ← authentication guards (edit this)
│   ├── app.py                          ← generated, do not edit by hand
│   └── custom/
│       ├── __init__.py
│       ├── routes.py                    ← hand-written extra routes
│       └── middlewares/
│           ├── __init__.py              ← extra middlewares list
│           └── authorization.py        ← authentication middleware (edit this)

Files in api/ (except app.py) are created once and never overwritten. Regenerating only rewrites app.py.


Customisation

Guards (api/guards.py)

Guards are async callables that receive the ASGI connection and raise an exception to deny access. Two minimal guards are provided out of the box: public (allow all) and connected (require authenticated user).

Add your own project-specific guards in api/guards.py:

# api/guards.py
from litestar.connection import ASGIConnection
from litestar.handlers.base import BaseRouteHandler
from litestar.exceptions import HTTPException

async def has_user_access(
    connection: ASGIConnection, handler: BaseRouteHandler = None
) -> None:
    """Allow only the user identified by the ``user_id`` path parameter."""
    if not connection.user:
        raise HTTPException(status_code=401)
    if connection.user != str(connection.path_params.get('user_id')):
        raise HTTPException(status_code=403)

Then reference the guard by name in your decorator:

@tools.api_get('/user/{user_id: uuid}/profile', guards=['has_user_access'])
async def get_profile(self, request: "Request"):
    ...

Authorization middleware (api/custom/middlewares/authorization.py)

Implement the Authorization class to decode tokens / sessions and populate connection.user. When the file exists, Authorization is automatically placed first in the middleware stack.

# api/custom/middlewares/authorization.py
import jwt
from litestar.middleware import AbstractAuthenticationMiddleware, AuthenticationResult
from litestar.connection import ASGIConnection

SECRET = "change-me"

class Authorization(AbstractAuthenticationMiddleware):
    async def authenticate_request(self, connection: ASGIConnection) -> AuthenticationResult:
        token = (
            connection.headers.get("Authorization", "")
            .removeprefix("Bearer ")
            .strip()
        )
        try:
            payload = jwt.decode(token, SECRET, algorithms=["HS256"])
            return AuthenticationResult(user=payload["sub"], auth=token)
        except Exception:
            return AuthenticationResult(user=None, auth=None)

Extra routes (api/custom/routes.py)

Hand-written Litestar route handlers can be added here:

# api/custom/routes.py
from litestar import get

@get('/health')
async def health_check() -> dict:
    return {'status': 'ok'}

routes = [health_check]

Extra middlewares (api/custom/middlewares/__init__.py)

# api/custom/middlewares/__init__.py
from .my_middleware import MyMiddleware

middlewares = [MyMiddleware]

Path prefix

The generated routes are automatically prefixed with the project's database name. For a project named mydb, '/user/{id: uuid}' becomes '/mydb/user/{id: uuid}'.


Advanced: using without half-orm-dev

GenApi can be used programmatically without a Repo object by supplying the relation classes directly:

from half_orm_litestar.generate import GenApi

GenApi(
    relation_classes=my_classes,   # iterable of (RelationClass, type) pairs
    module_name='mydb',
    base_dir='/path/to/project',
)

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

half_orm_litestar-1.0.0a5.tar.gz (29.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

half_orm_litestar-1.0.0a5-py3-none-any.whl (26.8 kB view details)

Uploaded Python 3

File details

Details for the file half_orm_litestar-1.0.0a5.tar.gz.

File metadata

  • Download URL: half_orm_litestar-1.0.0a5.tar.gz
  • Upload date:
  • Size: 29.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for half_orm_litestar-1.0.0a5.tar.gz
Algorithm Hash digest
SHA256 72eda25083212e6b3d008ee2965249400dfa148ac1defe05a47d17c9517549f1
MD5 298d0e505a8f92c9e12e1fcd2a90278f
BLAKE2b-256 8b34fde7cf06a12bbc841b31f9262b13dbb49d11ea7c266903bf04b257bd2a41

See more details on using hashes here.

File details

Details for the file half_orm_litestar-1.0.0a5-py3-none-any.whl.

File metadata

File hashes

Hashes for half_orm_litestar-1.0.0a5-py3-none-any.whl
Algorithm Hash digest
SHA256 088357d0543dfa713a1608c25836f1479676717a1bfc263eb438e3e618e8c389
MD5 d2122256decdc8edfd01300272d9a7de
BLAKE2b-256 be7c093c3e1f299fcdeecf6f2d84abe296b74bf312ec0be501165642bcb456f6

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.0a5 This release

2 files

1.0.0a3

2 files

1.0.0a2

2 files

1.0.0a1

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page