Skip to main content

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/:

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


Download files

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

Source Distribution

paramora-0.2.0.tar.gz (48.1 kB view details)

Uploaded Source

Built Distribution

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

paramora-0.2.0-py3-none-any.whl (21.6 kB view details)

Uploaded Python 3

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

Hashes for paramora-0.2.0.tar.gz
Algorithm Hash digest
SHA256 8cf936b571f62440fd3f28f65b2b0c02f8ab45e994f731c33f4d942adc33480f
MD5 54f3293c29fffa154de5c57b07bbb3f7
BLAKE2b-256 0bade08e6dd7752df1e11e9ad250a3256256862c3cb83862f21540ad6961bbce

See more details on using hashes here.

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

Hashes for paramora-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fb61408fe8592adc9930d741a483d01344b6646563a3041bfe3f77bef6156463
MD5 dbe7e57af4beebc3b497445e43215094
BLAKE2b-256 1f689272d96007076bc1243a944894ec87f0fb48e221b4038da49d1ddb927336

See more details on using hashes here.

Supported by

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