dry_open_api 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/Custom.md +10 -0
  3. data/.gitignore +12 -0
  4. data/.rubocop.yml +10 -0
  5. data/CHANGELOG.md +0 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +68 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +85 -0
  11. data/Rakefile +7 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/dry_open_api.gemspec +32 -0
  15. data/lib/dry_open_api.rb +49 -0
  16. data/lib/dry_open_api/callback.rb +23 -0
  17. data/lib/dry_open_api/components.rb +54 -0
  18. data/lib/dry_open_api/contact.rb +23 -0
  19. data/lib/dry_open_api/data_types.rb +31 -0
  20. data/lib/dry_open_api/discriminator.rb +40 -0
  21. data/lib/dry_open_api/encoding.rb +25 -0
  22. data/lib/dry_open_api/equatable_as_content.rb +13 -0
  23. data/lib/dry_open_api/example.rb +24 -0
  24. data/lib/dry_open_api/external_documentation.rb +20 -0
  25. data/lib/dry_open_api/header.rb +42 -0
  26. data/lib/dry_open_api/info.rb +38 -0
  27. data/lib/dry_open_api/license.rb +20 -0
  28. data/lib/dry_open_api/link.rb +50 -0
  29. data/lib/dry_open_api/media_type.rb +35 -0
  30. data/lib/dry_open_api/o_auth_flow.rb +25 -0
  31. data/lib/dry_open_api/o_auth_flows.rb +27 -0
  32. data/lib/dry_open_api/operation.rb +60 -0
  33. data/lib/dry_open_api/parameter.rb +66 -0
  34. data/lib/dry_open_api/path_item.rb +42 -0
  35. data/lib/dry_open_api/paths.rb +26 -0
  36. data/lib/dry_open_api/reference.rb +21 -0
  37. data/lib/dry_open_api/request_body.rb +22 -0
  38. data/lib/dry_open_api/response.rb +55 -0
  39. data/lib/dry_open_api/responses.rb +37 -0
  40. data/lib/dry_open_api/schema.rb +107 -0
  41. data/lib/dry_open_api/security_requirement.rb +20 -0
  42. data/lib/dry_open_api/security_schema.rb +35 -0
  43. data/lib/dry_open_api/serializers.rb +7 -0
  44. data/lib/dry_open_api/serializers/yaml_serializer.rb +17 -0
  45. data/lib/dry_open_api/server.rb +21 -0
  46. data/lib/dry_open_api/server_variable.rb +21 -0
  47. data/lib/dry_open_api/specification.rb +44 -0
  48. data/lib/dry_open_api/tag.rb +23 -0
  49. data/lib/dry_open_api/version.rb +3 -0
  50. data/lib/dry_open_api/xml.rb +26 -0
  51. metadata +211 -0
