use schemars::{schema_for, JsonSchema};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum SchemaGenerationError {
#[error("Failed to serialize schema to JSON")]
SerializationFailed {
#[source]
source: serde_json::Error,
},
}
impl SchemaGenerationError {
#[must_use]
pub fn help(&self) -> String {
match self {
Self::SerializationFailed { .. } => {
"Schema serialization failed. This is likely a bug in the schema generator.\n\
\n\
What to do:\n\
1. Check if the type has valid JsonSchema derives\n\
2. Report this as a bug if the error persists\n\
3. Include the full error message in your bug report"
.to_string()
}
}
}
}
pub struct SchemaGenerator;
impl SchemaGenerator {
pub fn generate<T: JsonSchema>() -> Result<String, SchemaGenerationError> {
let schema = schema_for!(T);
serde_json::to_string_pretty(&schema)
.map_err(|source| SchemaGenerationError::SerializationFailed { source })
}
}
#[cfg(test)]
mod tests {
use super::*;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, JsonSchema)]
struct TestConfig {
name: String,
value: i32,
}
#[test]
fn it_should_generate_valid_json_schema_when_given_valid_type() {
let result = SchemaGenerator::generate::<TestConfig>();
assert!(result.is_ok());
let schema = result.unwrap();
assert!(schema.contains("\"$schema\""));
assert!(schema.contains("\"properties\""));
}
#[test]
fn it_should_include_type_properties_in_generated_schema() {
let schema = SchemaGenerator::generate::<TestConfig>().unwrap();
assert!(schema.contains("\"name\""));
assert!(schema.contains("\"value\""));
}
#[test]
fn it_should_generate_pretty_printed_json_output() {
let schema = SchemaGenerator::generate::<TestConfig>().unwrap();
assert!(schema.contains('\n'));
assert!(schema.contains(" "));
}
#[test]
fn it_should_provide_help_text_for_serialization_error() {
let error = SchemaGenerationError::SerializationFailed {
source: serde_json::Error::io(std::io::Error::other("test")),
};
let help = error.help();
assert!(help.contains("What to do:"));
assert!(help.contains("bug"));
}
}