diff --git a/spec/amber/helper_spec.cr b/spec/amber/helper_spec.cr index a417de4..5828815 100644 --- a/spec/amber/helper_spec.cr +++ b/spec/amber/helper_spec.cr @@ -199,6 +199,7 @@ describe OpenAPI::Generator::Helpers::Amber do - union_types - free_form - array_of_hash + - tuple type: object properties: union_types: @@ -219,6 +220,23 @@ describe OpenAPI::Generator::Helpers::Amber do oneOf: - type: integer - type: string + tuple: + maxItems: 3 + minItems: 3 + type: array + items: + oneOf: + - type: integer + - type: string + - maxItems: 1 + minItems: 1 + type: array + items: + oneOf: + - type: array + items: + type: number + - type: boolean AmberSpec_Payload: required: - hello diff --git a/spec/core/generator_spec.cr b/spec/core/generator_spec.cr index da1150d..fd4a3aa 100644 --- a/spec/core/generator_spec.cr +++ b/spec/core/generator_spec.cr @@ -154,6 +154,7 @@ describe OpenAPI::Generator do - union_types - free_form - array_of_hash + - tuple type: object properties: union_types: @@ -174,6 +175,23 @@ describe OpenAPI::Generator do oneOf: - type: integer - type: string + tuple: + maxItems: 3 + minItems: 3 + type: array + items: + oneOf: + - type: integer + - type: string + - maxItems: 1 + minItems: 1 + type: array + items: + oneOf: + - type: array + items: + type: number + - type: boolean responses: {} parameters: {} examples: {} diff --git a/spec/lucky/helper_spec.cr b/spec/lucky/helper_spec.cr index 46ede90..2945334 100644 --- a/spec/lucky/helper_spec.cr +++ b/spec/lucky/helper_spec.cr @@ -150,6 +150,7 @@ describe OpenAPI::Generator::Helpers::Lucky do - union_types - free_form - array_of_hash + - tuple type: object properties: union_types: @@ -170,6 +171,23 @@ describe OpenAPI::Generator::Helpers::Lucky do oneOf: - type: integer - type: string + tuple: + maxItems: 3 + minItems: 3 + type: array + items: + oneOf: + - type: integer + - type: string + - maxItems: 1 + minItems: 1 + type: array + items: + oneOf: + - type: array + items: + type: number + - type: boolean LuckySpec_Payload: required: - hello diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 2cda27f..d0c2d93 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -79,13 +79,15 @@ struct Model property union_types : Int32 | String | Hash(String, InnerModel) property free_form : JSON::Any property array_of_hash : Array(Hash(String, Int32 | String)) + property tuple : Tuple(Int32, String, Tuple(Bool | Array(Float64))) SCHEMA = <<-JSON { "required": [ "union_types", "free_form", - "array_of_hash" + "array_of_hash", + "tuple" ], "type": "object", "properties": { @@ -124,6 +126,39 @@ struct Model ] } } + }, + "tuple": { + "maxItems": 3, + "minItems": 3, + "type": "array", + "items": { + "oneOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "maxItems": 1, + "minItems": 1, + "type": "array", + "items": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "boolean" + } + ] + } + } + ] + } } } } diff --git a/spec/spider-gazelle/helper_spec.cr b/spec/spider-gazelle/helper_spec.cr index 2640c44..9f39872 100644 --- a/spec/spider-gazelle/helper_spec.cr +++ b/spec/spider-gazelle/helper_spec.cr @@ -206,6 +206,7 @@ describe OpenAPI::Generator::Helpers::ActionController do - union_types - free_form - array_of_hash + - tuple type: object properties: union_types: @@ -226,6 +227,23 @@ describe OpenAPI::Generator::Helpers::ActionController do oneOf: - type: integer - type: string + tuple: + maxItems: 3 + minItems: 3 + type: array + items: + oneOf: + - type: integer + - type: string + - maxItems: 1 + minItems: 1 + type: array + items: + oneOf: + - type: array + items: + type: number + - type: boolean ActionControllerSpec_Payload: required: - mandatory diff --git a/src/openapi-generator/extensions.cr b/src/openapi-generator/extensions.cr index d272fd1..e53cdf4 100644 --- a/src/openapi-generator/extensions.cr +++ b/src/openapi-generator/extensions.cr @@ -21,6 +21,38 @@ class Array(T) end end +# :nodoc: +# Define a `self.to_openapi_schema` method for the Tuple class. +# +# OpenAPI 3.0 does not support tuples (3.1 does), so we serialize it into a fixed bounds array. +# see: https://github.com/OAI/OpenAPI-Specification/issues/1026 +struct Tuple + def self.to_openapi_schema + schema_items = uninitialized OpenAPI::Schema | OpenAPI::Reference + + {% begin %} + {% types = [] of Types %} + {% for i in 0...T.size %} + {% for t in T[i].union_types %} + {% types << t %} + {% end %} + {% end %} + + ::OpenAPI::Generator::Serializable.generate_schema( + schema_items, + types: {{ types }}, + ) + {% end %} + + OpenAPI::Schema.new( + type: "array", + items: schema_items, + min_items: {{ T.size }}, + max_items: {{ T.size }} + ) + end +end + # :nodoc: # Define a `self.to_openapi_schema` method for the Hash class. class Hash(K, V)