///|
/// A body written as JSON Schema (`Schema::json`), for what the descriptor
/// constructors cannot say — here a `pattern` and a closed set. The same
/// document is emitted into the OpenAPI operation and handed to moonschema to
/// validate the request against: one tree, two projections.
///
/// moon run src/examples/19-json-schema
#coverage.skip
fn main {
let body = @moonapi.Schema::object("Post", [
@moonapi.Field::new(
"slug",
@moonapi.Schema::json({ "type": "string", "pattern": "^[a-z0-9-]+$" }),
required=true,
),
@moonapi.Field::new(
"state",
@moonapi.Schema::json({ "enum": ["draft", "live"] }),
required=true,
),
])
let app = @moonapi.App::new()
app.post(
"/posts",
ctx => @moonapi.json(201, ctx.body_json().unwrap_or(Json::null())),
endpoint=@moonapi.Endpoint::new(request_body=body),
)
// The document says exactly what was written.
let doc = app.openapi()
println(
"schema: " +
at(doc, ["components", "schemas", "Post", "properties"]).stringify(),
)
// And the same schema decides what the endpoint accepts.
for
instance in (
[
{ "slug": "hello-world", "state": "live" },
{ "slug": "Hello", "state": "soon" },
] : Array[Json]) {
let errs : Array[@moonapi.ValidationError] = []
@moonapi.validate_schema(body, instance, [], errs)
println(
instance.stringify() + " -> " + errs.length().to_string() + " error(s)",
)
for err in errs {
println(" " + err.loc.join("/") + " " + err.kind + ": " + err.msg)
}
}
}
///|
/// One step at a time down a document.
fn at(doc : Json, path : Array[String]) -> Json {
let mut here = doc
for step in path {
here = match here {
Object(members) =>
match members.get(step) {
Some(next) => next
None => return Json::null()
}
_ => return Json::null()
}
}
here
}