diff --git a/lib/baobab/stage/interfaces/openapi.v b/lib/baobab/stage/interfaces/openapi.v index 5318cb09..e1f595fc 100644 --- a/lib/baobab/stage/interfaces/openapi.v +++ b/lib/baobab/stage/interfaces/openapi.v @@ -18,12 +18,9 @@ pub fn new_openapi_interface(client Client) &OpenAPIInterface { pub fn (mut i OpenAPIInterface) handle(request openapi.Request) !openapi.Response { // Convert incoming OpenAPI request to a procedure call action := action_from_openapi_request(request) - println('debugzo3 ${action}') response := i.client.call_to_action(action) or { - println('debugzo3.5 ${err.msg()}') return err } - println('debugzo4 ${response}') return action_to_openapi_response(response) } diff --git a/lib/core/code/types.v b/lib/core/code/types.v index a7890849..6d452781 100644 --- a/lib/core/code/types.v +++ b/lib/core/code/types.v @@ -50,7 +50,7 @@ pub const type_f64 = Float{ bytes: 64 } -pub type Type = Array | Object | Result | Integer | Alias | String | Boolean | Void +pub type Type = Void | Map | Array | Object | Result | Integer | Alias | String | Boolean | Function pub struct Boolean{} @@ -94,6 +94,8 @@ pub fn (t Type) symbol() string { Alias {t.name} String {'string'} Boolean {'bool'} + Map{'map[string]${t.typ.symbol()}'} + Function{'fn ()'} Void {''} } } @@ -105,6 +107,11 @@ pub: typ Type } +pub struct Map { +pub: + typ Type +} + pub struct Object { pub: name string @@ -117,6 +124,7 @@ pub: pub fn (t Type) typescript() string { return match t { + Map {'Record'} Array { '${t.typ.typescript()}[]' } Object { t.name } Result { '${t.typ.typescript()}'} @@ -124,6 +132,7 @@ pub fn (t Type) typescript() string { Integer { 'number' } Alias {t.name} String {'string'} + Function {'func'} Void {''} } } @@ -131,4 +140,19 @@ pub fn (t Type) typescript() string { // TODO: enfore that cant be both mutable and shared pub fn (t Type) vgen() string { return t.symbol() +} + +pub fn (t Type) empty_value() string { + return match t { + Map {'{}'} + Array { '[]${t.typ.symbol()}{}' } + Object { if t.name != '' {'${t.name}{}'} else {''} } + Result { t.typ.empty_value() } + Boolean { 'false' } + Integer { '0' } + Alias {''} + String {"''"} + Function {''} + Void {''} + } } \ No newline at end of file diff --git a/lib/schemas/jsonschema/codegen/codegen.v b/lib/schemas/jsonschema/codegen/codegen.v index 270d8faa..2fc388f0 100644 --- a/lib/schemas/jsonschema/codegen/codegen.v +++ b/lib/schemas/jsonschema/codegen/codegen.v @@ -5,6 +5,7 @@ import freeflowuniverse.herolib.schemas.jsonschema { Schema, SchemaRef, Referenc const vtypes = { 'integer': 'int' + 'number': 'int' 'string': 'string' 'u32': 'u32' 'boolean': 'bool' @@ -64,9 +65,14 @@ pub fn schema_to_type(schema Schema) Type { return match schema.typ { 'object' { if schema.title == '' { - panic('Object schemas must define a title.') + panic('Object schemas must define a title. ${schema}') } - Object{schema.title} + if schema.properties.len == 0 { + if additional_props := schema.additional_properties { + code.Map{code.String{}} + } else {Object{schema.title}} + } + else {Object{schema.title}} } 'array' { // todo: handle multiple item schemas @@ -102,7 +108,7 @@ pub fn schema_to_type(schema Schema) Type { panic('unknown type `${schema.typ}` ') } } - } + } } pub fn schema_to_code(schema Schema) CodeItem { @@ -170,9 +176,8 @@ pub fn ref_to_field(schema_ref SchemaRef, name string) StructField { name: name description: schema_ref.description } - if schema_ref.typ == 'object' { - // then it is an anonymous struct - field.anon_struct = schema_to_struct(schema_ref as Schema) + if schema_ref.typ == 'object' || schema_ref.typ == 'array' { + field.typ = schemaref_to_type(schema_ref) return field } else if schema_ref.typ in vtypes { field.typ = type_from_symbol(vtypes[schema_ref.typ]) diff --git a/lib/schemas/openapi/controller_http.v b/lib/schemas/openapi/controller_http.v index 9090b958..56753bf5 100644 --- a/lib/schemas/openapi/controller_http.v +++ b/lib/schemas/openapi/controller_http.v @@ -103,7 +103,6 @@ pub fn (mut c HTTPController) endpoints(mut ctx Context, path string) veb.Result // Use OpenAPI spec to determine the response status for the error return ctx.handle_error(operation.responses, err) } - println('debugzo2 ${response}') // Return the response to the client ctx.res.set_status(response.status) diff --git a/lib/schemas/openapi/factory.v b/lib/schemas/openapi/factory.v index 0a6baab8..f79e05ba 100644 --- a/lib/schemas/openapi/factory.v +++ b/lib/schemas/openapi/factory.v @@ -3,6 +3,7 @@ module openapi import freeflowuniverse.herolib.schemas.jsonschema {Schema, SchemaRef, Reference} import freeflowuniverse.herolib.core.texttools import os +import maps @[params] pub struct Params { @@ -31,6 +32,27 @@ pub fn new(params Params) !OpenAPI { } else {specification} } +@[params] +pub struct ProcessSchema { +pub: + name string = 'Unknown' +} + +pub fn process_schema(schema Schema, params ProcessSchema) Schema { + return Schema { + ...schema + id: if schema.id != '' && schema.typ == 'object' { schema.id } + else if schema.title != '' { schema.title } + else { params.name } + title: if schema.title != '' && schema.typ == 'object' { schema.title } + else if schema.id != '' { schema.id } + else { params.name } + properties: maps.to_map[string, SchemaRef, string, SchemaRef](schema.properties, fn (k string, v SchemaRef) (string, SchemaRef) { + return k, if v is Schema {SchemaRef(process_schema(v))} else {v} + }) + } +} + pub fn process(spec OpenAPI) !OpenAPI { mut processed := OpenAPI{...spec paths: spec.paths.clone() @@ -38,16 +60,7 @@ pub fn process(spec OpenAPI) !OpenAPI { for key, schema in spec.components.schemas { if schema is Schema { - mut processed_schema := Schema{ - ...schema, - id: if schema.id != '' { schema.id } - else if schema.title != '' { schema.title } - else { key } - title: if schema.title != '' { schema.title } - else if schema.id != '' { schema.id } - else { key } - } - processed.components.schemas[key] = processed_schema + processed.components.schemas[key] = process_schema(schema, name:key) } } @@ -87,7 +100,17 @@ fn (spec OpenAPI) process_operation(op Operation, method string, path string) !O mut req_body_ := RequestBody{...op.request_body content: op.request_body.content.clone() } - req_body_.content['application/json'].schema = SchemaRef(spec.dereference_schema(content.schema)!) + req_body_.content['application/json'].schema = SchemaRef( + process_schema(spec.dereference_schema(content.schema)!, name: content.schema.ref.all_after_last('/')) + ) + processed.request_body = RequestBodyRef(req_body_) + } else if content.schema is Schema { + mut req_body_ := RequestBody{...op.request_body + content: op.request_body.content.clone() + } + req_body_.content['application/json'].schema = SchemaRef( + process_schema(content.schema) + ) processed.request_body = RequestBodyRef(req_body_) } } @@ -99,7 +122,13 @@ fn (spec OpenAPI) process_operation(op Operation, method string, path string) !O } if media_type := processed_rs.content['application/json'] { if media_type.schema is Reference { - processed_rs.content['application/json'].schema = SchemaRef(spec.dereference_schema(media_type.schema)!) + processed_rs.content['application/json'].schema = SchemaRef( + process_schema(spec.dereference_schema(media_type.schema)!, name: media_type.schema.ref.all_after_last('/')) + ) + } else if media_type.schema is Schema { + processed_rs.content['application/json'].schema = SchemaRef( + process_schema(media_type.schema) + ) } } processed.responses['200'] = processed_rs