From de66eff378a12c0793f195f6220b025206762326 Mon Sep 17 00:00:00 2001 From: Alexandre Morignot Date: Fri, 5 Feb 2021 13:26:18 +0100 Subject: [PATCH 1/2] Add support for array to objects --- spec/swagger/object_spec.cr | 28 +++++++++++++++- spec/swagger/property_spec.cr | 20 ++++++++++++ src/swagger/builder.cr | 58 ++++++++++++++++++++++++++++----- src/swagger/object.cr | 6 ++-- src/swagger/objects/property.cr | 3 +- src/swagger/property.cr | 4 ++- 6 files changed, 105 insertions(+), 14 deletions(-) diff --git a/spec/swagger/object_spec.cr b/spec/swagger/object_spec.cr index 8eb0515..8946f3f 100644 --- a/spec/swagger/object_spec.cr +++ b/spec/swagger/object_spec.cr @@ -13,7 +13,33 @@ describe Swagger::Object do raw = Swagger::Object.new("User", "object", properties) raw.name.should eq "User" raw.type.should eq "object" - raw.properties.size.should eq 5 + raw.properties.should_not be_nil + raw.properties.try &.size.should eq 5 + end + + it "should supports the type array with items as an object" do + raw = Swagger::Object.new( + "CommentList", + "array", + items: Swagger::Object.new( + "Comment", + "object", + ) + ) + raw.type.should eq("array") + raw.properties.should be_nil + raw.items.class.should eq(Swagger::Object) + end + + it "should supports the type array with items as a ref" do + raw = Swagger::Object.new( + "CommentList", + "array", + items: "Comment", + ) + raw.type.should eq("array") + raw.properties.should be_nil + raw.items.should eq("Comment") end end end diff --git a/spec/swagger/property_spec.cr b/spec/swagger/property_spec.cr index 260fe57..72a29bb 100644 --- a/spec/swagger/property_spec.cr +++ b/spec/swagger/property_spec.cr @@ -12,5 +12,25 @@ describe Swagger::Property do raw.required.should be_nil raw.example.should be_nil end + + it "should supports the array type with items as an Object" do + raw = Swagger::Property.new( + "comments", + "array", + items: Swagger::Object.new("Comment", "object") + ) + raw.type.should eq("array") + raw.items.class.should eq(Swagger::Object) + end + + it "should supports the array type with items as a ref" do + raw = Swagger::Property.new( + "comments", + "array", + items: "Comment", + ) + raw.type.should eq("array") + raw.items.should eq("Comment") + end end end diff --git a/src/swagger/builder.cr b/src/swagger/builder.cr index 293ff5a..868e5a7 100644 --- a/src/swagger/builder.cr +++ b/src/swagger/builder.cr @@ -100,21 +100,61 @@ module Swagger private def build_components(security_schemes) schemas = if objects = @objects schema = objects.each_with_object(Hash(String, Schema).new) do |object, schemas_obj| - properties = object.properties.each_with_object(Hash(String, Objects::Property).new) do |property, prop_obj| - prop_obj[property.name] = Objects::Property.new( - type: property.type, - description: property.description, - example: property.example - ) - end - - schemas_obj[object.name] = Schema.new(type: object.type, properties: properties) + schemas_obj[object.name.not_nil!] = build_schema(object) end end Objects::Components.new(security_schemes: security_schemes, schemas: schemas) end + private def build_schema(object : Object) : Objects::Schema + if object.type == "array" + if items = object.items + if items.is_a?(String) + schema_items = Objects::Schema.use_reference(items) + else + schema_items = build_schema(items) + end + + Objects::Schema.new(type: object.type, items: schema_items) + else + raise %(OpenAPI v3 requires "items" to be specified when the type is "array") + end + else + properties = object.properties.try &.each_with_object(Hash(String, Objects::Property).new) do |property, prop_obj| + prop_obj[property.name] = build_property(property) + end + Objects::Schema.new(type: object.type, properties: properties) + end + end + + private def build_property(property : Property) : Objects::Property + if property.type == "array" + if items = property.items + if items.is_a?(String) + prop_items = Objects::Schema.use_reference(items) + else + prop_items = build_schema(items) + end + + Objects::Property.new( + type: property.type, + description: property.description, + example: property.example, + items: prop_items, + ) + else + raise %(OpenAPI v3 requires "items" to be specified when the type is "array") + end + else + Objects::Property.new( + type: property.type, + description: property.description, + example: property.example, + ) + end + end + def build_security(security_schemes) return unless security_schemes security_schemes.keys.each_with_object(Hash(String, Array(String)).new) do |name, obj| diff --git a/src/swagger/object.cr b/src/swagger/object.cr index 92a7187..25caffc 100644 --- a/src/swagger/object.cr +++ b/src/swagger/object.cr @@ -12,12 +12,14 @@ module Swagger # Swagger::Property.new("bio", "Personal bio"), # ]) # ``` - struct Object + class Object property name property type property properties + property items - def initialize(@name : String, @type : String, @properties : Array(Property)) + def initialize(@name : String, @type : String, @properties : Array(Property)? = nil, + @items : (self | String)? = nil) end end end diff --git a/src/swagger/objects/property.cr b/src/swagger/objects/property.cr index 42998cf..2acd00a 100644 --- a/src/swagger/objects/property.cr +++ b/src/swagger/objects/property.cr @@ -3,12 +3,13 @@ module Swagger::Objects include JSON::Serializable getter type : String + getter items : Schema? = nil getter description : String? = nil getter default : (String | Int32 | Int64 | Float64 | Bool)? = nil getter example : (String | Int32 | Int64 | Float64 | Bool)? = nil getter required : Bool? = nil - def initialize(@type : String, @description : String? = nil, + def initialize(@type : String, @description : String? = nil, @items : Schema? = nil, @default : (String | Int32 | Int64 | Float64 | Bool)? = nil, @example : (String | Int32 | Int64 | Float64 | Bool)? = nil, @required : Bool? = nil) diff --git a/src/swagger/property.cr b/src/swagger/property.cr index 099e582..b72d616 100644 --- a/src/swagger/property.cr +++ b/src/swagger/property.cr @@ -3,13 +3,15 @@ module Swagger property name property type property format + property items property description property default_value property example property required def initialize(@name : String, @type : String = "string", @format : String? = nil, - @description : String? = nil, @default_value : (String | Int32 | Int64 | Float64 | Bool)? = nil, + @items : (Object | String)? = nil, @description : String? = nil, + @default_value : (String | Int32 | Int64 | Float64 | Bool)? = nil, @example : (String | Int32 | Int64 | Float64 | Bool)? = nil, @required : Bool? = nil) end From dc5cd765b5b5b80b82b61863b2818f40410d7382 Mon Sep 17 00:00:00 2001 From: Alexandre Morignot Date: Fri, 5 Feb 2021 17:49:16 +0100 Subject: [PATCH 2/2] Add ref support to Swagger::Property --- src/swagger/builder.cr | 4 +++- src/swagger/objects/property.cr | 13 ++++++++++--- src/swagger/property.cr | 3 ++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/swagger/builder.cr b/src/swagger/builder.cr index 868e5a7..6c750db 100644 --- a/src/swagger/builder.cr +++ b/src/swagger/builder.cr @@ -129,7 +129,9 @@ module Swagger end private def build_property(property : Property) : Objects::Property - if property.type == "array" + if ref = property.ref + Objects::Property.use_reference(ref) + elsif property.type == "array" if items = property.items if items.is_a?(String) prop_items = Objects::Schema.use_reference(items) diff --git a/src/swagger/objects/property.cr b/src/swagger/objects/property.cr index 2acd00a..f4b5155 100644 --- a/src/swagger/objects/property.cr +++ b/src/swagger/objects/property.cr @@ -2,17 +2,24 @@ module Swagger::Objects struct Property include JSON::Serializable - getter type : String + def self.use_reference(name : String) + new(ref: "#/components/schemas/#{name}") + end + + getter type : String? = nil getter items : Schema? = nil getter description : String? = nil getter default : (String | Int32 | Int64 | Float64 | Bool)? = nil getter example : (String | Int32 | Int64 | Float64 | Bool)? = nil getter required : Bool? = nil - def initialize(@type : String, @description : String? = nil, @items : Schema? = nil, + @[JSON::Field(key: "$ref")] + getter ref : String? = nil + + def initialize(@type : String? = nil, @description : String? = nil, @items : Schema? = nil, @default : (String | Int32 | Int64 | Float64 | Bool)? = nil, @example : (String | Int32 | Int64 | Float64 | Bool)? = nil, - @required : Bool? = nil) + @required : Bool? = nil, @ref : String? = nil,) end end end diff --git a/src/swagger/property.cr b/src/swagger/property.cr index b72d616..bfb77d3 100644 --- a/src/swagger/property.cr +++ b/src/swagger/property.cr @@ -8,12 +8,13 @@ module Swagger property default_value property example property required + property ref def initialize(@name : String, @type : String = "string", @format : String? = nil, @items : (Object | String)? = nil, @description : String? = nil, @default_value : (String | Int32 | Int64 | Float64 | Bool)? = nil, @example : (String | Int32 | Int64 | Float64 | Bool)? = nil, - @required : Bool? = nil) + @required : Bool? = nil, @ref : String? = nil) end end end