///|
priv struct ModeledErrorExample {
shape : @smithy.ShapeId
content : Map[String, @smithy.NodeValue]
}
///|
priv struct ModeledExample {
ordinal : Int32
title : String
documentation : String
input : Map[String, @smithy.NodeValue]
output : Map[String, @smithy.NodeValue]
error : ModeledErrorExample?
}
///|
priv enum ExamplePhase {
RequestExample
ResponseExample
FailedExample(Array[@smithy.ShapeId])
}
///|
fn Context::modeled_examples(
self : Context,
operation : @smithy.Shape,
) -> Array[ModeledExample] raise OpenApiError {
if self.examples_cache.get(operation.id) is Some(cached) {
return cached
}
let out : Array[ModeledExample] = []
guard operation.trait_value("smithy.api#examples")
is Some(@smithy.Array(examples)) else {
self.examples_cache[operation.id] = out
return out
}
for i = 0; i < examples.length(); i = i + 1 {
guard examples[i] is @smithy.Object(fields) &&
fields.get("title") is Some(@smithy.String(title)) else {
raise InvalidConfiguration(
"Malformed example on `" + operation.id.to_string() + "`",
)
}
let documentation = match fields.get("documentation") {
Some(@smithy.String(value)) => value
_ => ""
}
let input = match fields.get("input") {
Some(@smithy.Object(value)) => value
_ => Map([])
}
let output = match fields.get("output") {
Some(@smithy.Object(value)) => value
_ => Map([])
}
let error = match fields.get("error") {
None => None
Some(@smithy.Object(error)) => {
guard error.get("shapeId") is Some(@smithy.String(name)) &&
@smithy.ShapeId::parse(name) is Some(shape) else {
raise InvalidConfiguration(
"Example error requires an absolute shapeId",
)
}
Some({
shape,
content: match error.get("content") {
Some(@smithy.Object(value)) => value
_ => Map([])
},
})
}
_ => raise InvalidConfiguration("Example error must be an object")
}
out.push({ ordinal: i + 1, title, documentation, input, output, error, })
}
self.examples_cache[operation.id] = out
out
}
///|
fn Context::example_rows(
self : Context,
operation : @smithy.Shape,
phase : ExamplePhase,
) -> Array[(ModeledExample, Map[String, @smithy.NodeValue])] raise OpenApiError {
let out : Array[(ModeledExample, Map[String, @smithy.NodeValue])] = []
for example in self.modeled_examples(operation) {
match phase {
RequestExample => out.push((example, example.input))
ResponseExample if example.error is None =>
out.push((example, example.output))
FailedExample(ids) =>
if example.error is Some(error) && ids.contains(error.shape) {
out.push((example, error.content))
}
_ => ()
}
}
out
}
///|
fn Context::example_value(
self : Context,
shape : @smithy.Shape,
value : @smithy.NodeValue,
) -> @smithy.NodeValue {
let target = self.target(shape)
match (target.body, value) {
(@smithy.Simple(Document), _) => value
(@smithy.List(item), @smithy.Array(values)) => {
guard self.model.shapes.get(item) is Some(element) else { return value }
@smithy.Array(values.map(value => self.example_value(element, value)))
}
(@smithy.Map(value=element_id, ..), @smithy.Object(values)) => {
guard self.model.shapes.get(element_id) is Some(element) else {
return value
}
let out : Map[String, @smithy.NodeValue] = Map([])
for key, value in values {
out[key] = self.example_value(element, value)
}
@smithy.Object(out)
}
(@smithy.Structure(_) | @smithy.Union(_), @smithy.Object(values)) => {
let out : Map[String, @smithy.NodeValue] = Map([])
for key, value in values {
if target.id.with_member(key) is Some(member_id) &&
self.model.shapes.get(member_id) is Some(member_shape) {
out[self.property_name(member_shape)] = self.example_value(
member_shape, value,
)
} else {
out[key] = value
}
}
@smithy.Object(out)
}
_ => value
}
}
///|
fn example_object(example : ModeledExample, value : @smithy.NodeValue) -> Json {
Json::object({
"summary": Json::string(example.title),
"description": Json::string(example.documentation),
"value": value.to_json(),
})
}
///|
fn Context::binding_examples(
self : Context,
operation : @smithy.Shape,
binding : Binding,
phase : ExamplePhase,
) -> Map[String, Json] raise OpenApiError {
let out : Map[String, Json] = Map([])
let member_name = binding.shape.id.member_name().unwrap()
for (example, values) in self.example_rows(operation, phase) {
if values.get(member_name) is Some(value) {
out[operation.id.name() + "_example" + example.ordinal.to_string()] = example_object(
example,
self.example_value(binding.shape, value),
)
}
}
out
}
///|
fn Context::document_examples(
self : Context,
operation : @smithy.Shape,
container : @smithy.ShapeId,
members : Array[@smithy.Shape],
phase : ExamplePhase,
) -> Map[String, Json] raise OpenApiError {
let out : Map[String, Json] = Map([])
for (example, values) in self.example_rows(operation, phase) {
let selected : Map[String, @smithy.NodeValue] = Map([])
match phase {
FailedExample(_) =>
for key, value in values {
selected[key] = value
}
_ =>
for shape in members {
let name = shape.id.member_name().unwrap()
if values.get(name) is Some(value) {
selected[name] = value
}
}
}
let value = match self.model.shapes.get(container) {
Some(shape) => self.example_value(shape, @smithy.Object(selected))
None => @smithy.Object(selected)
}
out[operation.id.name() + "_example" + example.ordinal.to_string()] = example_object(
example, value,
)
}
out
}
///|
fn content_examples(content : Json, examples : Map[String, Json]) -> Json {
if examples.is_empty() {
return content
}
let out : Map[String, Json] = Map([])
for media_type, value in fields(content) {
let item = copy_fields(value)
item["examples"] = Json::object(examples)
out[media_type] = Json::object(item)
}
Json::object(out)
}