From ab7ed34dc05e56ca9dd8146abd4a8063bdfaa9ea Mon Sep 17 00:00:00 2001 From: Alexey Bashtanov Date: Mon, 23 Sep 2024 15:00:25 +0100 Subject: [PATCH] json2code: allow "$ref" for custom type references Swagger only allows to refer to custom composite types via "$ref", not via "type", whether it is about array elements or individual items. Disallowing "type" would break existing use, so allow "$ref" to be used interchangeably. Signed-off-by: Alexey Bashtanov --- scripts/seastar-json2code.py | 18 +++++++++--------- tests/unit/api.json | 13 +++++++++++-- tests/unit/json2code_test.py | 4 ++-- tests/unit/rest_api_httpd.cc | 4 +++- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/scripts/seastar-json2code.py b/scripts/seastar-json2code.py index 298bc9746fd..673742d37d7 100755 --- a/scripts/seastar-json2code.py +++ b/scripts/seastar-json2code.py @@ -364,22 +364,22 @@ def add_operation(hfile, ccfile, path, oper): def get_base_name(param): return os.path.basename(param) +def get_referenced_type(schema, name): + # to be backward compatible, support "type" as well + type = schema.get("$ref") or schema.get("type") + if type is None: + raise Exception(f"neither '$ref' nor 'type' found in {name}") + return type def is_model_valid(name, model): if name in valid_vars: return "" properties = getitem(model[name], "properties", name) for var in properties: - type = getitem(properties[var], "type", name + ":" + var) + type = get_referenced_type(properties[var], name + ":" + var) if type == "array": items = getitem(properties[var], "items", name + ":" + var) - try: - type = getitem(items, "type", name + ":" + var + ":items") - except Exception as e: - try: - type = getitem(items, "$ref", name + ":" + var + ":items") - except: - raise e + type = get_referenced_type(items, name + ":" + var + ":items") if type not in valid_vars: if type not in model: raise Exception("Unknown type '" + type + "' in Model '" + name + "'") @@ -563,7 +563,7 @@ def indent(s): fprintln(hfile, create_enum_wrapper(model_name, member_name, member["enum"])) fprintln(hfile, f" {config.jsonns}::json_element<{member_name}_wrapper> {member_name};\n") else: - type_name = type_change(member["type"], member) + type_name = type_change(member["type"] if "type" in member else member["$ref"], member) fprintln(hfile, f" {config.jsonns}::{type_name} {member_name};\n") member_init += f'add(&{member_name}, "{member_name}");\n' member_assignment += f'{member_name} = e.{member_name};\n' diff --git a/tests/unit/api.json b/tests/unit/api.json index 8132a37e395..f09fd030326 100644 --- a/tests/unit/api.json +++ b/tests/unit/api.json @@ -54,6 +54,15 @@ } ], "models": { + "var2_referred": { + "type": "object", + "properties": { + "var21": { + "type": "string", + "description": "The inner part of the second parameter" + } + } + }, "my_object": { "id": "my_object", "description": "Demonstrate an object", @@ -63,8 +72,8 @@ "description": "The first parameter in the path" }, "var2": { - "type": "string", - "description": "The second parameter in the path" + "$ref": "var2_referred", + "description": "The second parameter in the path wrapped in an object" }, "enum_var": { "type": "string", diff --git a/tests/unit/json2code_test.py b/tests/unit/json2code_test.py index 46c912bb76f..a4c8d98dbe5 100755 --- a/tests/unit/json2code_test.py +++ b/tests/unit/json2code_test.py @@ -57,7 +57,7 @@ def test_path_params(self): with urllib.request.urlopen(url) as f: response = json.loads(f.read().decode('utf-8')) self.assertEqual(response['var1'], f'/{var1}') - self.assertEqual(response['var2'], f'/{var2}') + self.assertEqual(response['var2']['var21'], f'/{var2}') self.assertEqual(response['enum_var'], query_enum) def test_bad_enum(self): @@ -69,7 +69,7 @@ def test_bad_enum(self): with urllib.request.urlopen(url) as f: response = json.loads(f.read().decode('utf-8')) self.assertEqual(response['var1'], f'/{var1}') - self.assertEqual(response['var2'], f'/{var2}') + self.assertEqual(response['var2']['var21'], f'/{var2}') self.assertEqual(response['enum_var'], 'Unknown') def test_missing_path_param(self): diff --git a/tests/unit/rest_api_httpd.cc b/tests/unit/rest_api_httpd.cc index db29247f932..11f1d450d11 100644 --- a/tests/unit/rest_api_httpd.cc +++ b/tests/unit/rest_api_httpd.cc @@ -43,7 +43,9 @@ void set_routes(routes& r) { api_json::hello_world.set(r, [] (const_req req) { api_json::my_object obj; obj.var1 = req.param.at("var1"); - obj.var2 = req.param.at("var2"); + api_json::var2_referred var2_wrapped; + var2_wrapped.var21 = req.param.at("var2"); + obj.var2 = var2_wrapped; api_json::ns_hello_world::query_enum v = api_json::ns_hello_world::str2query_enum(req.query_parameters.at("query_enum")); // This demonstrate enum conversion obj.enum_var = v;