DefSpec
Create the OpenAPI spec and document from dataclass, attrs, msgspec, etc.
Why not ...
This project is a legacy of a private initiative. During the development, I discovered that using msgspec could elegantly define and generate the API schema. The OpenAPI component can be utilized to generate the API documentation for various projects. As a result, I made the decision to extract it and transform it into a public project.
You can use this project as a low-level component or a drop-in module when you don't want to introduce too many other dependencies.
Installation
pip install defspec
# to enable the offline feature
pip install defspec[offline]
Examples
flask: examples/flaskfalcon: examples/falconoffline: examples/offline
You can run the above examples and open the OpenAPI document in your browser:
swagger: http://127.0.0.1:8000/openapi/swaggerredoc: http://127.0.0.1:8000/openapi/redocscalar: http://127.0.0.1:8000/openapi/scalar
Usage
from dataclasses import dataclass
from typing import List
from defspec import OpenAPI, OpenAPIComponent, SecuritySchemeHTTP
@dataclass
class User:
name: str
age: int
openapi = OpenAPI(
components=OpenAPIComponent(
security_schemes={"token": SecuritySchemeHTTP(scheme="bearer")}
),
security=[{"token": []}],
)
openapi.register_route("/", method="get", summary="Hello World")
openapi.register_route(
"/users", method="post", summary="Get all the user info", response_type=List[User]
)
# get the OpenAPI spec
print(openapi.to_dict())
# get the OpenAPI spec bytes
with open("openapi.json", "wb") as f:
f.write(openapi.to_json())
# serve as a HTTP server
openapi.serve_as_http_daemon(port=8000, run_in_background=True)
OpenAPI compatibility
Starting with DefSpec 0.7, the default is OpenAPI 3.2.0. Both 3.2.x and 3.1.x are supported. To keep generating 3.1 documents for existing consumers:
openapi = OpenAPI(openapi="3.1.0")
The existing model, parameter, and security APIs work with both versions.
OpenAPI 3.2 also accepts method="QUERY" with a request body; 3.1 rejects it.
Construction and JSON decoding reject operations unsupported by the selected
version, including query in 3.1. Operation keys in supplied paths must use
lowercase names; register_route accepts methods in any letter case.
Custom HTTP methods (additionalOperations), whole-query-string parameters,
and streaming item schemas do not yet have dedicated generation APIs.
- Models use
components.schemasand#/components/schemas/...references. When migrating, update saved$defsreferences. Thedefs=constructor argument is removed;openapi.defsremains an alias foropenapi.components.schemas. - Query, header, cookie, and path models expand into one parameter per encoded
field name; generated msgspec tags are omitted. Wrap unions such as
int | strin a model. Named scalars, such asintorUUID, use the type name as the parameter name. Defaults make non-path fields optional unless the schema requires them. Path fields must match the URL placeholders and cannot have defaults or default factories. TypedDict path keys must be required. Each placeholder must have a unique name. - Field constraints and descriptions are preserved; parameter schemas are copied
independently. Model titles, descriptions, and
forbid_unknown_fieldsare ignored during expansion. Constraints that cannot be expanded raiseValueError, includingadditionalProperties: falseannotations that forbid declared fields. - Header names
Authorization,Accept, andContent-Typeare rejected regardless of case. Use security schemes and request/response content types instead. request_type=Noneomits the body;response_type=Noneomits response content. Usetype(None)for JSON null. Routes document a200response by default.- Omit
securityto inherit global security; usesecurity=[]for public routes. OAuth flows omit absent fields and keep the requiredscopesmap. - Default operation IDs include a stable path hash:
_users_<hash>_getfor GET/users. Setoperation_idto choose your own name. - Invalid routes, equivalent path templates, duplicate operation IDs, and
empty or conflicting schema names raise
ValueErrorwithout changing the document. HTTP methods are case-insensitive. Use distinct model names andoperation_idvalues to resolve conflicts.
Custom schema hooks follow msgspec's rules: return a schema dictionary or True
for an unconstrained schema. The tests validate generated documents against
both supported versions with openapi-spec-validator, including JSON round
trips. Validate custom schemas and direct edits before use. Swagger UI and
ReDoc are pinned to releases that accept OpenAPI 3.2 documents.
Use Swagger UI or Scalar for QUERY operations;
ReDoc 2.5.3 renders ordinary operations but omits QUERY. Offline renderer and
client generator compatibility depends on the upstream version. Select 3.1
when your consumer requires it.
Metadata
Release files for defspec 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| defspec-0.7.0.tar.gz | 36.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| defspec-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 55.9 kB
Release files / defspec-0.7.0.tar.gz
| Download URL | defspec-0.7.0.tar.gz |
|---|---|
| Size | 36.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5c917cbcb64b58f6fbdf6f47df1cdcf762e8e0fb9dad77eda032ba8bfc71bcec
|
|
BLAKE2b-256 checksum How to use checksums |
27ebd2d6bd95a22e06152038ad95cd554121689b19f0d728289cde97370d2ba9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.24 {"installer":{"name":"uv","version":"0.12.24","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 / defspec-0.7.0-py3-none-any.whl
| Download URL | defspec-0.7.0-py3-none-any.whl |
|---|---|
| Size | 19.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6a7cf7a5f35e86a5ae7c582873a5f245ebf9d8999ff0630559714911812d586c
|
|
BLAKE2b-256 checksum How to use checksums |
e2ebf283e8ecc5a0fc45919e52d5d4f0dc5020c0b532163a63665b66f9e5e46b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.24 {"installer":{"name":"uv","version":"0.12.24","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}
|