README.md in dry-swagger-1.0.0 vs README.md in dry-swagger-2.0.0

- old
+ new

@@ -1,10 +1,29 @@ # Dry::Swagger Generate a valid and up to date swagger documentation out of your dry-structs and dry-validations The gem is still work in progress and is not yet fully tested. +## IMPORTANT: + +If you are upgrading from version 1 to version 2, you will need to replace: + + Dry::Swagger::StructParser.new.call(struct) +with + + Dry::Swagger::DocumentationGenerator.new.from_struct(struct) +and replace + + Dry::Swagger::ContractParser.new.call(contract) +with + + Dry::Swagger::DocumentationGenerator.new.from_validation(contract). + +For the configuration file in project/config/initializers/dry-swagger.rb, you will need to replace: + + Dry::Swagger::Config::ContractConfiguration -> Dry::Swagger::Config::SwaggerConfiguration +you do not need both ContractConfiguration and StructConfiguration. ## Installation Add this line to your application's Gemfile: ```ruby @@ -22,12 +41,10 @@ This will generate configuration files in your project under `project/config`. See Configuration section for more details. ## Usage #### With Dry::Validation::Contract -Lets say we have the following Dry::Validation::Contract definition: - class TestContract < Dry::Validation::Contract params do required(:some_field).value(:str?, min_size?: 5, max_size?: 10) required(:some_array_of_objects).array(:hash) do required(:some_nested_attribute).value(:str?) @@ -37,132 +54,67 @@ optional(:some_nested_attribute).maybe(:str?) end end end - parser = Dry::Swagger::ContractParser.new - -`parser.call(TestContract)` will set the `keys` of the `parser` object to: - - { - :some_field => { - :required => true, - :type => "string", - :description => "Minimum size: 5, Maximum size: 10" - }, - :some_array_of_objects => { - :required => true, - :array => true, - :type => "array", - :keys => { - :some_nested_attribute => { - :required=>true, :type=>"string" - } - } - }, - :some_array_of_integers => { - :required=>true, - :array=>true, - :type=>"integer" - }, - :dto => { - :required => true, - :type => "hash", - :keys => { - :some_nested_attribute => { - :required => false, - :"x-nullable"=>true, - :type=>"string" - } - } - } - } - -As we can see, the `ContractParser` goes through all the params defined in the -schema and generates a hash. The hash is saved in the `keys` attribute of the parser, -so that we can call `to_swagger` later. - -The required key in our result will be set to `true` if the field is defined as -`required(:field_name)`, and `false` if defined as `optional(:field_name)`. - -The "x-nullable" key depends on whether we have defined the field as value, maybe or filled. - -For nested objects like array of objects or hash, we add a keys field with a definition -for each field inside the nested hash. - -If the field is an array of primitive type, the type field will equal to the primitive type, and a -array flag will be set on the field. - -Calling `parser.to_swagger` will give the following result: - - { - "type": "object", - "properties": { - "some_field": { - "type": "string", - "description": "Minimum size: 5, Maximum size: 10", - "x-nullable": false - }, - "some_array_of_objects": { - "type": "array", - "items": { - "type": "object", - "properties": { - "some_nested_attribute": { - "type": "string", - "x-nullable": false - } - }, - "required": [ - "some_nested_attribute" - ], - "x-nullable": false - }, - "x-nullable": false - }, - "some_array_of_integers": { - "type": "array", - "items": { - "type": "integer", - "x-nullable": false - }, - "x-nullable": false - }, - "dto": { + Dry::Swagger::DocumentationGenerator.new.from_validation(TestContract) + => { "type": "object", "properties": { - "some_nested_attribute": { + "some_field": { "type": "string", - "x-nullable": true + "description": "Minimum size: 5, Maximum size: 10", + "x-nullable": false + }, + "some_array_of_objects": { + "type": "array", + "items": { + "type": "object", + "properties": { + "some_nested_attribute": { + "type": "string", + "x-nullable": false + } + }, + "required": [ + "some_nested_attribute" + ], + "x-nullable": false + }, + "x-nullable": false + }, + "some_array_of_integers": { + "type": "array", + "items": { + "type": "integer", + "x-nullable": false + }, + "x-nullable": false + }, + "dto": { + "type": "object", + "properties": { + "some_nested_attribute": { + "type": "string", + "x-nullable": true + } + }, + "required": [ + + ], + "x-nullable": false } }, "required": [ - - ], - "x-nullable": false + "some_field", + "some_array_of_objects", + "some_array_of_integers", + "dto" + ] } - }, - "required": [ - "some_field", - "some_array_of_objects", - "some_array_of_integers", - "dto" - ] - } #### With Dry::Struct -The `Dry::Swagger::StructParser` works the same as the contract parser. - -The required key depends on whether we define the field as attribute or attribute? - -The "x-nullable" key depends on whether we define the type as Type or Type.optional. - -For more complex types, for example DTO1 | DTO2 or Types::Array.of(DTO1 | DTO2), -the parser converts the field value to an array of both schemas. - -Example: - class DTO1 < Dry::Struct attribute :dto1_field, Types::String end class DTO2 < Dry::Struct @@ -170,148 +122,82 @@ end class DTO < Dry::Struct attribute :dynamic_dto, DTO1 | DTO2 end - parser = Dry::Swagger::StructParser.new - - parser.call(DTO) - => { - "dynamic_dto": [ # ARRAY - { - "type": "hash", - "required": true, - "x-nullable": false, - "keys": { - "dto1_field": { - "type": "string", - "required": true, - "x-nullable": false - } - } - }, - { - "type": "hash", - "required": true, - "x-nullable": false, - "keys": { - "dto2_field": { - "type": "string", - "required": true, - "x-nullable": false - } - } - } - ] - } -Calling `parser.to_swagger` will give the following result: - - { - "type": "object", - "properties": { - "dynamic_dto": { + Dry::Swagger::DocumentationGenerator.new.from_struct(DTO) + => { "type": "object", "properties": { - "definition_1": { + "dynamic_dto": { "type": "object", "properties": { - "dto1_field": { - "type": "string", + "definition_1": { + "type": "object", + "properties": { + "dto1_field": { + "type": "string", + "x-nullable": false + } + }, + "required": [ + "dto1_field" + ], "x-nullable": false - } - }, - "required": [ - "dto1_field" - ], - "x-nullable": false - }, - "definition_2": { - "type": "object", - "properties": { - "dto2_field": { - "type": "string", + }, + "definition_2": { + "type": "object", + "properties": { + "dto2_field": { + "type": "string", + "x-nullable": false + } + }, + "required": [ + "dto2_field" + ], "x-nullable": false } }, - "required": [ - "dto2_field" - ], - "x-nullable": false - } - }, - "example": "Dynamic Field. See Model Definitions", - "oneOf": [ - { - "type": "object", - "properties": { - "dto1_field": { - "type": "string", + "example": "Dynamic Field. See Model Definitions", + "oneOf": [ + { + "type": "object", + "properties": { + "dto1_field": { + "type": "string", + "x-nullable": false + } + }, + "required": [ + "dto1_field" + ], "x-nullable": false - } - }, - "required": [ - "dto1_field" - ], - "x-nullable": false - }, - { - "type": "object", - "properties": { - "dto2_field": { - "type": "string", + }, + { + "type": "object", + "properties": { + "dto2_field": { + "type": "string", + "x-nullable": false + } + }, + "required": [ + "dto2_field" + ], "x-nullable": false } - }, - "required": [ - "dto2_field" - ], - "x-nullable": false + ] } + }, + "required": [ + "dynamic_dto" ] } - }, - "required": [ - "dynamic_dto" - ] - } ## Overriding fields -You can also modify the fields by passing a block after the .call() method. - - Dry::Swagger::StructParser.new.call(DTO) do |it| - # types = string/integer/hash/array - - # Remove a field - its.keys = it.keys.except(:field_name) - - # Add new field on root level - it.keys[:new_field_name] = { type: type, required: true/false, :it.config.nullable_type=>true/false } - - # Add a new field in nested hash/array - it.keys[:nested_field][:keys][:new_field_name] = { - type: type, required: true/false, :it.config.nullable_type=>true/false - } - - # Remove a field in nested hash/array - it.keys = it.keys[:nested_field][:keys].except(:field_name) - - # Add an array or hash - it.keys[:nested_field] = { - type: "array/hash", required: true/false, :it.config.nullable_type=> true/false, keys: { - # List all nested fields - new_field: { type: :type, required: true/false, :it.config.nullable_type=>true/false } - } - } - - # Add an Array of primitive types, type field needs to be the element type(string, integer, float), - and add an array: true flag - - it.keys[:array_field_name] = { - type: type, array: true, required: true/false, :it.config.nullable_type=> true/false - } - - end.to_swagger() +The documentation generator returns the result as a hash, so you can easily modify it based on your needs. ## Custom Configuration For Your Project You can override default configurations by changing the values in the `config/initializers/dry-swagger.rb` file generated from the rake command in the Installation section. To modify the descriptions for the Contracts, modify the values in `config/locale/dry-swagger.yml`.