sober_swag 0.19.0 → 0.20.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint.yml +1 -1
  3. data/.github/workflows/ruby.yml +1 -1
  4. data/.gitignore +2 -0
  5. data/.rubocop.yml +5 -1
  6. data/.yardopts +7 -0
  7. data/CHANGELOG.md +5 -0
  8. data/Gemfile +8 -0
  9. data/README.md +1 -1
  10. data/docs/serializers.md +3 -0
  11. data/example/Gemfile +1 -1
  12. data/example/config/environments/production.rb +1 -1
  13. data/lib/sober_swag.rb +6 -1
  14. data/lib/sober_swag/compiler.rb +29 -3
  15. data/lib/sober_swag/compiler/path.rb +42 -3
  16. data/lib/sober_swag/compiler/paths.rb +20 -0
  17. data/lib/sober_swag/compiler/primitive.rb +17 -0
  18. data/lib/sober_swag/compiler/type.rb +105 -22
  19. data/lib/sober_swag/controller.rb +39 -12
  20. data/lib/sober_swag/controller/route.rb +103 -20
  21. data/lib/sober_swag/input_object.rb +90 -7
  22. data/lib/sober_swag/nodes/array.rb +19 -0
  23. data/lib/sober_swag/nodes/attribute.rb +45 -4
  24. data/lib/sober_swag/nodes/base.rb +27 -7
  25. data/lib/sober_swag/nodes/binary.rb +30 -13
  26. data/lib/sober_swag/nodes/enum.rb +16 -1
  27. data/lib/sober_swag/nodes/list.rb +20 -0
  28. data/lib/sober_swag/nodes/nullable_primitive.rb +3 -0
  29. data/lib/sober_swag/nodes/object.rb +4 -1
  30. data/lib/sober_swag/nodes/one_of.rb +11 -3
  31. data/lib/sober_swag/nodes/primitive.rb +34 -2
  32. data/lib/sober_swag/nodes/sum.rb +8 -0
  33. data/lib/sober_swag/output_object.rb +35 -4
  34. data/lib/sober_swag/output_object/definition.rb +31 -1
  35. data/lib/sober_swag/output_object/field.rb +31 -11
  36. data/lib/sober_swag/output_object/field_syntax.rb +19 -3
  37. data/lib/sober_swag/output_object/view.rb +46 -1
  38. data/lib/sober_swag/parser.rb +7 -1
  39. data/lib/sober_swag/serializer/array.rb +27 -3
  40. data/lib/sober_swag/serializer/base.rb +75 -25
  41. data/lib/sober_swag/serializer/conditional.rb +33 -1
  42. data/lib/sober_swag/serializer/field_list.rb +18 -2
  43. data/lib/sober_swag/serializer/mapped.rb +10 -1
  44. data/lib/sober_swag/serializer/optional.rb +18 -1
  45. data/lib/sober_swag/serializer/primitive.rb +3 -0
  46. data/lib/sober_swag/server.rb +5 -1
  47. data/lib/sober_swag/type/named.rb +14 -0
  48. data/lib/sober_swag/types/comma_array.rb +4 -0
  49. data/lib/sober_swag/version.rb +1 -1
  50. metadata +3 -2
@@ -1,45 +1,95 @@
1
1
  module SoberSwag
2
2
  class Compiler
3
3
  ##
4
- # A compiler for DRY-Struct data types, essentially.
5
- # It only consumes one type at a time.
4
+ # A compiler for swagger-able types.
5
+ #
6
+ # This class turns Swagger-able types into a *schema*.
7
+ # This Schema may be:
8
+ # - a [schema object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#schemaObject) with {#object_schema}
9
+ # - a [path schema](https://swagger.io/docs/specification/describing-parameters/#path-parameters) with {#path_schema}
10
+ # - a [query schema](https://swagger.io/docs/specification/describing-parameters/#query-parameters) with {#query_schema}
11
+ #
12
+ # As such, it compiles all types to all applicable schemas.
13
+ #
14
+ # While this class compiles *one* type at a time, it *keeps track* of the other types needed to describe this schema.
15
+ # It stores these types in a set, available at {#found_types}.
16
+ #
17
+ # For example, with a schema like:
18
+ #
19
+ # ```ruby
20
+ # class Bar < SoberSwag::InputObject
21
+ # attribute :baz, primitive(:String)
22
+ # end
23
+ #
24
+ # class Foo < SoberSwag::InputObject
25
+ # attribute :bar, Bar
26
+ # end
27
+ # ```
28
+ #
29
+ # If you compile `Foo` with this class, {#found_types} will include `Bar`.
30
+ #
6
31
  class Type # rubocop:disable Metrics/ClassLength