@@ -0,0 +1,54 @@
1
+ require 'dry-initializer'
2
+
3
+ module DryOpenApi
4
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#componentsObject
5
+ class Components
6
+ prepend EquatableAsContent
7
+ extend Dry::Initializer
8
+
9
+ option :schemas, default: proc { nil }
10
+ option :responses, default: proc { nil }
11
+ option :parameters, default: proc { nil }
12
+ option :examples, default: proc { nil }
13
+ option :request_bodies, default: proc { nil }
14
+ option :headers, default: proc { nil }
15
+ option :security_schemes, default: proc { nil }
16
+ option :links, default: proc { nil }
17
+ option :callbacks, default: proc { nil }
18
+
19
+ # rubocop:disable Metrics/MethodLength
20
+ def serializable_hash
21
+ {
22
+ 'schemas' => schemas&.map { |k, v| [k.to_s, v.serializable_hash] }&.to_h,
23
+ 'responses' => responses&.map { |k, v| [k.to_s, v.serializable_hash] }&.to_h,
24
+ 'parameters' => parameters&.map { |k, v| [k.to_s, v.serializable_hash] }&.to_h,
25
+ 'examples' => examples&.map { |k, v| [k.to_s, v.serializable_hash] }&.to_h,
26
+ 'requestBodies' => request_bodies&.map { |k, v| [k.to_s, v.serializable_hash] }&.to_h,
27
+ 'headers' => headers&.map { |k, v| [k.to_s, v.serializable_hash] }&.to_h,
28
+ 'securitySchemes' => security_schemes&.map { |k, v| [k.to_s, v.serializable_hash] }&.to_h,
29
+ 'links' => links&.map { |k, v| [k.to_s, v.serializable_hash] }&.to_h,
30
+ 'callbacks' => callbacks&.map { |k, v| [k.to_s, v.serializable_hash] }&.to_h
31
+ }.compact
32
+ end
33
+
34
+ # rubocop:disable Metrics/PerceivedComplexity
35
+ def self.load(hash)
36
+ return unless hash
37
+
38
+ new(
39
+ schemas: hash['schemas']&.map { |k, v| [k, Reference.load(v) || Schema.load(v)] }&.to_h,
40
+ responses: hash['responses']&.map { |k, v| [k, Reference.load(v) || Response.load(v)] }&.to_h,
41
+ parameters: hash['parameters']&.map { |k, v| [k, Reference.load(v) || Parameter.load(v)] }&.to_h,
42
+ examples: hash['examples']&.map { |k, v| [k, Reference.load(v) || Example.load(v)] }&.to_h,
43
+ request_bodies: hash['requestBodies']&.map { |k, v| [k, Reference.load(v) || RequestBody.load(v)] }&.to_h,
44
+ headers: hash['headers']&.map { |k, v| [k, Reference.load(v) || Header.load(v)] }&.to_h,
45
+ security_schemes: hash['securitySchemes']&.map { |k, v|
46
+ [k, Reference.load(v) || SecuritySchema.load(v)]
47
+ }&.to_h,
48
+ links: hash['links']&.map { |k, v| [k, Reference.load(v) || Link.load(v)] }&.to_h,
49
+ callbacks: hash['callbacks']&.map { |k, v| [k, Reference.load(v) || Callback.load(v)] }&.to_h
50
+ )
51
+ end
52
+ # rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity
53
+ end
54
+ end
@@ -0,0 +1,23 @@
1
+ require 'dry-initializer'
2
+
3
+ module DryOpenApi
4
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#contactObject
5
+ class Contact
6
+ prepend EquatableAsContent
7
+ extend Dry::Initializer
8
+
9
+ option :name, proc(&:to_s), default: proc { nil }
10
+ option :url, proc(&:to_s), default: proc { nil }
11
+ option :email, proc(&:to_s), default: proc { nil }
12
+
13
+ def self.load(hash)
14
+ return unless hash
15
+
16
+ new(
17
+ name: hash['name'],
18
+ url: hash['url'],
19
+ email: hash['email']
20
+ )
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,31 @@
1
+ module DryOpenApi
2
+ DataType = Struct.new(:name, :type, :format)
3
+
4
+ # defines the DataTypes defined by the spec and adds some shortcuts
5
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types
6
+ class DataTypes
7
+ @data = [
8
+ DataType.new(:integer, :integer, :int32),
9
+ DataType.new(:long, :integer, :int64),
10
+ DataType.new(:float, :number, :float),
11
+ DataType.new(:double, :number, :double),
12
+ DataType.new(:string, :string),
13
+ DataType.new(:byte, :string, :byte),
14
+ DataType.new(:binary, :string, :binary),
15
+ DataType.new(:uuid, :string, :uuid),
16
+ DataType.new(:email, :string, :email),
17
+ DataType.new(:boolean, :boolean),
18
+ DataType.new(:date, :string, :date),
19
+ DataType.new(:dateTime, :string, :"date-time"),
20
+ DataType.new(:password, :string, :password)
21
+ ]
22
+
23
+ def self.all
24
+ @data
25
+ end
26
+
27
+ def self.all_types
28
+ all.map(&:type).uniq
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,40 @@
1
+ module DryOpenApi
2
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#discriminatorObject
3
+ class Discriminator
4
+ prepend EquatableAsContent
5
+
6
+ attr_accessor :property_name, :mapping
7
+
8
+ def initialize(property_name: nil, mapping: {}, **other_fields_hash)
9
+ self.property_name = property_name
10
+ self.mapping = mapping.with_indifferent_access
11
+ self.other_fields_hash = other_fields_hash
12
+
13
+ other_fields_hash.keys.each do |field_name|
14
+ define_singleton_method(field_name) do
15
+ other_fields_hash[field_name]
16
+ end
17
+ define_singleton_method("#{field_name}=") do |value|
18
+ other_fields_hash[field_name] = value
19
+ end
20
+ end
21
+ end
22
+
23
+ def self.load(hash)
24
+ return unless hash
25
+
26
+ fixed_field_names = %w[propertyName mapping]
27
+ other_fields_hash = hash.reject { |key| key.to_s.in?(fixed_field_names) }
28
+
29
+ new(
30
+ property_name: hash['propertyName'].to_s,
31
+ mapping: hash['mapping'],
32
+ **other_fields_hash.symbolize_keys,
33
+ )
34
+ end
35
+
36
+ private
37
+
38
+ attr_accessor :other_fields_hash
39
+ end
40
+ end
@@ -0,0 +1,25 @@
1
+ require 'dry-initializer'
2
+
3
+ module DryOpenApi
4
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#encodingObject
5
+ class Encoding
6
+ prepend EquatableAsContent
7
+ extend Dry::Initializer
8
+
9
+ option :content_type, proc(&:to_s), default: proc { nil }
10
+ option :headers, default: proc { nil }
11
+ option :style, proc(&:to_s), default: proc { nil }
12
+ option :explode, default: proc { nil }
13
+ option :allow_reserved, default: proc { false }
14
+
15
+ def self.load(hash)
16
+ new(
17
+ content_type: hash['contentType'],
18
+ headers: hash['headers']&.map { |k, v| [k, Reference.load(v) || Header.load(v)] }.to_h,
19
+ style: hash['style'],
20
+ explode: hash['explode'],
21
+ allow_reserved: hash['allowReserved'].present?
22
+ )
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ module DryOpenApi
2
+ module EquatableAsContent
3
+ def ==(other)
4
+ all_instance_variables == other.all_instance_variables
5
+ end
6
+
7
+ protected
8
+
9
+ def all_instance_variables
10
+ instance_variables.map { |name| instance_variable_get(name) }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ require 'dry-initializer'
2
+
3
+ module DryOpenApi
4
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#exampleObject
5
+ class Example
6
+ extend Dry::Initializer
7
+
8
+ option :value, default: proc { nil }
9
+ option :summary, proc(&:to_s), default: proc { nil }
10
+ option :description, proc(&:to_s), default: proc { nil }
11
+ option :external_value, proc(&:to_s), default: proc { nil }
12
+
13
+ def self.load(hash)
14
+ return unless hash
15
+
16
+ new(
17
+ summary: hash['summary'],
18
+ description: hash['description'],
19
+ value: hash['value'],
20
+ external_value: hash['externalValue']
21
+ )
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ require 'dry-initializer'
2
+
3
+ module DryOpenApi
4
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#externalDocumentationObject
5
+ class ExternalDocumentation
6
+ extend Dry::Initializer
7
+
8
+ option :url, proc(&:to_s)
9
+ option :description, proc(&:to_s), default: proc { nil }
10
+
11
+ def self.load(hash)
12
+ return unless hash
13
+
14
+ new(
15
+ description: hash['description'],
16
+ url: hash['url']
17
+ )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ module DryOpenApi
2
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#header-object
3
+ class Header
4
+ prepend EquatableAsContent
5
+
6
+ attr_accessor :description, :required, :deprecated, :allow_empty_value
7
+
8
+ def initialize(description: nil, required: false, deprecated: nil, allow_empty_value: false, **other_fields_hash)
9
+ self.description = description
10
+ self.required = required
11
+ self.deprecated = deprecated
12
+ self.allow_empty_value = allow_empty_value
13
+ self.other_fields_hash = other_fields_hash.with_indifferent_access
14
+
15
+ other_fields_hash.keys.each do |field_name|
16
+ define_singleton_method(field_name) do
17
+ other_fields_hash[field_name]
18
+ end
19
+ define_singleton_method("#{field_name}=") do |value|
20
+ other_fields_hash[field_name] = value
21
+ end
22
+ end
23
+ end
24
+
25
+ def self.load(hash)
26
+ fixed_field_names = %i[description required deprecated allowEmptyValue]
27
+ other_fields_hash = hash.reject { |key| key.to_sym.in?(fixed_field_names) }
28
+
29
+ new(
30
+ description: hash['description'],
31
+ required: hash['required'].nil? ? false : hash['required'],
32
+ deprecated: hash['deprecated'].nil? ? false : hash['deprecated'],
33
+ allow_empty_value: hash['allowEmptyValue'].nil? ? false : hash['allowEmptyValue'],
34
+ **other_fields_hash.symbolize_keys
35
+ )
36
+ end
37
+
38
+ private
39
+
40
+ attr_accessor :other_fields_hash
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ require 'dry-initializer'
2
+
3
+ module DryOpenApi
4
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#info-object
5
+ class Info
6
+ prepend EquatableAsContent
7
+ extend Dry::Initializer
8
+
9
+ option :title, proc(&:to_s)
10
+ option :version, proc(&:to_s)
11
+ option :description, default: proc { nil }
12
+ option :terms_of_service, default: proc { nil }
13
+ option :contact, default: proc { nil }
14
+ option :license, default: proc { nil }
15
+
16
+ def serializable_hash
17
+ {
18
+ 'title' => title,
19
+ 'description' => description,
20
+ 'termsOfService' => terms_of_service,
21
+ 'contact' => contact&.serializable_hash,
22
+ 'license' => license&.serializable_hash,
23
+ 'version' => version
24
+ }.compact
25
+ end
26
+
27
+ def self.load(hash)
28
+ new(
29
+ title: hash['title'],
30
+ description: hash['description'],
31
+ terms_of_service: hash['termsOfService'],
32
+ contact: Contact.load(hash['contact']),
33
+ license: License.load(hash['license']),
34
+ version: hash['version']
35
+ )
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ require 'dry-initializer'
2
+
3
+ module DryOpenApi
4
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#license-object
5
+ class License
6
+ extend Dry::Initializer
7
+
8
+ option :name, proc(&:to_s)
9
+ option :url, proc(&:to_s), default: proc { nil }
10
+
11
+ def self.load(hash)
12
+ return unless hash
13
+
14
+ new(
15
+ name: hash['name'],
16
+ url: hash['url']
17
+ )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,50 @@
1
+ module DryOpenApi
2
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#link-object
3
+ class Link
4
+ prepend EquatableAsContent
5
+
6
+ attr_accessor :operation_ref, :operation_id, :parameters, :request_body, :description, :server
7
+
8
+ def initialize(operation_ref: nil, operation_id: nil, parameters: nil, request_body: nil, description: nil, server: nil, **other_fields_hash)
9
+ self.operation_ref = operation_ref
10
+ self.operation_id = operation_id
11
+ self.parameters = parameters
12
+ self.request_body = request_body
13
+ self.description = description
14
+ self.server = server
15
+ self.other_fields_hash = other_fields_hash.with_indifferent_access
16
+
17
+ other_fields_hash.keys.each do |field_name|
18
+ define_singleton_method(field_name) do
19
+ other_fields_hash[field_name]
20
+ end
21
+ define_singleton_method("#{field_name}=") do |value|
22
+ other_fields_hash[field_name] = value
23
+ end
24
+ end
25
+ end
26
+
27
+ def self.load(hash)
28
+ return unless hash
29
+
30
+ fixed_field_names = %i[operationRef operationId parameters requestBody description server]
31
+ other_fields_hash = hash.reject { |key|
32
+ key.to_sym.in?(fixed_field_names)
33
+ }.symbolize_keys
34
+
35
+ new(
36
+ operation_ref: hash['operationRef']&.to_s,
37
+ operation_id: hash['operationId']&.to_s,
38
+ parameters: hash['parameters'],
39
+ request_body: RequestBody.load(hash['requestBody']),
40
+ description: hash['description']&.to_s,
41
+ server: Server.load(hash['server']),
42
+ **other_fields_hash
43
+ )
44
+ end
45
+
46
+ private
47
+
48
+ attr_accessor :other_fields_hash
49
+ end
50
+ end
@@ -0,0 +1,35 @@
1
+ require 'dry-initializer'
2
+
3
+ module DryOpenApi
4
+ class MediaType
5
+ prepend EquatableAsContent
6
+ extend Dry::Initializer
7
+
8
+ option :schema, default: proc { nil }
9
+ option :example, default: proc { nil }
10
+ option :examples, default: proc { nil }
11
+ option :encoding, default: proc { nil }
12
+
13
+ def serializable_hash
14
+ {
15
+ 'schema' => schema&.serializable_hash,
16
+ 'example' => example,
17
+ 'examples' => examples&.map { |k, v| [k.to_s, v.serializable_hash] }&.to_h,
18
+ 'encoding' => encoding&.map { |k, v| [k.to_s, v.serializable_hash] }&.to_h
19
+ }.compact
20
+ end
21
+
22
+ def self.load(hash)
23
+ return unless hash
24
+
25
+ indi_hash = hash.with_indifferent_access
26
+
27
+ new(
28
+ schema: Reference.load(indi_hash['schema']) || Schema.load(indi_hash['schema']),
29
+ example: indi_hash['example'],
30
+ examples: indi_hash['examples']&.map { |k, v| [k, Reference.load(v) || Example.load(v)] }&.to_h,
31
+ encoding: indi_hash['encoding']&.map { |k, v| [k, Encoding.load(v)] }&.to_h
32
+ )
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ require 'dry-initializer'
2
+
3
+ module DryOpenApi
4
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oauthFlowObject
5
+ class OAuthFlow
6
+ prepend EquatableAsContent
7
+ extend Dry::Initializer
8
+
9
+ option :authorization_url, proc(&:to_s)
10
+ option :scopes, proc(&:to_s)
11
+ option :token_url, proc(&:to_s)
12
+ option :refresh_url, proc(&:to_s), default: proc { nil }
13
+
14
+ def self.load(hash)
15
+ return unless hash
16
+
17
+ new(
18
+ authorization_url: hash['authorizationUrl'],
19
+ token_url: hash['tokenUrl'],
20
+ refresh_url: hash['refreshUrl'],
21
+ scopes: hash['scopes']
22
+ )
23
+ end
24
+ end
25
+ end