refactor: Update example generation and schema handling
- Remove unused `generate_example_call` and `generate_example_response` functions - Rename `example_call` to `example_request` in `DocMethod` - Update schema example extraction to use `schema.example` directly - Introduce `generate_request_example` and `generate_response_example` for dynamic example generation - Change type of `id` from string to number in schema examples PS: The work is still in progress
This commit is contained in:
@@ -37,8 +37,8 @@
|
||||
"description": "The unique identifier of the comment to retrieve.",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"example": "comment_12345"
|
||||
"type": "number",
|
||||
"example": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -57,7 +57,7 @@
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"example": {
|
||||
"id": "comment_12345",
|
||||
"id": 1,
|
||||
"text": "This is a sample comment",
|
||||
"created_at": "2024-01-15T10:30:00Z"
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ pub mut:
|
||||
description string
|
||||
params []DocParam
|
||||
result DocParam
|
||||
example_call string
|
||||
example_request string
|
||||
example_response string
|
||||
endpoint_url string
|
||||
curl_example string
|
||||
@@ -105,13 +105,17 @@ pub fn doc_spec_from_openrpc_with_config(openrpc_spec openrpc.OpenRPC, config Do
|
||||
fn process_method(method openrpc.Method, config DocConfig) !DocMethod {
|
||||
// Convert parameters
|
||||
doc_params := process_parameters(method.params)!
|
||||
example_request := generate_request_example(doc_params)!
|
||||
|
||||
// Convert result
|
||||
doc_result := process_result(method.result)!
|
||||
example_response := if doc_result.example.len > 0 {
|
||||
doc_result.example
|
||||
} else {
|
||||
generate_response_example(doc_result)!
|
||||
}
|
||||
|
||||
// Generate examples
|
||||
example_call := generate_example_call(doc_params)
|
||||
example_response := generate_example_response(doc_result)
|
||||
// example_call := generate_example_call(doc_params)
|
||||
|
||||
doc_method := DocMethod{
|
||||
name: method.name
|
||||
@@ -119,13 +123,15 @@ fn process_method(method openrpc.Method, config DocConfig) !DocMethod {
|
||||
description: method.description
|
||||
params: doc_params
|
||||
result: doc_result
|
||||
endpoint_url: '${config.base_url}/api/${config.handler_type}'
|
||||
example_call: example_call
|
||||
example_response: example_response
|
||||
curl_example: generate_curl_example_jsonrpc(method.name, doc_params, config.base_url,
|
||||
config.handler_type)
|
||||
example_request: example_request
|
||||
}
|
||||
|
||||
// endpoint_url: '${config.base_url}/api/${config.handler_type}'
|
||||
// example_call: example_call
|
||||
// curl_example: generate_curl_example_jsonrpc(method.name, doc_params, config.base_url,
|
||||
// config.handler_type)
|
||||
|
||||
return doc_method
|
||||
}
|
||||
|
||||
@@ -136,7 +142,7 @@ fn process_parameters(params []openrpc.ContentDescriptorRef) ![]DocParam {
|
||||
for param in params {
|
||||
if param is openrpc.ContentDescriptor {
|
||||
type_info := extract_type_from_schema(param.schema)
|
||||
example := generate_example_from_schema(param.schema, param.name)
|
||||
example := extract_example_from_schema(param.schema)
|
||||
|
||||
doc_params << DocParam{
|
||||
name: param.name
|
||||
@@ -157,14 +163,14 @@ fn process_result(result openrpc.ContentDescriptorRef) !DocParam {
|
||||
|
||||
if result is openrpc.ContentDescriptor {
|
||||
type_info := extract_type_from_schema(result.schema)
|
||||
example := generate_example_from_schema(result.schema, result.name)
|
||||
example := extract_example_from_schema(result.schema)
|
||||
|
||||
doc_result = DocParam{
|
||||
name: result.name
|
||||
description: result.description
|
||||
type_info: type_info
|
||||
required: false // Results are never required
|
||||
example: example
|
||||
// required: false // Results are never required
|
||||
example: example
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,10 +207,8 @@ fn extract_type_from_schema(schema_ref jsonschema.SchemaRef) string {
|
||||
return 'unknown'
|
||||
}
|
||||
|
||||
// generate_example_from_schema creates an example value for a parameter or result.
|
||||
// Uses the jsonschema.Schema.example_value() method with parameter name customization for strings.
|
||||
// Returns properly formatted JSON values based on the schema type.
|
||||
fn generate_example_from_schema(schema_ref jsonschema.SchemaRef, param_name string) string {
|
||||
// extract_example_from_schema extracts the example value from a SchemaRef
|
||||
fn extract_example_from_schema(schema_ref jsonschema.SchemaRef) string {
|
||||
schema := match schema_ref {
|
||||
jsonschema.Schema {
|
||||
schema_ref
|
||||
@@ -214,40 +218,22 @@ fn generate_example_from_schema(schema_ref jsonschema.SchemaRef, param_name stri
|
||||
}
|
||||
}
|
||||
|
||||
// Use the improved example_value() method from jsonschema module
|
||||
example := schema.example_value()
|
||||
|
||||
// For string types without explicit examples, customize with parameter name
|
||||
if example == '"example_value"' && schema.typ == 'string' && param_name != '' {
|
||||
return '"example_${param_name}"'
|
||||
if schema.example.str() != '' {
|
||||
return schema.example.str()
|
||||
}
|
||||
|
||||
return example
|
||||
return ''
|
||||
}
|
||||
|
||||
// generate_example_call creates a formatted JSON example for method calls.
|
||||
// Combines all parameter examples into a properly formatted JSON object.
|
||||
fn generate_example_call(params []DocParam) string {
|
||||
if params.len == 0 {
|
||||
return '{}'
|
||||
// generate_example_from_schema creates an example value for a parameter or result
|
||||
fn generate_example_from_schema(schema_ref jsonschema.SchemaRef, param_name string) string {
|
||||
match schema_ref {
|
||||
jsonschema.Schema {
|
||||
return '"example_value"'
|
||||
}
|
||||
jsonschema.Reference {
|
||||
return '"reference_value"'
|
||||
}
|
||||
}
|
||||
|
||||
mut call_parts := []string{}
|
||||
for param in params {
|
||||
call_parts << '"${param.name}": ${param.example}'
|
||||
}
|
||||
|
||||
return '{\n ${call_parts.join(',\n ')}\n}'
|
||||
}
|
||||
|
||||
// generate_example_response creates a formatted JSON example for method responses.
|
||||
// Wraps the result example in a standard {"result": ...} format.
|
||||
fn generate_example_response(result DocParam) string {
|
||||
if result.name == '' {
|
||||
return '{"result": "success"}'
|
||||
}
|
||||
|
||||
return '{"result": ${result.example}}'
|
||||
}
|
||||
|
||||
// Create authentication documentation info
|
||||
@@ -290,41 +276,3 @@ fn create_auth_info() AuthDocInfo {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// generate_jsonrpc_example_call creates a complete JSON-RPC request example
|
||||
fn generate_jsonrpc_example_call(method_name string, params []DocParam) string {
|
||||
params_obj := if params.len == 0 {
|
||||
'{}'
|
||||
} else {
|
||||
mut call_parts := []string{}
|
||||
for param in params {
|
||||
call_parts << '"${param.name}": ${param.example}'
|
||||
}
|
||||
'{\n ${call_parts.join(',\n ')}\n }'
|
||||
}
|
||||
|
||||
return '{\n "jsonrpc": "2.0",\n "method": "${method_name}",\n "params": ${params_obj},\n "id": 1\n}'
|
||||
}
|
||||
|
||||
// generate_curl_example_jsonrpc creates a curl command with proper JSON-RPC format
|
||||
fn generate_curl_example_jsonrpc(method_name string, params []DocParam, base_url string, handler_name string) string {
|
||||
endpoint := '${base_url}/api/${handler_name}'
|
||||
jsonrpc_request := generate_jsonrpc_example_call(method_name, params)
|
||||
|
||||
mut curl_cmd := 'curl -X POST ${endpoint} \\\n'
|
||||
curl_cmd += ' -H "Content-Type: application/json" \\\n'
|
||||
curl_cmd += ' -d \'${jsonrpc_request}\''
|
||||
|
||||
return curl_cmd
|
||||
}
|
||||
|
||||
// generate_curl_example creates a curl command for the given method (legacy)
|
||||
pub fn generate_curl_example(method DocMethod, base_url string, handler_name string) string {
|
||||
endpoint := '${base_url}/api/${handler_name}'
|
||||
|
||||
mut curl_cmd := 'curl -X POST ${endpoint} \\\n'
|
||||
curl_cmd += ' -H "Content-Type: application/json" \\\n'
|
||||
curl_cmd += ' -d \'${method.example_call}\''
|
||||
|
||||
return curl_cmd
|
||||
}
|
||||
|
||||
45
lib/hero/heroserver/examples.v
Normal file
45
lib/hero/heroserver/examples.v
Normal file
@@ -0,0 +1,45 @@
|
||||
module heroserver
|
||||
|
||||
import rand
|
||||
|
||||
fn generate_request_example[T](model T) !string {
|
||||
mut field_parts := []string{} // Build JSON manually to avoid type conflicts
|
||||
|
||||
for param in model {
|
||||
value := match param.type_info.to_lower() {
|
||||
'string', 'str', 'text' {
|
||||
'"${rand.string(10)}"'
|
||||
}
|
||||
'integer', 'int', 'number' {
|
||||
'${rand.intn(1000)!}'
|
||||
}
|
||||
'boolean', 'bool' {
|
||||
if rand.intn(2)! == 0 { 'false' } else { 'true' }
|
||||
}
|
||||
'array', '[]' {
|
||||
'[]'
|
||||
}
|
||||
'object' {
|
||||
'{}'
|
||||
}
|
||||
else {
|
||||
// handle generic cases like `[int]`, `[string]`, `map[string]int`, etc.
|
||||
if param.type_info.starts_with('[') {
|
||||
'[]'
|
||||
} else if param.type_info.starts_with('map') {
|
||||
'{}'
|
||||
} else {
|
||||
'"example_value"'
|
||||
}
|
||||
}
|
||||
}
|
||||
field_parts << '"${param.name}": ${value}'
|
||||
}
|
||||
|
||||
return '{${field_parts.join(', ')}}'
|
||||
}
|
||||
|
||||
fn generate_response_example[T](model T) !string {
|
||||
println('response model: ${model}')
|
||||
return 'xxxx'
|
||||
}
|
||||
@@ -58,13 +58,12 @@ pub fn (mut server HeroServer) start() ! {
|
||||
}
|
||||
|
||||
// Start VEB server
|
||||
handler_name := server.handlers.keys()[0]
|
||||
console.print_item('Server starting on http://${server.host}:${server.port}')
|
||||
console.print_item('HTML Homepage: http://${server.host}:${server.port}/')
|
||||
console.print_item('JSON Info: http://${server.host}:${server.port}/json/${handler_name}')
|
||||
console.print_item('Documentation: http://${server.host}:${server.port}/doc/${handler_name}')
|
||||
console.print_item('Markdown Docs: http://${server.host}:${server.port}/md/${handler_name}')
|
||||
console.print_item('API Endpoint: http://${server.host}:${server.port}/api/${handler_name}')
|
||||
console.print_item('JSON Info: http://${server.host}:${server.port}/json/{handler_name}')
|
||||
console.print_item('Documentation: http://${server.host}:${server.port}/doc/{handler_name}')
|
||||
console.print_item('Markdown Docs: http://${server.host}:${server.port}/md/{handler_name}')
|
||||
console.print_item('API Endpoint: http://${server.host}:${server.port}/api/{handler_name}')
|
||||
|
||||
veb.run[HeroServer, Context](mut server, server.port)
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@
|
||||
<div class="col-md-6">
|
||||
<h6>Example Request:</h6>
|
||||
<div class="code-block">
|
||||
<pre>${method.example_call}</pre>
|
||||
<pre>${method.example_request}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
@@ -383,7 +383,7 @@
|
||||
<div class="col-md-6">
|
||||
<h6>Example Request:</h6>
|
||||
<div class="code-block">
|
||||
<pre>${method.example_call}</pre>
|
||||
<pre>${method.example_request}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
|
||||
@@ -4,30 +4,33 @@ 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 {
|
||||
// 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
|
||||
}
|
||||
// // 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[T](model T) T {
|
||||
// obj := T{}
|
||||
// return obj
|
||||
// // // Check if schema has an explicit example value (ignore empty arrays which indicate no example)
|
||||
// // example_str := schema.example.str()
|
||||
// // println('example_str: ${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"' }
|
||||
}
|
||||
}
|
||||
// // // 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"' }
|
||||
// // }
|
||||
// }
|
||||
|
||||
@@ -19,7 +19,6 @@ pub fn decode(data string) !Schema {
|
||||
} 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +1,43 @@
|
||||
module openrpc
|
||||
|
||||
import json
|
||||
import x.json2
|
||||
import freeflowuniverse.herolib.schemas.jsonschema
|
||||
|
||||
// In Method struct
|
||||
pub fn (method Method) example() (string, string) {
|
||||
// Extract user-provided examples from the OpenRPC specification
|
||||
|
||||
// // In the OpenRPC specification struct
|
||||
// pub fn (spec OpenRPC) methods_by_object() map[string][]Method {
|
||||
// mut grouped := map[string][]Method{}
|
||||
|
||||
// for method in spec.methods {
|
||||
// // Extract root object from method name (e.g., "calendar.create" -> "calendar")
|
||||
// parts := method.name.split('.')
|
||||
// root_object := if parts.len > 1 { parts[0] } else { 'general' }
|
||||
|
||||
// if root_object !in grouped {
|
||||
// grouped[root_object] = []Method{}
|
||||
// }
|
||||
// grouped[root_object] << method
|
||||
// }
|
||||
|
||||
// return grouped
|
||||
// }
|
||||
mut example_params := map[string]json2.Any{}
|
||||
for param in method.params {
|
||||
if param is ContentDescriptor {
|
||||
param_desc := param as ContentDescriptor
|
||||
if param_desc.schema is jsonschema.Schema {
|
||||
schema := param_desc.schema as jsonschema.Schema
|
||||
if schema.example.str() != '' {
|
||||
example_params[param_desc.name] = schema.example
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn (spec OpenRPC) get_object_description(object_name string) string {
|
||||
// // Return description for object if available
|
||||
// // Implementation depends on how objects are defined in the spec
|
||||
// return ''
|
||||
// }
|
||||
example_call := json.encode(example_params)
|
||||
|
||||
// pub fn (spec OpenRPC) name_fix() string {
|
||||
// return spec.info.title.replace(' ', '_').to_lower()
|
||||
// }
|
||||
example_response := if method.result is ContentDescriptor {
|
||||
result_desc := method.result as ContentDescriptor
|
||||
if result_desc.schema is jsonschema.Schema {
|
||||
schema := result_desc.schema as jsonschema.Schema
|
||||
if schema.example.str() != '' {
|
||||
json.encode(schema.example)
|
||||
} else {
|
||||
'{"result": "success"}'
|
||||
}
|
||||
} else {
|
||||
'{"result": "success"}'
|
||||
}
|
||||
} else {
|
||||
'{"result": "success"}'
|
||||
}
|
||||
|
||||
// // In Method struct
|
||||
// pub fn (method Method) example() (string, string) {
|
||||
// // Generate example call and response
|
||||
// // This should create realistic JSON examples based on the method schema
|
||||
|
||||
// mut example_params := map[string]string{}
|
||||
// for param in method.params {
|
||||
// param_schema_ref := param.schema
|
||||
// example_params[param.name] = match param_schema_ref {
|
||||
// openrpc.ContentDescriptor {
|
||||
// match param_schema_ref.schema {
|
||||
// jsonschema.Schema {
|
||||
// param_schema_ref.schema.example_value()
|
||||
// }
|
||||
// jsonschema.Reference {
|
||||
// ''
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// jsonschema.Reference {
|
||||
// ''
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// example_call := json.encode(example_params)
|
||||
// example_response := if method.result is openrpc.ContentDescriptor {
|
||||
// result_schema_ref := method.result
|
||||
// match result_schema_ref {
|
||||
// openrpc.ContentDescriptor {
|
||||
// match result_schema_ref.schema {
|
||||
// jsonschema.Schema {
|
||||
// result_schema_ref.schema.example_value()
|
||||
// }
|
||||
// jsonschema.Reference {
|
||||
// '{"result": "success"}'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// jsonschema.Reference {
|
||||
// '{"result": "success"}'
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// '{"result": "success"}'
|
||||
// }
|
||||
|
||||
// return example_call, example_response
|
||||
// }
|
||||
return example_call, example_response
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user