32
+ ##
33
+ # An error raised when a type is too complicated for a given schema.
34
+ # This may be due to containing too many layers of nesting.
7
35
  class TooComplicatedError < ::SoberSwag::Compiler::Error; end
36
+ ##
37
+ # An error raised when a type is too complicated to transform into a *path* schema.
8
38
  class TooComplicatedForPathError < TooComplicatedError; end
39
+ ##
40
+ # An error raised when a type is too complicated to transform into a *query* schema.
9
41
  class TooComplicatedForQueryError < TooComplicatedError; end
10
42
 
43
+ ##
44
+ # A list of acceptable keys to use as metadata for an object schema.
45
+ # All other metadata keys defined on a type with {SoberSwag::InputObject.meta} will be ignored.
46
+ #
47
+ # @return [Array<Symbol>] valid keys.
11
48
  METADATA_KEYS = %i[description deprecated].freeze
12
49
 
50
+ ##
51
+ # Create a new compiler for a swagger-able type.
52
+ # @param type [Class] the type to compile
13
53
  def initialize(type)
14
54
  @type = type
15
55
  end
16
56
 
57
+ ##
58
+ # @return [Class] the type we are compiling.
17
59
  attr_reader :type
18
60
 
19
61
  ##
20
62
  # Is this type standalone, IE, worth serializing on its own
21
63
  # in the schemas section of our schema?
64
+ # @return [true,false]
22
65
  def standalone?
23
66
  type.is_a?(Class)
24
67
  end
25
68
 
69
+ ##
70
+ # Get back the [schema object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#schemaObject)
71
+ # for the type described.
72
+ #
73
+ # @return [Hash]
26
74
  def object_schema
27
75
  @object_schema ||=
28
76
  make_object_schema
29
77
  end
30
78
 
31
- def object_schema_meta
32
- return {} unless standalone? && type <= SoberSwag::Type::Named
33
-
34
- {
35
- description: type.description
36
- }.reject { |_, v| v.nil? }
37
- end
38
-
79
+ ##
80
+ # Give a "stub type" for this schema.
81
+ # This is suitable to use as the schema for attributes of other schemas.
82
+ # Almost always generates a ref object.
83
+ # @return [Hash] the OpenAPI V3 schema stub
39
84
  def schema_stub
40
85
  @schema_stub ||= generate_schema_stub
41
86
  end
42
87
 
88
+ ##
89
+ # The schema for this type when it is path of the path.
90
+ #
91
+ # @raise [TooComplicatedForPathError] when the compiled type is too complicated to use in a path
92
+ # @return [Hash] a [path parameters hash](https://swagger.io/docs/specification/describing-parameters/#path-parameters) for this type.
43
93
  def path_schema
44
94
  path_schema_stub.map do |e|
45
95
  ensure_uncomplicated(e[:name], e[:schema])
@@ -51,16 +101,30 @@ module SoberSwag
51
101
 
52
102
  DEFAULT_QUERY_SCHEMA_ATTRS = { in: :query, style: :deepObject, explode: true }.freeze
53
103
 
104
+ ##
105
+ # The schema for this type when it is part of the query.
106
+ # @raise [TooComplicatedForQueryError] when this type is too complicated to use in a query schema
107
+ # @return [Hash] a [query parameters hash](https://swagger.io/docs/specification/describing-parameters/#query-parameters) for this type.
54
108
  def query_schema
55
109
  path_schema_stub.map { |e| DEFAULT_QUERY_SCHEMA_ATTRS.merge(e) }
56
110
  rescue TooComplicatedError => e
57
111
  raise TooComplicatedForQueryError, e.message
58
112
  end
59
113
 
114
+ ##
115
+ # Get the name of this type if it is to be used in a `$ref` key.
116
+ # This is useful if we are going to use this type compiler to compile an *attribute* of another object.
117
+ #
118
+ # @return [String] a reference specifier for this type
60
119
  def ref_name
61
120
  SoberSwag::Compiler::Primitive.new(type).ref_name
62
121
  end
63
122
 
