feat: generate dynamic API docs from OpenRPC spec
- Implement dynamic doc generation from OpenRPC methods - Generate example calls and responses from schemas - Improve OpenRPC and JSON Schema decoders for full parsing - Add example value generation based on schema type - Add tests for schema decoding with examples
This commit is contained in:
@@ -4,6 +4,30 @@ pub fn (schema Schema) type_() string {
|
||||
return schema.typ.str()
|
||||
}
|
||||
|
||||
// example_value generates a basic example value based on the schema type.
|
||||
// Returns a JSON-formatted string appropriate for the schema type.
|
||||
pub fn (schema Schema) example_value() string {
|
||||
return ''
|
||||
}
|
||||
// Check if schema has an explicit example value (ignore empty arrays which indicate no example)
|
||||
example_str := schema.example.str()
|
||||
if example_str != '' && example_str != '[]' {
|
||||
// For object examples, return the JSON string as-is
|
||||
if schema.typ == 'object' || example_str.starts_with('{') {
|
||||
return example_str
|
||||
}
|
||||
// For string types, ensure proper JSON formatting with quotes
|
||||
if schema.typ == 'string' && !example_str.starts_with('"') {
|
||||
return '"${example_str}"'
|
||||
}
|
||||
return example_str
|
||||
}
|
||||
|
||||
// Generate type-based example when no explicit example is provided
|
||||
match schema.typ {
|
||||
'string' { return '"example_value"' }
|
||||
'integer', 'number' { return '42' }
|
||||
'boolean' { return 'true' }
|
||||
'array' { return '[]' }
|
||||
'object' { return '{}' }
|
||||
else { return '"example_value"' }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,14 @@ module jsonschema
|
||||
import x.json2 { Any }
|
||||
import json
|
||||
|
||||
// decode parses a JSON Schema string into a Schema struct.
|
||||
// Handles complex fields like properties, additionalProperties, items, and examples
|
||||
// that require custom parsing beyond standard JSON decoding.
|
||||
pub fn decode(data string) !Schema {
|
||||
schema_map := json2.raw_decode(data)!.as_map()
|
||||
mut schema := json.decode(Schema, data)!
|
||||
|
||||
// Process fields that require custom decoding
|
||||
for key, value in schema_map {
|
||||
if key == 'properties' {
|
||||
schema.properties = decode_schemaref_map(value.as_map())!
|
||||
@@ -13,6 +18,9 @@ pub fn decode(data string) !Schema {
|
||||
schema.additional_properties = decode_schemaref(value.as_map())!
|
||||
} else if key == 'items' {
|
||||
schema.items = decode_items(value)!
|
||||
} else if key == 'example' {
|
||||
// Manually handle example field since it's marked with @[json: '-'] in the Schema struct
|
||||
schema.example = value
|
||||
}
|
||||
}
|
||||
return schema
|
||||
@@ -41,11 +49,15 @@ pub fn decode_schemaref_map(data_map map[string]Any) !map[string]SchemaRef {
|
||||
return schemaref_map
|
||||
}
|
||||
|
||||
// decode_schemaref parses a map into either a Schema or Reference.
|
||||
// Handles both direct schema definitions and $ref references to external schemas.
|
||||
pub fn decode_schemaref(data_map map[string]Any) !SchemaRef {
|
||||
if ref := data_map['\$ref'] {
|
||||
return Reference{
|
||||
ref: ref.str()
|
||||
}
|
||||
}
|
||||
return decode(data_map.str())!
|
||||
// Convert map back to JSON string for proper schema decoding with custom field handling
|
||||
json_str := json2.encode(data_map)
|
||||
return decode(json_str)!
|
||||
}
|
||||
|
||||
@@ -42,3 +42,49 @@ fn test_decode_schemaref() ! {
|
||||
required: ['name']
|
||||
}
|
||||
}
|
||||
|
||||
fn test_decode_with_example() ! {
|
||||
// Test schema with example field
|
||||
schema_with_example := '{
|
||||
"type": "string",
|
||||
"description": "A test string",
|
||||
"example": "test_value"
|
||||
}'
|
||||
|
||||
schema := decode(schema_with_example)!
|
||||
assert schema.typ == 'string'
|
||||
assert schema.description == 'A test string'
|
||||
assert schema.example.str() == 'test_value'
|
||||
}
|
||||
|
||||
fn test_decode_with_object_example() ! {
|
||||
// Test schema with object example
|
||||
schema_with_object_example := '{
|
||||
"type": "object",
|
||||
"description": "A test object",
|
||||
"example": {
|
||||
"name": "test",
|
||||
"value": 123
|
||||
}
|
||||
}'
|
||||
|
||||
schema := decode(schema_with_object_example)!
|
||||
assert schema.typ == 'object'
|
||||
assert schema.description == 'A test object'
|
||||
// Object examples are stored as json2.Any and need special handling
|
||||
assert schema.example.str().contains('test')
|
||||
}
|
||||
|
||||
fn test_decode_without_example() ! {
|
||||
// Test schema without example field
|
||||
schema_without_example := '{
|
||||
"type": "integer",
|
||||
"description": "A test integer"
|
||||
}'
|
||||
|
||||
schema := decode(schema_without_example)!
|
||||
assert schema.typ == 'integer'
|
||||
assert schema.description == 'A test integer'
|
||||
// Should have empty example
|
||||
assert schema.example.str() == '[]'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user