apiquart
The minimalistic API framework for Quart — declarative request/response validation and automatic OpenAPI 3.1 docs, built on Pydantic v2.
apiquart brings APIFlask-style ergonomics to Quart's
async-native world. It is a thin layer over vanilla Quart and Pydantic: an
APIQuart app is a quart.Quart subclass, your schemas are plain Pydantic
models, and removing every decorator still leaves a working route.
@app.input— parse and validate the request (json/query/form/files/ headers/cookies/path); the validated model instance is injected as an argument.@app.output— serialize the return value (ORM object, dict, or model) through Pydantic.@app.doc— attach OpenAPI operation metadata.@app.auth_required— first-class auth via quart-httpauth.- OpenAPI 3.1 generated straight from your Pydantic models, with four
interactive doc UIs behind a single
/docsendpoint.
Installation
pip install apiquart
The distribution name is apiquart; the import name is apiquart. Optional
extras: apiquart[auth] (quart-httpauth), apiquart[yaml] (YAML spec output).
Quickstart
from apiquart import APIQuart, BaseModel, abort
app = APIQuart(__name__, title="Pets API", version="1.0.0")
class PetIn(BaseModel):
name: str
category: str = "other"
class PetOut(PetIn):
id: int
pets: dict[int, dict] = {}
@app.post("/pets")
@app.input(PetIn, arg_name="pet")
@app.output(PetOut, status_code=201)
async def create_pet(pet): # pet is a validated PetIn
pet_id = len(pets) + 1
pets[pet_id] = {"id": pet_id, **pet.model_dump()}
return pets[pet_id]
@app.get("/pets/<int:pet_id>")
@app.output(PetOut)
async def get_pet(pet_id):
if pet_id not in pets:
abort(404, message="Pet not found")
return pets[pet_id]
Run it with any ASGI server:
hypercorn module:app
- OpenAPI spec:
GET /openapi.json - Interactive docs:
GET /docs(Swagger UI by default; try?ui=redoc,?ui=rapidoc,?ui=elements)
Input locations
@app.input(Model, location=...) supports json (default), query, form,
files, form_and_files, headers, cookies and path. The validated model
is injected as f"{location}_data" unless you pass arg_name=. Multiple
@app.input decorators stack for different locations. Invalid input yields a
422 with the standard error envelope.
Output
@app.output(Model, status_code=200) validates and serializes the handler's
return value (model.model_validate(obj).model_dump(mode="json")). Handlers may
return obj, (obj, status), or (obj, status, headers). Use EmptyModel
with status_code=204 to document an empty response.
Errors
Every error is a single JSON envelope:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request contains invalid data",
"detail": {"json": [{"loc": ["name"], "msg": "Field required", "type": "missing"}]}
}
}
Raise one with abort(404, message="Pet not found") or
raise HTTPError(...). Quart's own HTTPExceptions are reshaped into the same
envelope. Customize the shape with @app.error_processor.
Authentication
from quart_httpauth import HTTPTokenAuth
from apiquart import APIQuart
app = APIQuart(__name__)
auth = HTTPTokenAuth(scheme="Bearer")
@auth.verify_token
async def verify(token):
return await User.from_token(token)
@app.get("/admin/stats")
@app.auth_required(auth, roles="admin")
async def stats():
return {"user": auth.current_user()}
apiquart introspects the auth object and registers the matching OpenAPI security
scheme (Basic → http/basic, Bearer → http/bearer, custom header → apiKey).
Pagination
from apiquart import BaseModel, PaginationMeta, pagination_builder
class PetsPage(BaseModel):
data: list[PetOut]
pagination: PaginationMeta
@app.get("/pets")
@app.input(PetQuery, location="query")
@app.output(PetsPage)
async def list_pets(query_data):
items, total = await Pet.paginate(query_data.page, query_data.per_page)
return {
"data": items,
"pagination": pagination_builder(query_data.page, query_data.per_page, total),
}
Blueprints and class-based views
APIBlueprint carries the same decorators so blueprint routes contribute to the
spec. Quart's MethodView is supported — decorate the HTTP methods directly.
See examples/ for runnable apps.
License
MIT.
Metadata
Release files for apiquart 0.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| apiquart-0.0.1.tar.gz | 161.6 kB | Without provenance | Details for apiquart-0.0.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| apiquart-0.0.1-py3-none-any.whl | Python 3 | none | any | Details for apiquart-0.0.1-py3-none-any.whl |
Total release size: 186.1 kB
Release files / apiquart-0.0.1.tar.gz
| Download URL | apiquart-0.0.1.tar.gz |
|---|---|
| Size | 161.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0e0eb1926855f43414e6e34f6c76d08e62c1474572a0f04283b128c845e6b140
|
|
BLAKE2b-256 checksum How to use checksums |
9ff0bb701c3d7ae0aa5b679cda6fb52f900560361902bc4f57677e4f1842cd47
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / apiquart-0.0.1-py3-none-any.whl
| Download URL | apiquart-0.0.1-py3-none-any.whl |
|---|---|
| Size | 24.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bdff2d39e7a0ed144a7a74c837a9f42af9c9ab2876df33f3c82df5633ab81703
|
|
BLAKE2b-256 checksum How to use checksums |
cd27b576b732829bc47f52047f915dbc23601508f506a400057e0c704d130e4f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for apiquart 0.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.