123
+ ##
124
+ # Get a set of all other types needed to compile this type.
125
+ # This set will *not* include the type being compiled.
126
+ #
127
+ # @return [Set<Class>]
64
128
  def found_types
65
129
  @found_types ||=
66
130
  begin
@@ -69,32 +133,51 @@ module SoberSwag
69
133
  end
70
134
  end
71
135
 
72
- def mapped_type
73
- @mapped_type ||= parsed_type.map { |v| SoberSwag::Compiler::Primitive.new(v).type_hash }
74
- end
75
-
76
- def parsed_type
77
- @parsed_type ||=
78
- begin
79
- (parsed,) = parsed_result
80
- parsed
81
- end
82
- end
83
-
136
+ ##
137
+ # This type, parsed into an AST.
84
138
  def parsed_result
85
139
  @parsed_result ||= Parser.new(type_for_parser).run_parser
86
140
  end
87
141
 
142
+ ##
143
+ # Standard ruby equality.
88
144
  def eql?(other)
89
145
  other.class == self.class && other.type == type
90
146
  end
91
147
 
148
+ ##
149
+ # Standard ruby hashing method.
150
+ # Compilers hash to the same value if they are compiling the same type.
92
151
  def hash
93
152
  [self.class, type].hash
94
153
  end
95
154
 
96
155
  private
97
156
 
157
+ ##
158
+ # Get metadata attributes to be used if compiling an object schema.
159
+ #
160
+ # @return [Hash]
161
+ def object_schema_meta
162
+ return {} unless standalone? && type <= SoberSwag::Type::Named
163
+
164
+ {
165
+ description: type.description
166
+ }.reject { |_, v| v.nil? }
167
+ end
168
+
169
+ def parsed_type
170
+ @parsed_type ||=
171
+ begin
172
+ (parsed,) = parsed_result
173
+ parsed
174
+ end
175
+ end
176
+
177
+ def mapped_type
178
+ @mapped_type ||= parsed_type.map { |v| SoberSwag::Compiler::Primitive.new(v).type_hash }
179
+ end
180
+
98
181
  def generate_schema_stub
99
182
  if type.is_a?(Class)
100
183
  SoberSwag::Compiler::Primitive.new(type).type_hash
@@ -2,7 +2,8 @@ require 'active_support/concern'
2
2
 
3
3
  module SoberSwag
4
4
  ##
5
- # Controller concern
5
+ # This module can be included in any subclass of `ActionController` or `ActionController::API` to make it `SoberSwag`-able.
6
+ # This means that you can use the mechanics of SoberSwag to define a type-safe API, with generated Swagger documentation!
6
7
  module Controller
7
8
  extend ActiveSupport::Concern
8
9
 
@@ -17,14 +18,18 @@ module SoberSwag
17
18
  include ::Dry::Types()
18
19
  end
19
20
 
20
- class_methods do
21
+ ##
22
+ # Module containing class methods.
23
+ # Any class that `include`s {SoberSwag::Controller} will also `extend` {SoberSwag::Controller::ClassMethods}.
24
+ module ClassMethods
21
25
  ##
22
26
  # Define a new action with the given HTTP method, action name, and path.
23
- # This will eventaully delegate to making an actual method on your controller,
27
+ # This will eventually delegate to making an actual method on your controller,
24
28
  # so you can use controllers as you wish with no harm.
25
29
  #
26
30
  # This method takes a block, evaluated in the context of a {SoberSwag::Controller::Route}.
27
31
  # Used like:
32
+ #
28
33
  # define(:get, :show, '/posts/{id}') do
29
34
  # path_params do
30
35
  # attribute :id, Types::Integer
@@ -36,32 +41,46 @@ module SoberSwag
36
41
  # end
37
42
  #
38
43
  # This will define an "action module" on this class to contain the generated types.
39
- # In the above example, the following constants will be deifned on the controller:
40
- # PostsController::Show # the container module for everything in this action
41
- # PostsController::Show::PathParams # the dry-struct type for the path attribute.
44
+ # In the above example, the following constants will be defined on the controller:
45
+ #
46
+ # - `PostsController::Show` - the container module for everything in this action
47
+ # - `PostsController::Show::PathParams` - the dry-struct type for the path attribute.
48
+ #
42
49
  # So, in the same controller, you can refer to Show::PathParams to get the type created by the 'path_params' block above.
