better openapi schema support
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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<string, ${t.typ.typescript()}>'}
|
||||
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 {''}
|
||||
}
|
||||
}
|
||||
@@ -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])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user