make schema models and methods more defensive
This commit is contained in:
@@ -8,7 +8,7 @@ pub struct Request {
|
||||
pub mut:
|
||||
jsonrpc string @[required] // JSON-RPC version, e.g., "2.0"
|
||||
method string @[required] // Method to invoke
|
||||
params string @[required] // JSON-encoded parameters
|
||||
params string // JSON-encoded parameters
|
||||
id string @[required] // Unique request ID
|
||||
}
|
||||
|
||||
@@ -32,12 +32,23 @@ pub fn (req Request) encode() string {
|
||||
return json2.encode(req)
|
||||
}
|
||||
|
||||
// Validates that the response does not contain both `result` and `error`.
|
||||
pub fn (req Request) validate() ! {
|
||||
if req.jsonrpc == '' {
|
||||
return error('request jsonrpc version not specified')
|
||||
} else if req.id == '' {
|
||||
return error('request id is empty')
|
||||
} else if req.method == '' {
|
||||
return error('request method is empty')
|
||||
}
|
||||
}
|
||||
|
||||
// A generic JSON-RPC request struct allowing strongly-typed parameters.
|
||||
pub struct RequestGeneric[T] {
|
||||
pub mut:
|
||||
jsonrpc string @[required]
|
||||
method string @[required]
|
||||
params T @[required]
|
||||
params T
|
||||
id string @[required]
|
||||
}
|
||||
|
||||
|
||||
@@ -15,15 +15,15 @@ pub fn json_decode(data string) !OpenAPI {
|
||||
|
||||
// Decode all schema and schemaref fields using `jsonschema.decode_schemaref`
|
||||
// 1. Process components.schemas
|
||||
if 'paths' in raw_map {
|
||||
mut paths := raw_map['paths'].as_map()
|
||||
if paths_any := raw_map['paths'] {
|
||||
mut paths := paths_any.as_map()
|
||||
for key, path in paths {
|
||||
spec.paths[key] = json_decode_path(spec.paths[key], path.as_map())!
|
||||
}
|
||||
}
|
||||
|
||||
if 'components' in raw_map {
|
||||
components_map := raw_map['components'].as_map()
|
||||
if components_any := raw_map['components'] {
|
||||
components_map := components_any.as_map()
|
||||
spec.components = json_decode_components(spec.components, components_map)!
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ pub fn json_decode(data string) !OpenAPI {
|
||||
pub fn json_decode_components(components_ Components, components_map map[string]Any) !Components {
|
||||
mut components := components_
|
||||
|
||||
if 'schemas' in components_map {
|
||||
components.schemas = jsonschema.decode_schemaref_map(components_map['schemas'].as_map())!
|
||||
if schemas_any := components_map['schemas'] {
|
||||
components.schemas = jsonschema.decode_schemaref_map(schemas_any.as_map())!
|
||||
}
|
||||
return components
|
||||
}
|
||||
@@ -44,37 +44,33 @@ pub fn json_decode_path(path_ PathItem, path_map map[string]Any) !PathItem {
|
||||
mut path := path_
|
||||
|
||||
for key in path_map.keys() {
|
||||
operation_any := path_map[key] or {
|
||||
panic('This should never happen')
|
||||
}
|
||||
operation_map := operation_any.as_map()
|
||||
match key {
|
||||
'get' {
|
||||
operation_map := path_map[key].as_map()
|
||||
path.get = json_decode_operation(path.get, operation_map)!
|
||||
}
|
||||
'post' {
|
||||
operation_map := path_map[key].as_map()
|
||||
path.post = json_decode_operation(path.post, operation_map)!
|
||||
}
|
||||
'put' {
|
||||
operation_map := path_map[key].as_map()
|
||||
path.put = json_decode_operation(path.put, operation_map)!
|
||||
}
|
||||
'delete' {
|
||||
operation_map := path_map[key].as_map()
|
||||
path.delete = json_decode_operation(path.delete, operation_map)!
|
||||
}
|
||||
'options' {
|
||||
operation_map := path_map[key].as_map()
|
||||
path.options = json_decode_operation(path.options, operation_map)!
|
||||
}
|
||||
'head' {
|
||||
operation_map := path_map[key].as_map()
|
||||
path.head = json_decode_operation(path.head, operation_map)!
|
||||
}
|
||||
'patch' {
|
||||
operation_map := path_map[key].as_map()
|
||||
path.patch = json_decode_operation(path.patch, operation_map)!
|
||||
}
|
||||
'trace' {
|
||||
operation_map := path_map[key].as_map()
|
||||
path.trace = json_decode_operation(path.trace, operation_map)!
|
||||
}
|
||||
else {
|
||||
@@ -88,42 +84,41 @@ pub fn json_decode_path(path_ PathItem, path_map map[string]Any) !PathItem {
|
||||
pub fn json_decode_operation(operation_ Operation, operation_map map[string]Any) !Operation {
|
||||
mut operation := operation_
|
||||
|
||||
if 'requestBody' in operation_map {
|
||||
request_body_any := operation_map['requestBody']
|
||||
if request_body_any := operation_map['requestBody'] {
|
||||
request_body_map := request_body_any.as_map()
|
||||
|
||||
if 'content' in request_body_map {
|
||||
if content_any := request_body_map['content'] {
|
||||
mut request_body := json.decode(RequestBody, request_body_any.str())!
|
||||
// mut request_body := operation.request_body as RequestBody
|
||||
mut content := request_body.content.clone()
|
||||
content_map := request_body_map['content'].as_map()
|
||||
content_map := content_any.as_map()
|
||||
request_body.content = json_decode_content(content, content_map)!
|
||||
operation.request_body = request_body
|
||||
}
|
||||
}
|
||||
|
||||
if 'responses' in operation_map {
|
||||
responses_map := operation_map['responses'].as_map()
|
||||
if responses_any := operation_map['responses'] {
|
||||
responses_map := responses_any.as_map()
|
||||
for key, response_any in responses_map {
|
||||
response_map := response_any.as_map()
|
||||
if 'content' in response_map {
|
||||
if content_any := response_map['content'] {
|
||||
mut response := operation.responses[key]
|
||||
mut content := response.content.clone()
|
||||
content_map := response_map['content'].as_map()
|
||||
content_map := content_any.as_map()
|
||||
response.content = json_decode_content(content, content_map)!
|
||||
operation.responses[key] = response
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if 'parameters' in operation_map {
|
||||
parameters_arr := operation_map['parameters'].arr()
|
||||
if parameters_any := operation_map['parameters'] {
|
||||
parameters_arr := parameters_any.arr()
|
||||
mut parameters := []Parameter{}
|
||||
for i, parameter_any in parameters_arr {
|
||||
parameter_map := parameter_any.as_map()
|
||||
if 'schema' in parameter_map {
|
||||
if schema_any := parameter_map['schema'] {
|
||||
mut parameter := operation.parameters[i]
|
||||
parameter.schema = jsonschema.decode_schemaref(parameter_map['schema'].as_map())!
|
||||
parameter.schema = jsonschema.decode_schemaref(schema_any.as_map())!
|
||||
parameters << parameter
|
||||
} else {
|
||||
parameters << operation.parameters[i]
|
||||
@@ -139,9 +134,10 @@ fn json_decode_content(content_ map[string]MediaType, content_map map[string]Any
|
||||
mut content := content_.clone()
|
||||
for key, item in content_map {
|
||||
media_type_map := item.as_map()
|
||||
schema_any := media_type_map['schema']
|
||||
mut media_type := content[key]
|
||||
media_type.schema = jsonschema.decode_schemaref(schema_any.as_map())!
|
||||
if schema_any := media_type_map['schema'] {
|
||||
media_type.schema = jsonschema.decode_schemaref(schema_any.as_map())!
|
||||
}
|
||||
content[key] = media_type
|
||||
}
|
||||
return content
|
||||
|
||||
@@ -13,19 +13,20 @@ pub fn decode(data string) !OpenRPC {
|
||||
}
|
||||
}
|
||||
|
||||
for i, method in data_map['methods'].arr() {
|
||||
methods_any := data_map['methods'] or {return object}
|
||||
for i, method in methods_any.arr() {
|
||||
method_map := method.as_map()
|
||||
params_arr := method_map['params'].arr()
|
||||
result := if 'result' in method_map {
|
||||
method_map['result']
|
||||
} else {
|
||||
''
|
||||
|
||||
if result_any := method_map['result'] {
|
||||
object.methods[i].result = decode_content_descriptor_ref(result_any.as_map()) or {
|
||||
return error('Failed to decode result\n${err}')
|
||||
}
|
||||
}
|
||||
object.methods[i].params = params_arr.map(decode_content_descriptor_ref(it.as_map()) or {
|
||||
return error('Failed to decode params\n${err}')
|
||||
})
|
||||
object.methods[i].result = decode_content_descriptor_ref(result.as_map()) or {
|
||||
return error('Failed to decode result\n${err}')
|
||||
if params_any := method_map['params'] {
|
||||
params_arr := params_any.arr()
|
||||
object.methods[i].params = params_arr.map(decode_content_descriptor_ref(it.as_map()) or {
|
||||
return error('Failed to decode params\n${err}')
|
||||
})
|
||||
}
|
||||
}
|
||||
// object.methods = decode_method(data_map['methods'].as_array)!
|
||||
@@ -50,18 +51,21 @@ pub fn decode(data string) !OpenRPC {
|
||||
|
||||
fn decode_components(data_map map[string]Any) !Components {
|
||||
mut components := Components{}
|
||||
components_map := data_map['components'].as_map()
|
||||
mut components_map := map[string]Any
|
||||
if components_any := data_map['components'] {
|
||||
components_map = components_any.as_map()
|
||||
}
|
||||
|
||||
if 'contentDescriptors' in components_map {
|
||||
descriptors_map := components_map['contentDescriptors'].as_map()
|
||||
if cd_any := components_map['contentDescriptors'] {
|
||||
descriptors_map := cd_any.as_map()
|
||||
for key, value in descriptors_map {
|
||||
descriptor := decode_content_descriptor_ref(value.as_map())!
|
||||
components.content_descriptors[key] = descriptor
|
||||
}
|
||||
}
|
||||
|
||||
if 'schemas' in components_map {
|
||||
schemas_map := components_map['schemas'].as_map()
|
||||
if schemas_any := components_map['schemas'] {
|
||||
schemas_map := schemas_any.as_map()
|
||||
for key, value in schemas_map {
|
||||
schema := jsonschema.decode(value.str())!
|
||||
components.schemas[key] = schema
|
||||
@@ -72,9 +76,9 @@ fn decode_components(data_map map[string]Any) !Components {
|
||||
}
|
||||
|
||||
fn decode_content_descriptor_ref(data_map map[string]Any) !ContentDescriptorRef {
|
||||
if '\$ref' in data_map {
|
||||
if ref_any := data_map['\$ref'] {
|
||||
return Reference{
|
||||
ref: data_map['\$ref'].str()
|
||||
ref: ref_any.str()
|
||||
}
|
||||
}
|
||||
mut descriptor := json.decode(ContentDescriptor, data_map.str())!
|
||||
|
||||
Reference in New Issue
Block a user