50
+ #
51
+ # The block given evaluates in the context of `SoberSwag::Controller::Route`.
52
+ #
53
+ # @todo Explore parsing the `path` parameter from rails routes so we can avoid forcing the duplicate boilerplate.
54
+ #
55
+ # @param method [Symbol] the HTTP method of this route
56
+ # @param action [Symbol] the name of the controller method this maps onto
57
+ # @param path [String] an OpenAPI v3 Path Specifier
43
58
  def define(method, action, path, &block)
44
59
  r = Route.new(method, action, path)
45
60
  r.instance_eval(&block)
46
61
  const_set(r.action_module_name, r.action_module)
47
62
  defined_routes << r
48
- define_method(action, r.action) if r.action
49
63
  end
50
64
 
51
65
  ##
52
66
  # All the routes that this controller knows about.
67
+ # @return [Array<SoberSwag::Controller::Route>
53
68
  def defined_routes
54
69
  @defined_routes ||= []
55
70
  end
56
71
 
57
72
  ##
58
73
  # Find a route with the given name.
74
+ # @param name [Symbol] the name
75
+ # @return [SoberSwag::Controller::Route]
59
76
  def find_route(name)
60
77
  defined_routes.find { |r| r.action_name.to_s == name.to_s }
61
78
  end
62
79
 
63
80
  ##
64
- # A swagger definition for *this controller only*.
81
+ # Get the OpenAPI v3 definition for this controller.
82
+ #
83
+ # @return [Hash]
65
84
  def swagger_info
66
85
  @swagger_info ||=
67
86
  begin
@@ -74,14 +93,19 @@ module SoberSwag
74
93
  end
75
94
  end
76
95
 
96
+ included do |base|
97
+ base.extend ClassMethods
98
+ end
99
+
77
100
  ##
78
- # Action to get the singular swagger for this entire API.
101
+ # ActiveController action to get the swagger definition for this API.
102
+ # It renders a JSON of the OpenAPI v3 schema for this API.
79
103
  def swagger
80
104
  render json: self.class.swagger_info
81
105
  end
82
106
 
83
107
  ##
84
- # Get the path parameters, parsed into the type you defined with {SoberSwag::Controller.define}
108
+ # Get the path parameters, parsed into the type you defined with {SoberSwag::Controller::ClassMethods#define}
85
109
  # @raise [UndefinedPathError] if there's no path params defined for this route
86
110
  # @raise [Dry::Struct::Error] if we cannot convert the path params to the defined type.
87
111
  def parsed_path
@@ -95,7 +119,7 @@ module SoberSwag
95
119
  end
96
120
 
97
121
  ##
98
- # Get the request body, parsed into the type you defined with {SoberSwag::Controller.define}.
122
+ # Get the request body, parsed into the type you defined with {SoberSwag::Controller::ClassMethods#define}.
99
123
  # @raise [UndefinedBodyError] if there's no request body defined for this route
100
124
  # @raise [Dry::Struct::Error] if we cannot convert the path params to the defined type.
101
125
  def parsed_body
@@ -109,7 +133,7 @@ module SoberSwag
109
133
  end
110
134
 
111
135
  ##
112
- # Get the query params, parsed into the type you defined with {SoberSwag::Controller.define}
136
+ # Get the query params, parsed into the type you defined with {SoberSwag::Controller::ClassMethods#define}
113
137
  # @raise [UndefinedQueryError] if there's no query params defined for this route
114
138
  # @raise [Dry::Struct::Error] if we cannot convert the path params to the defined type.
115
139
  def parsed_query
@@ -140,6 +164,8 @@ module SoberSwag
140
164
  # This kinda violates the "be liberal in what you accept" principle,
141
165
  # but it keeps the docs honest: parameters sent in the body *must* be
142
166
  # in the body.
167
+ #
168
+ # @return [Hash]
143
169
  def body_params
144
170
  request.request_parameters
145
171
  end
@@ -147,6 +173,7 @@ module SoberSwag
147
173
  ##
148
174
  # Get the action-definition for the current action.
149
175
  # Under the hood, delegates to the `:action` key of rails params.
176
+ # @return [SoberSwag::Controller::Route]
150
177
  def current_action_def
151
178
  self.class.find_route(params[:action])
152
179
  end
@@ -3,6 +3,12 @@ module SoberSwag
3
3
  ##
4
4
  # Describe a single controller endpoint.
