use schemars::{gen::SchemaSettings, schema::SchemaObject, Map};
use serde::Serialize;
pub use schemars as type_def;
pub use schemars::JsonSchema;
#[derive(Debug, Clone, Serialize)]
pub struct Doc {
pub openrpc: String,
pub info: Info,
pub methods: Vec<Method>,
pub components: Components,
}
#[derive(Debug, Clone, Serialize)]
pub struct Info {
pub version: String,
pub title: String,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Method {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub params: Vec<Param>,
pub result: Param,
pub param_structure: ParamStructure,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum ParamStructure {
ByName,
ByPosition,
}
#[derive(Debug, Clone, Serialize)]
pub struct Param {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub schema: SchemaObject,
pub required: bool,
}
#[derive(Debug, Clone, Serialize)]
pub struct Components {
#[serde(default, skip_serializing_if = "Map::is_empty")]
pub schemas: Map<String, SchemaObject>,
}
pub fn object_schema_to_params<T: JsonSchema>(
) -> anyhow::Result<(Vec<Param>, Map<String, SchemaObject>)> {
let (schema, definitions) = generate_schema::<T>();
let properties = match schema.object.as_ref() {
Some(obj) => &obj.properties,
None => return Err(anyhow::anyhow!("Invalid parameter definition")),
};
let mut params = vec![];
for (key, schema) in properties {
params.push(Param {
name: key.to_string(),
schema: schema.clone().into_object(),
description: None,
required: true,
});
}
Ok((params, definitions))
}
pub fn generate_schema<T: JsonSchema>() -> (SchemaObject, Map<String, SchemaObject>) {
let settings = SchemaSettings::draft07().with(|s| {
s.inline_subschemas = false;
s.definitions_path = "#/components/schemas/".to_string();
});
let mut gen = settings.into_generator();
let schema = gen.subschema_for::<T>();
let definitions: Map<String, SchemaObject> = gen
.take_definitions()
.into_iter()
.map(|(k, v)| (k, v.into_object()))
.collect();
(schema.into_object(), definitions)
}