///|
/// The descriptor tree drives validation and OpenAPI from one source of truth.
/// The `users_app` in `models.mbt`: its `Endpoint` / `Param` / `Schema` / `ResponseSpec` descriptors
/// validate an inbound `POST /users` body and a typed `{id}` path param, and the
/// same tree emits the request/response body schemas — objects, arrays, and a
/// nested `Address` hoisted into `components/schemas` behind a `$ref`. A body
/// that violates the descriptor comes back as a FastAPI-shaped `422`.
///
/// moon run src/examples/04-descriptors
#coverage.skip
async fn main {
let app = users_app()
let json_headers = [("content-type", "application/json")]
let hit = (verb : String, path : String, body : String) => {
let req : @moonasgi.Request = {
http_method: verb,
path,
query_string: b"",
headers: json_headers,
body: @utf8.encode(body),
}
let r = app.handle(req)
println("\{verb} \{path} -> \{r.status} \{@utf8.decode_lossy(r.body[:])}")
}
// A conforming body validates and deserialises.
hit(
"POST", "/users", "{\"name\":\"qwq\",\"email\":\"qwq@example.com\",\"age\":23}",
)
// Missing the required `name` -> 422 with a located `missing` error.
hit("POST", "/users", "{\"email\":\"qwq@example.com\",\"age\":23}")
// A typed integer path param returns the nested `User` (address + tags).
hit("GET", "/users/233", "")
println("--- OpenAPI 3.1.0 (note components/schemas + $ref) ---")
println(app.openapi_json(version=OpenApi31))
}