Build a typed JSON API
Prerequisites: Python 3.12+, Dexpot with its CLI, and a terminal. Create a project and install the framework before following this guide:
python -m venv .venv. .venv/bin/activatepython -m pip install 'dexpot[cli]'On Windows PowerShell, activate with .venv\Scripts\Activate.ps1. This guide uses a local-only listener; it does not expose the example to a network.
1. Declare the wire shapes and routes
Section titled “1. Declare the wire shapes and routes”Save as main.py:
import msgspecfrom dexpot import Dex
class ItemIn(msgspec.Struct): name: str price: float
class ItemOut(msgspec.Struct): id: int name: str price: float
app = Dex()
@app.get('/items/{item_id}', response=ItemOut)def get_item(item_id: int) -> ItemOut: return ItemOut(item_id, f'item-{item_id}', 9.99)
@app.post('/items', body=ItemIn, response=ItemOut)def create_item(item: ItemIn) -> tuple[int, ItemOut]: return 201, ItemOut(1, item.name, item.price)The explicit body=ItemIn selects and precompiles a msgspec JSON decoder; the matching handler parameter receives the decoded ItemIn. A path capture is converted according to the int annotation. response=ItemOut precompiles the successful response encoder; it does not enforce the returned value’s type at runtime. Annotate an optional request: Request parameter to receive the frozen public request context; see routes and handlers.
2. Run and exercise the public HTTP interface
Section titled “2. Run and exercise the public HTTP interface”dexpot serve main:app --host 127.0.0.1 --port 8000In another terminal:
curl -i http://127.0.0.1:8000/items/7curl -i -X POST http://127.0.0.1:8000/items \ -H 'Content-Type: application/json' \ -d '{"name":"keyboard","price":79.0}'curl -i -X POST http://127.0.0.1:8000/items \ -H 'Content-Type: application/json' -d '{"name":false}'curl -i -X PUT http://127.0.0.1:8000/itemsThe first request returns a JSON ItemOut with id 7. The valid POST returns status 201 and the submitted name and price. Invalid JSON or body validation returns 422; a path that exists only for another method returns 405 with Allow. These are deterministic contract expectations; consult the linked response checks for the repository’s executable examples.
3. Verify against the repository
Section titled “3. Verify against the repository”The repository’s socket-level example test launches each example as a subprocess and checks actual HTTP responses:
uv sync --all-extrasuv run pytest tests/test_examples.py -qSee examples/typed_crud.py for mutable CRUD state and application-owned locking. Do not share mutable state between concurrent handlers without synchronization. For binding details—including positional and keyword-only parameters, registration failures, postponed annotations, and annotation_locals—continue to routes and handlers. For bounded limits and parser behavior, read the HTTP boundary.