5
5
  class Route
6
+ ##
7
+ # @param method [Symbol] the HTTP method to get
8
+ # @param action_name [Symbol] the name of the rails action
9
+ # (the name of the controller method, usually)
10
+ # @param path [String] an OpenAPI V3 path template,
11
+ # which should [match this format](https://swagger.io/docs/specification/describing-parameters/#path-parameters)
6
12
  def initialize(method, action_name, path)
7
13
  @method = method
8
14
  @path = path
@@ -12,20 +18,56 @@ module SoberSwag
12
18
  @tags = []
13
19
  end
14
20
 
15
- attr_reader :response_serializers, :response_descriptions, :controller, :method, :path, :action_name
21
+ ##
22
+ # A hash of response code -> response serializer
23
+ # @return [Hash{Symbol => SoberSwag::Serializer::Base}]
24
+ # response code to response serializer
25
+ attr_reader :response_serializers
26
+
27
+ ##
28
+ # A hash of response code -> response description
29
+ # @return [Hash{Symbol => String}]
30
+ # response code to response description
31
+ attr_reader :response_descriptions
32
+
33
+ ##
34
+ # The HTTP method of this route.
35
+ # @return [Symbol]
36
+ attr_reader :method
37
+
38
+ ##
39
+ # The swagger path specifier of this route.
40
+ # @return [String]
41
+ attr_reader :path
42
+
43
+ ##
44
+ # The name of the rails action (usually the controller method) of this route.
45
+ # @return [Symbol]
46
+ attr_reader :action_name
16
47
 
17
48
  ##
18
49
  # What to parse the request body into.
50
+ # @return [Class] a swagger-able class type for a request body.
19
51
  attr_reader :request_body_class
20
52
  ##
21
53
  # What to parse the request query_params into.
54
+ # @return [Class] a swagger-able class type for query parameters.
22
55
  attr_reader :query_params_class
23
56
  ##
24
57
  # What to parse the path params into.
58
+ # @return [Class] a swagger-able class type for path parameters.
25
59
  attr_reader :path_params_class
26
60
 
27
61
  ##
28
62
  # Standard swagger tags.
63
+ #
64
+ # @overload tags()
65
+ # Get the tags for this route.
66
+ # @return [Array<String,Symbol>] the tags.
67
+ # @overload tags(*args)
68
+ # Set the tags for this route.
69
+ # @param tags [Array<String,Symbol>] the tags to set
70
+ # @return [Array<String,Symbol>] the tags used
29
71
  def tags(*args)
30
72
  return @tags if args.empty?
31
73
 
@@ -34,8 +76,13 @@ module SoberSwag
34
76
 
35
77
  ##
36
78
  # Define the request body, using SoberSwag's type-definition scheme.
37
- # The block passed will be used to define the body of a new sublcass of `base` (defaulted to {SoberSwag::InputObject}.)
38
- # If you want, you can also define utility methods in here
79
+ # The block passed will be used to define the body of a new subclass of `base` (defaulted to {SoberSwag::InputObject}.)
80
+ # @overload request_body(base)
81
+ # Give a Swagger-able type that will be used to parse the request body, and used in generated docs.
82
+ # @param base [Class] a swagger-able class
83
+ # @overload request_body(base = SoberSwag::InputObject, &block)
84
+ # Define a Swagger-able type inline to use to parse the request body.
85
+ # @see SoberSwag.input_object
39
86
  def request_body(base = SoberSwag::InputObject, &block)
40
87
  @request_body_class = make_input_object!(base, &block)
41
88
  action_module.const_set('RequestBody', @request_body_class)
@@ -48,9 +95,12 @@ module SoberSwag
48
95
  end
49
96
 
50
97
  ##
51
- # Define the shape of the query_params parameters, using SoberSwag's type-definition scheme.
52
- # The block passed is the body of the newly-defined type.
53
- # You can also include a base type.
98
+ # @overload query_params(base)
99
+ # Give a Swagger-able type that will be used to parse the query params, and used in generated docs.
100
+ # @param base [Class] a swagger-able class
101
+ # @overload query_params(base = SoberSwag::InputObject, &block)
102
+ # Define a Swagger-able type inline to use to parse the query params.
103
+ # @see SoberSwag.input_object
54
104
  def query_params(base = SoberSwag::InputObject, &block)
