Safe typed query compilation for FastAPI.
Project description
Paramora
Paramora is safe typed query compilation for FastAPI. It turns HTTP query parameters into a backend-neutral AST, then emits backend-specific query objects. The current MVP is FastAPI-native and currently supports MongoDB output.
Status: 0.1 pre-release. The API is still allowed to change before the first stable release.
Documentation
The README gives the short path. The full user and contributor documentation is
kept in this repository under docs/:
- Quickstart
- Query contracts
- Query syntax
- Error handling
- MongoDB backend
- Development with uv
- Testing strategy
- Profiling and future Rust hotspots
Docs live on the main branch so GitHub, source distributions, and PyPI readers
can find the same authoritative material. Wheels only need the runtime
paramora package.
Installation
Paramora is designed for FastAPI applications. The package is not published yet; when it is, installation will look like this:
uv add paramora
For local development from the repository:
uv sync --group dev
Quickstart
Define a type-checker-friendly query contract with typing.Annotated, pass it to
Query, and mount it with FastAPI using Depends(item_query).
from datetime import datetime
from typing import Annotated
from fastapi import Depends, FastAPI
from paramora import CompiledQuery, Query, QueryContract, query_field
app = FastAPI()
class ItemQuery(QueryContract):
status: Annotated[str, query_field("eq", "in")]
active: bool
created_at: Annotated[
datetime,
query_field("gte", "lte", sortable=True),
]
price: Annotated[float, query_field("eq", "gt", "gte", "lt", "lte")]
item_query = Query(ItemQuery, default_limit=20, max_limit=100)
@app.get("/items")
def list_items(query: CompiledQuery = Depends(item_query)):
mongo = query.to_mongo()
return list(
collection
.find(mongo.filter)
.sort(mongo.sort)
.skip(mongo.offset)
.limit(mongo.limit)
)
Request:
/items?status__in=free,busy&active=true&sort=-created_at&limit=20
Mongo output:
MongoQuery(
filter={"status": {"$in": ["free", "busy"]}, "active": True},
sort=[("created_at", -1)],
limit=20,
offset=0,
)
Modes
Paramora has one simple mode rule:
Query()has no contract and defaults to loose mode.Query(MyContract)has a contract and defaults to strict mode.
Strict mode is recommended for public endpoints. Loose mode is useful for prototypes and trusted internal tools.
Contract fields
Bare annotations create equality-only filters:
class ItemQuery(QueryContract):
active: bool
Use query_field(...) inside Annotated for operators, sortability, aliases,
and required filters:
class ItemQuery(QueryContract):
status: Annotated[str, query_field("eq", "in", "nin")]
created_at: Annotated[
datetime,
query_field("gte", "lte", sortable=True, alias="createdAt"),
]
The positional operator API is deliberate: editors such as Pylance can provide
better autocomplete for query_field("eq", "in") than for a nested tuple such as
allow=("eq", "in").
MongoDB backend
MongoDB is the first supported backend. Paramora currently emits Mongo filter
dictionaries, PyMongo-compatible sort pairs, limit, and offset.
mongo = query.to_mongo()
collection.find(mongo.filter).sort(mongo.sort).skip(mongo.offset).limit(mongo.limit)
Other backends are planned after the public contract, AST, and error model are stable.
Error handling
Validation errors are structured and FastAPI-compatible:
{
"detail": [
{
"loc": ["query", "price"],
"msg": "Expected a float-compatible value.",
"type": "query.type_error.float",
"input": "bad"
}
]
}
See Error handling for stable error-code semantics.
Development
This repository is uv-first:
uv sync --group dev
uv run pytest -vv
uv run ruff format --check .
uv run ruff check .
uv run pyright
The default pytest configuration runs coverage with missing-line reporting.
Mongo-like execution tests use mongomock; parser and coercion behavior are
covered by focused unit tests.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file paramora-0.2.0.tar.gz.
File metadata
- Download URL: paramora-0.2.0.tar.gz
- Upload date:
- Size: 48.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8cf936b571f62440fd3f28f65b2b0c02f8ab45e994f731c33f4d942adc33480f
|
|
| MD5 |
54f3293c29fffa154de5c57b07bbb3f7
|
|
| BLAKE2b-256 |
0bade08e6dd7752df1e11e9ad250a3256256862c3cb83862f21540ad6961bbce
|
File details
Details for the file paramora-0.2.0-py3-none-any.whl.
File metadata
- Download URL: paramora-0.2.0-py3-none-any.whl
- Upload date:
- Size: 21.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb61408fe8592adc9930d741a483d01344b6646563a3041bfe3f77bef6156463
|
|
| MD5 |
dbe7e57af4beebc3b497445e43215094
|
|
| BLAKE2b-256 |
1f689272d96007076bc1243a944894ec87f0fb48e221b4038da49d1ddb927336
|