diff --git a/lib/schemas/jsonrpc/model_request.v b/lib/schemas/jsonrpc/model_request.v index 1c80c59e..1b1bc110 100644 --- a/lib/schemas/jsonrpc/model_request.v +++ b/lib/schemas/jsonrpc/model_request.v @@ -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] } diff --git a/lib/schemas/openapi/decode.v b/lib/schemas/openapi/decode.v index 13059997..1f378c87 100644 --- a/lib/schemas/openapi/decode.v +++ b/lib/schemas/openapi/decode.v @@ -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 diff --git a/lib/schemas/openrpc/decode.v b/lib/schemas/openrpc/decode.v index 2309cf4f..f91982c6 100644 --- a/lib/schemas/openrpc/decode.v +++ b/lib/schemas/openrpc/decode.v @@ -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())!