55
105
  @query_params_class = make_input_object!(base, &block)
56
106
  action_module.const_set('QueryParams', @query_params_class)
@@ -63,9 +113,12 @@ module SoberSwag
63
113
  end
64
114
 
65
115
  ##
66
- # Define the shape of the *path* parameters, using SoberSwag's type-definition scheme.
67
- # The block passed will be the body of a new subclass of `base` (defaulted to {SoberSwag::InputObject}).
68
- # Names of this should match the names in the path template originally passed to {SoberSwag::Controller::Route.new}
116
+ # @overload path_params(base)
117
+ # Give a Swagger-able type that will be used to parse the path params, and used in generated docs.
118
+ # @param base [Class] a swagger-able class
119
+ # @overload path_params(base = SoberSwag::InputObject, &block)
120
+ # Define a Swagger-able type inline to use to parse the path params.
121
+ # @see SoberSwag.input_object
69
122
  def path_params(base = SoberSwag::InputObject, &block)
70
123
  @path_params_class = make_input_object!(base, &block)
71
124
  action_module.const_set('PathParams', @path_params_class)
@@ -78,19 +131,27 @@ module SoberSwag
78
131
  end
79
132
 
80
133
  ##
81
- # Define the body of the action method in the controller.
82
- def action(&body)
83
- return @action if body.nil?
84
-
85
- @action ||= body
86
- end
87
-
134
+ # @overload description()
135
+ # Get a description of this route object.
136
+ # @return [String] markdown-formatted description
137
+ # @overload description(desc)
138
+ # Set the description of this route object.
139
+ # @param desc [String] markdown-formatted description
140
+ # @return [String] `desc`.
88
141
  def description(desc = nil)
89
142
  return @description if desc.nil?
90
143
 
91
144
  @description = desc
92
145
  end
93
146
 
147
+ ##
148
+ # @overload summary()
149
+ # Get the summary of this route object, a short string that identifies
150
+ # what it does.
151
+ # @return [String] markdown-formatted summary
152
+ # @overload summary(sum)
153
+ # Set a short, markdown-formatted summary of what this route does.
154
+ # @param sum [String] markdown-formatted summary
94
155
  def summary(sum = nil)
95
156
  return @summary if sum.nil?
96
157
 
@@ -100,14 +161,35 @@ module SoberSwag
100
161
  ##
101
162
  # The container module for all the constants this will eventually define.
102
163
  # Each class generated by this Route will be defined within this module.
164
+ # @return [Module] the module under which constants will be defined.
103
165
  def action_module
104
166
  @action_module ||= Module.new
105
167
  end
106
168
 
107
169
  ##
108
- # Define a serializer for a response with the given status code.
109
- # You may either give a serializer you defined elsewhere, or define one inline as if passed to
110
- # {SoberSwag::OutputObject.define}
170
+ # @overload response(status_code, description, &block)
171
+ # Define a new response from this route, by defining a serializer inline.
172
+ # This serializer will be defined as if with {SoberSwag::OutputObject.define}
173
+ #
174
+ # Generally, you want to define your serializers elsewhere for independent testing and such.
175
+ # However, if you have a really quick thing to serialize, this works.
176
+ # @param status_code [Symbol]
177
+ # the name of the HTTP status of this response.
178
+ # @param description [String]
179
+ # a description of what this response is, markdown-formatted
180
+ # @param block [Proc]
181
+ # passed to {SoberSwag::OutputObject.define}
182
+ #
183
+ # @overload response(status_code, description, serializer)
184
+ # Define a new response from this route, with an existing serializer.
185
+ # The generated swagger will document this response's format using the serializer.
186
+ #
187
+ # @param status_code [Symbol]
188
+ # the name of the HTTP status of this response
189
+ # @param description [String]
190
+ # a description of what this response is, markdown-formatted
191
+ # @param serializer [SoberSwag::Serializer::Base] a serializer to use for the
192
+ # body of this response
111
193
  def response(status_code, description, serializer = nil, &block)
112
194
  status_key = Rack::Utils.status_code(status_code)
113
195
 
@@ -120,7 +202,8 @@ module SoberSwag
120
202
  end
121
203
 
122
204
  ##
123
- # What you should call the module of this action in your controller
205
+ # What you should call the module of this action in your controller.
206
+ # @return [String]
124
207
  def action_module_name
125
208
  action_name.to_s.classify
126
209
  end