///|
/// Pydantic-style field constraints and the scalar schema types, emitted into
/// the OpenAPI schema and enforced off one descriptor. Every `Constraint` is
/// exercised — `Minimum` / `Maximum`, `ExclusiveMinimum` / `ExclusiveMaximum`,
/// `MultipleOf`, `MinLength` / `MaxLength`, `Pattern`, `MinItems` / `MaxItems` —
/// alongside the scalar types `SInt` / `SFloat` / `SStr` / `SBool` / `SNull` /
/// `SArray` and a closed `SEnum`. A conforming body validates; a low/short body
/// and a high/long body each return a `422` naming every violation by its
/// pydantic error type.
///
/// moon run src/examples/05-constraints
#coverage.skip
async fn main {
let color : @moonapi.Schema = SEnum(SStr, [
Json("red"),
Json("green"),
Json("blue"),
])
let schema = @moonapi.Schema::object("Order", [
@moonapi.Field::new("qty", SInt, constraints=[Minimum(1.0), Maximum(99.0)]),
@moonapi.Field::new("step", SInt, constraints=[MultipleOf(5.0)]),
@moonapi.Field::new("ratio", SFloat, constraints=[
ExclusiveMinimum(0.0),
ExclusiveMaximum(1.0),
]),
@moonapi.Field::new("code", SStr, constraints=[
MinLength(3),
MaxLength(8),
Pattern("^[a-z]+$"),
]),
@moonapi.Field::new("tags", @moonapi.Schema::array(SStr), constraints=[
MinItems(1),
MaxItems(3),
]),
@moonapi.Field::new("active", SBool),
@moonapi.Field::new("color", color),
// A field whose value must be JSON null.
@moonapi.Field::new("note", SNull, required=false),
])
let ep = @moonapi.Endpoint::new(request_body=schema)
let app = @moonapi.App::new()
app.post(
"/orders",
ctx => {
let errs = ep.validate(ctx)
if errs.length() > 0 {
@moonapi.unprocessable(errs)
} else {
@moonapi.text(201, "order accepted")
}
},
endpoint=ep,
)
let hit = (label : String, body : String) => {
let req : @moonasgi.Request = {
http_method: "POST",
path: "/orders",
query_string: b"",
headers: [("content-type", "application/json")],
body: @utf8.encode(body),
}
let r = app.handle(req)
println("\{label} -> \{r.status} \{@utf8.decode_lossy(r.body[:])}")
}
// Within every bound.
hit(
"ok ", "{\"qty\":5,\"step\":10,\"ratio\":0.5,\"code\":\"abc\",\"tags\":[\"a\",\"b\"],\"active\":true,\"color\":\"red\"}",
)
// Below the lower bounds, too short, wrong scalar types, off the enum.
hit(
"low ", "{\"qty\":0,\"step\":7,\"ratio\":1.5,\"code\":\"AB\",\"tags\":[],\"active\":\"yes\",\"color\":\"pink\",\"note\":5}",
)
// Above the upper bounds, too long, too many items.
hit(
"high", "{\"qty\":100,\"step\":5,\"ratio\":0.0,\"code\":\"toolongcode\",\"tags\":[\"a\",\"b\",\"c\",\"d\"],\"active\":false,\"color\":\"green\"}",
)
println("--- OpenAPI 3.1.0 (constraints + enum in the schema) ---")
println(app.openapi_json(version=OpenApi31))
}