5-Minute Quickstart¶
From zero to an endpoint that responds, without cookiecutter, so you can see what is actually happening.
In a hurry?
Go straight to the cookiecutter scaffold - a complete service with tests, Docker, and CI in 30 seconds.
1. Install¶
python3.14 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install "mic-core[fastapi]"
2. Write a handler¶
main.py:
from fastapi import FastAPI
from mic.contracts import StrictSchema, wrap_http_success
from mic.http import HttpResponseSpec, HttpRouteSpec
from mic.fastapi import build_fastapi_router
from mic.model.errors import DomainError
# 1. Strict input schema
class CreateItem(StrictSchema):
name: str
quantity: int = 0
# 2. Framework-neutral handler
def _create(*, payload: CreateItem) -> HttpResponseSpec:
if payload.quantity < 0:
raise DomainError(
code="items.invalid_quantity",
message="quantity must be >= 0",
details={"received_quantity": payload.quantity},
)
return HttpResponseSpec(
status_code=201,
body=wrap_http_success(
{"name": payload.name, "qty": payload.quantity}
),
)
# 3. Wiring
routes = (
HttpRouteSpec(
method="POST",
path="/api/v1/items",
name="items_v1_create",
category="items",
handler=_create,
),
)
app = FastAPI()
app.include_router(build_fastapi_router(routes=routes))
3. Run it¶
4. Call it¶
# Happy path
curl -X POST http://localhost:8000/api/v1/items \
-H "Content-Type: application/json" \
-d '{"name": "widget", "quantity": 3}'
# {"success":true,"data":{"name":"widget","qty":3},"meta":null}
# DomainError
curl -X POST http://localhost:8000/api/v1/items \
-H "Content-Type: application/json" \
-d '{"name": "x", "quantity": -1}'
# 400 {"success":false,"code":"items.invalid_quantity","message":"...","details":{"received_quantity":-1}}
# extra=forbid
curl -X POST http://localhost:8000/api/v1/items \
-H "Content-Type: application/json" \
-d '{"name": "x", "secret": "boom"}'
# 400 {"success":false,"code":"http.validation_error","message":"...","details":[...]}
5. Switch to Litestar Without Touching the Handler¶
Change only the final wiring:
# Before (FastAPI)
from fastapi import FastAPI
from mic.fastapi import build_fastapi_router
app = FastAPI()
app.include_router(build_fastapi_router(routes=routes))
# After (Litestar)
from litestar import Litestar
from mic.litestar import build_litestar_router
app = Litestar(route_handlers=[build_litestar_router(routes=routes)])
The _create handler did not change at all. The curl commands above
produce the same responses. That is MIC.
What Comes Next?¶
- Cookiecutter scaffold for a complete project with tests, database, and observability in 30 seconds.
- Module anatomy to structure domain code cleanly.
- Mirror tests to reach 100% coverage.