hanami-controller 2.0.0.rc1 → 2.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +0 -6
- data/hanami-controller.gemspec +4 -2
- data/lib/hanami/action/cache/cache_control.rb +0 -2
- data/lib/hanami/action/cache/expires.rb +0 -2
- data/lib/hanami/action/cache.rb +0 -4
- data/lib/hanami/action/config/formats.rb +216 -0
- data/lib/hanami/action/config.rb +18 -113
- data/lib/hanami/action/errors.rb +8 -1
- data/lib/hanami/action/mime/request_mime_weight.rb +66 -0
- data/lib/hanami/action/mime.rb +177 -220
- data/lib/hanami/action/params.rb +0 -1
- data/lib/hanami/action/request.rb +0 -1
- data/lib/hanami/action/response.rb +10 -10
- data/lib/hanami/action/session.rb +0 -2
- data/lib/hanami/action/validatable.rb +1 -1
- data/lib/hanami/action.rb +39 -56
- data/lib/hanami/controller/version.rb +6 -1
- data/lib/hanami/controller.rb +2 -14
- data/lib/hanami-controller.rb +3 -0
- metadata +38 -7
data/lib/hanami/action/mime.rb
CHANGED
@@ -68,260 +68,217 @@ module Hanami
|
|
68
68
|
zip: "application/zip"
|
69
69
|
}.freeze
|
70
70
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
71
|
+
ANY_TYPE = "*/*"
|
72
|
+
|
73
|
+
class << self
|
74
|
+
# Returns a format name for the given content type.
|
75
|
+
#
|
76
|
+
# The format name will come from the configured formats, if such a format is configured
|
77
|
+
# there, or instead from the default list of formats in `Mime::TYPES`.
|
78
|
+
#
|
79
|
+
# Returns nil if no matching format can be found.
|
80
|
+
#
|
81
|
+
# This is used to return the format name a {Response}.
|
82
|
+
#
|
83
|
+
# @example
|
84
|
+
# detect_format("application/jsonl charset=utf-8", config) # => :json
|
85
|
+
#
|
86
|
+
# @return [Symbol, nil]
|
87
|
+
#
|
88
|
+
# @see Response#format
|
89
|
+
# @see Action#finish
|
90
|
+
#
|
91
|
+
# @since 2.0.0
|
92
|
+
# @api private
|
93
|
+
def detect_format(content_type, config)
|
94
|
+
return if content_type.nil?
|
76
95
|
|
77
|
-
|
78
|
-
|
79
|
-
# on the content of the ACCEPT header taking in consideration the weights
|
80
|
-
#
|
81
|
-
# If no ACCEPT header it will check the default response_format, then the default request format and
|
82
|
-
# lastly it will fallback to DEFAULT_CONTENT_TYPE
|
83
|
-
#
|
84
|
-
# @return [String]
|
85
|
-
#
|
86
|
-
# @since 2.0.0
|
87
|
-
# @api private
|
88
|
-
def self.content_type(config, request, accepted_mime_types)
|
89
|
-
if request.accept_header?
|
90
|
-
type = best_q_match(request.accept, accepted_mime_types)
|
91
|
-
return type if type
|
96
|
+
ct = content_type.split(";").first
|
97
|
+
config.formats.format_for(ct) || TYPES.key(ct)
|
92
98
|
end
|
93
99
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
# @see Hanami::Action::Mime#finish
|
128
|
-
# @example
|
129
|
-
# detect_format("text/html; charset=utf-8", config) #=> :html
|
130
|
-
#
|
131
|
-
# @return [Symbol, nil]
|
132
|
-
#
|
133
|
-
# @since 2.0.0
|
134
|
-
# @api private
|
135
|
-
def self.detect_format(content_type, config)
|
136
|
-
return if content_type.nil?
|
137
|
-
|
138
|
-
ct = content_type.split(";").first
|
139
|
-
config.format_for(ct) || format_for(ct)
|
140
|
-
end
|
141
|
-
|
142
|
-
# @since 2.0.0
|
143
|
-
# @api private
|
144
|
-
def self.format_for(content_type)
|
145
|
-
TYPES.key(content_type)
|
146
|
-
end
|
147
|
-
|
148
|
-
# @since 2.0.0
|
149
|
-
# @api private
|
150
|
-
def self.detect_format_and_content_type(value, config)
|
151
|
-
case value
|
152
|
-
when Symbol
|
153
|
-
[value, format_to_mime_type(value, config)]
|
154
|
-
when String
|
155
|
-
[detect_format(value, config), value]
|
156
|
-
else
|
157
|
-
raise UnknownFormatError.new(value)
|
100
|
+
# Returns a format name and content type pair for a given format name or content type
|
101
|
+
# string.
|
102
|
+
#
|
103
|
+
# @example
|
104
|
+
# detect_format_and_content_type(:json, config)
|
105
|
+
# # => [:json, "application/json"]
|
106
|
+
#
|
107
|
+
# detect_format_and_content_type("application/json", config)
|
108
|
+
# # => [:json, "application/json"]
|
109
|
+
#
|
110
|
+
# @example Unknown format name
|
111
|
+
# detect_format_and_content_type(:unknown, config)
|
112
|
+
# # raises Hanami::Action::UnknownFormatError
|
113
|
+
#
|
114
|
+
# @example Unknown content type
|
115
|
+
# detect_format_and_content_type("application/unknown", config)
|
116
|
+
# # => [nil, "application/unknown"]
|
117
|
+
#
|
118
|
+
# @return [Array<(Symbol, String)>]
|
119
|
+
#
|
120
|
+
# @raise [Hanami::Action::UnknownFormatError] if an unknown format name is given
|
121
|
+
#
|
122
|
+
# @since 2.0.0
|
123
|
+
# @api private
|
124
|
+
def detect_format_and_content_type(value, config)
|
125
|
+
case value
|
126
|
+
when Symbol
|
127
|
+
[value, format_to_mime_type(value, config)]
|
128
|
+
when String
|
129
|
+
[detect_format(value, config), value]
|
130
|
+
else
|
131
|
+
raise UnknownFormatError.new(value)
|
132
|
+
end
|
158
133
|
end
|
159
|
-
end
|
160
134
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
135
|
+
# Returns a string combining the given content type and charset, intended for setting as a
|
136
|
+
# `Content-Type` header.
|
137
|
+
#
|
138
|
+
# @example
|
139
|
+
# Mime.content_type_with_charset("application/json", "utf-8")
|
140
|
+
# # => "application/json; charset=utf-8"
|
141
|
+
#
|
142
|
+
# @param content_type [String]
|
143
|
+
# @param charset [String]
|
144
|
+
#
|
145
|
+
# @return [String]
|
146
|
+
#
|
147
|
+
# @since 2.0.0
|
148
|
+
# @api private
|
149
|
+
def content_type_with_charset(content_type, charset)
|
150
|
+
"#{content_type}; charset=#{charset}"
|
176
151
|
end
|
177
152
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
# @since 2.0.0
|
197
|
-
# @api private
|
198
|
-
def self.enforce_accept(request, config)
|
199
|
-
return unless request.accept_header?
|
200
|
-
|
201
|
-
accept_types = ::Rack::Utils.q_values(request.accept).map(&:first)
|
202
|
-
return if accept_types.any? { |mime_type| accepted_mime_type?(mime_type, config) }
|
153
|
+
# Returns a string combining a MIME type and charset, intended for setting as the
|
154
|
+
# `Content-Type` header for the response to the given request.
|
155
|
+
#
|
156
|
+
# This uses the request's `Accept` header (if present) along with the configured formats to
|
157
|
+
# determine the best content type to return.
|
158
|
+
#
|
159
|
+
# @return [String]
|
160
|
+
#
|
161
|
+
# @see Action#call
|
162
|
+
#
|
163
|
+
# @since 2.0.0
|
164
|
+
# @api private
|
165
|
+
def response_content_type_with_charset(request, config)
|
166
|
+
content_type_with_charset(
|
167
|
+
response_content_type(request, config),
|
168
|
+
config.default_charset || Action::DEFAULT_CHARSET
|
169
|
+
)
|
170
|
+
end
|
203
171
|
|
204
|
-
|
205
|
-
|
172
|
+
# Patched version of <tt>Rack::Utils.best_q_match</tt>.
|
173
|
+
#
|
174
|
+
# @since 2.0.0
|
175
|
+
# @api private
|
176
|
+
#
|
177
|
+
# @see http://www.rubydoc.info/gems/rack/Rack/Utils#best_q_match-class_method
|
178
|
+
# @see https://github.com/rack/rack/pull/659
|
179
|
+
# @see https://github.com/hanami/controller/issues/59
|
180
|
+
# @see https://github.com/hanami/controller/issues/104
|
181
|
+
# @see https://github.com/hanami/controller/issues/275
|
182
|
+
def best_q_match(q_value_header, available_mimes = TYPES.values)
|
183
|
+
::Rack::Utils.q_values(q_value_header).each_with_index.map { |(req_mime, quality), index|
|
184
|
+
match = available_mimes.find { |am| ::Rack::Mime.match?(am, req_mime) }
|
185
|
+
next unless match
|
186
|
+
|
187
|
+
RequestMimeWeight.new(req_mime, quality, index, match)
|
188
|
+
}.compact.max&.format
|
189
|
+
end
|
206
190
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
content_type = request.content_type || default_content_type(config)
|
191
|
+
# Yields if an action is configured with `formats`, the request has an `Accept` header, an
|
192
|
+
# none of the Accept types matches the accepted formats. The given block is expected to halt
|
193
|
+
# the request handling.
|
194
|
+
#
|
195
|
+
# If any of these conditions are not met, then the request is acceptable and the method
|
196
|
+
# returns without yielding.
|
197
|
+
#
|
198
|
+
# @see Action#enforce_accepted_mime_types
|
199
|
+
# @see Config#formats
|
200
|
+
#
|
201
|
+
# @since 2.0.0
|
202
|
+
# @api private
|
203
|
+
def enforce_accept(request, config)
|
204
|
+
return unless request.accept_header?
|
222
205
|
|
223
|
-
|
206
|
+
accept_types = ::Rack::Utils.q_values(request.accept).map(&:first)
|
207
|
+
return if accept_types.any? { |mime_type| accepted_mime_type?(mime_type, config) }
|
224
208
|
|
225
|
-
|
209
|
+
yield
|
210
|
+
end
|
226
211
|
|
227
|
-
|
228
|
-
|
212
|
+
# Yields if an action is configured with `formats`, the request has a `Content-Type` header
|
213
|
+
# (or a `default_requst_format` is configured), and the content type does not match the
|
214
|
+
# accepted formats. The given block is expected to halt the request handling.
|
215
|
+
#
|
216
|
+
# If any of these conditions are not met, then the request is acceptable and the method
|
217
|
+
# returns without yielding.
|
218
|
+
#
|
219
|
+
# @see Action#enforce_accepted_mime_types
|
220
|
+
# @see Config#formats
|
221
|
+
#
|
222
|
+
# @since 2.0.0
|
223
|
+
# @api private
|
224
|
+
def enforce_content_type(request, config)
|
225
|
+
content_type = request.content_type
|
229
226
|
|
230
|
-
|
231
|
-
# @api private
|
232
|
-
def self.accepted_mime_type?(mime_type, config)
|
233
|
-
config.accepted_mime_types.any? { |accepted_mime_type|
|
234
|
-
::Rack::Mime.match?(accepted_mime_type, mime_type)
|
235
|
-
}
|
236
|
-
end
|
227
|
+
return if content_type.nil?
|
237
228
|
|
238
|
-
|
239
|
-
#
|
240
|
-
# @return [String]
|
241
|
-
#
|
242
|
-
# @since 2.0.0
|
243
|
-
# @api private
|
244
|
-
def self.calculate_content_type_with_charset(config, request, accepted_mime_types)
|
245
|
-
charset = self.charset(config.default_charset)
|
246
|
-
content_type = self.content_type(config, request, accepted_mime_types)
|
247
|
-
content_type_with_charset(content_type, charset)
|
248
|
-
end
|
229
|
+
return if accepted_mime_type?(content_type, config)
|
249
230
|
|
250
|
-
|
251
|
-
|
252
|
-
# @since 2.0.0
|
253
|
-
# @api private
|
254
|
-
#
|
255
|
-
# @see http://www.rubydoc.info/gems/rack/Rack/Utils#best_q_match-class_method
|
256
|
-
# @see https://github.com/rack/rack/pull/659
|
257
|
-
# @see https://github.com/hanami/controller/issues/59
|
258
|
-
# @see https://github.com/hanami/controller/issues/104
|
259
|
-
# @see https://github.com/hanami/controller/issues/275
|
260
|
-
def self.best_q_match(q_value_header, available_mimes = TYPES.values)
|
261
|
-
::Rack::Utils.q_values(q_value_header).each_with_index.map do |(req_mime, quality), index|
|
262
|
-
match = available_mimes.find { |am| ::Rack::Mime.match?(am, req_mime) }
|
263
|
-
next unless match
|
231
|
+
yield
|
232
|
+
end
|
264
233
|
|
265
|
-
|
266
|
-
end.compact.max&.format
|
267
|
-
end
|
234
|
+
private
|
268
235
|
|
269
|
-
# @since 1.0.1
|
270
|
-
# @api private
|
271
|
-
class RequestMimeWeight
|
272
236
|
# @since 2.0.0
|
273
237
|
# @api private
|
274
|
-
|
275
|
-
|
238
|
+
def accepted_mime_type?(mime_type, config)
|
239
|
+
accepted_mime_types(config).any? { |accepted_mime_type|
|
240
|
+
::Rack::Mime.match?(accepted_mime_type, mime_type)
|
241
|
+
}
|
242
|
+
end
|
276
243
|
|
277
244
|
# @since 2.0.0
|
278
245
|
# @api private
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
include Comparable
|
283
|
-
|
284
|
-
# @since 1.0.1
|
285
|
-
# @api private
|
286
|
-
attr_reader :quality
|
246
|
+
def accepted_mime_types(config)
|
247
|
+
return [ANY_TYPE] if config.formats.empty?
|
287
248
|
|
288
|
-
|
289
|
-
|
290
|
-
attr_reader :index
|
249
|
+
config.formats.map { |format| format_to_mime_types(format, config) }.flatten(1)
|
250
|
+
end
|
291
251
|
|
292
|
-
# @since
|
252
|
+
# @since 2.0.0
|
293
253
|
# @api private
|
294
|
-
|
254
|
+
def response_content_type(request, config)
|
255
|
+
if request.accept_header?
|
256
|
+
all_mime_types = TYPES.values + config.formats.mapping.keys
|
257
|
+
content_type = best_q_match(request.accept, all_mime_types)
|
295
258
|
|
296
|
-
|
297
|
-
|
298
|
-
attr_reader :format
|
259
|
+
return content_type if content_type
|
260
|
+
end
|
299
261
|
|
300
|
-
|
301
|
-
|
302
|
-
|
262
|
+
if config.formats.default
|
263
|
+
return format_to_mime_type(config.formats.default, config)
|
264
|
+
end
|
303
265
|
|
304
|
-
|
305
|
-
# @api private
|
306
|
-
def initialize(mime, quality, index, format = mime)
|
307
|
-
@quality, @index, @format = quality, index, format
|
308
|
-
calculate_priority(mime)
|
266
|
+
Action::DEFAULT_CONTENT_TYPE
|
309
267
|
end
|
310
268
|
|
311
|
-
# @since
|
269
|
+
# @since 2.0.0
|
312
270
|
# @api private
|
313
|
-
def
|
314
|
-
|
315
|
-
|
316
|
-
other.index <=> index
|
271
|
+
def format_to_mime_type(format, config)
|
272
|
+
config.formats.mime_type_for(format) ||
|
273
|
+
TYPES.fetch(format) { raise Hanami::Action::UnknownFormatError.new(format) }
|
317
274
|
end
|
318
275
|
|
319
|
-
|
320
|
-
|
321
|
-
# @since 1.0.1
|
276
|
+
# @since 2.0.0
|
322
277
|
# @api private
|
323
|
-
def
|
324
|
-
|
278
|
+
def format_to_mime_types(format, config)
|
279
|
+
config.formats.mime_types_for(format).tap { |types|
|
280
|
+
types << TYPES[format] if TYPES.key?(format)
|
281
|
+
}
|
325
282
|
end
|
326
283
|
end
|
327
284
|
end
|
data/lib/hanami/action/params.rb
CHANGED
@@ -3,11 +3,6 @@
|
|
3
3
|
require "rack"
|
4
4
|
require "rack/response"
|
5
5
|
require "hanami/utils/kernel"
|
6
|
-
require "hanami/action/halt"
|
7
|
-
require "hanami/action/cookie_jar"
|
8
|
-
require "hanami/action/cache/cache_control"
|
9
|
-
require "hanami/action/cache/expires"
|
10
|
-
require "hanami/action/cache/conditional_get"
|
11
6
|
require_relative "errors"
|
12
7
|
|
13
8
|
module Hanami
|
@@ -44,10 +39,10 @@ module Hanami
|
|
44
39
|
# @since 2.0.0
|
45
40
|
# @api private
|
46
41
|
def self.build(status, env)
|
47
|
-
new(config:
|
42
|
+
new(config: Action.config.dup, content_type: Mime.best_q_match(env[Action::HTTP_ACCEPT]), env: env).tap do |r|
|
48
43
|
r.status = status
|
49
44
|
r.body = Http::Status.message_for(status)
|
50
|
-
r.set_format(Mime.
|
45
|
+
r.set_format(Mime.detect_format(r.content_type), config)
|
51
46
|
end
|
52
47
|
end
|
53
48
|
|
@@ -111,9 +106,12 @@ module Hanami
|
|
111
106
|
|
112
107
|
# Sets the format and associated content type for the response.
|
113
108
|
#
|
114
|
-
# Either a format name (`:json`) or a
|
115
|
-
#
|
116
|
-
#
|
109
|
+
# Either a format name (`:json`) or a MIME type (`"application/json"`) may be given. In either
|
110
|
+
# case, the format or content type will be derived from the given value, and both will be set.
|
111
|
+
#
|
112
|
+
# Providing an unknown format name will raise an {Hanami::Action::UnknownFormatError}.
|
113
|
+
#
|
114
|
+
# Providing an unknown MIME type will set the content type and set the format as nil.
|
117
115
|
#
|
118
116
|
# @example Assigning via a format name symbol
|
119
117
|
# response.format = :json
|
@@ -127,6 +125,8 @@ module Hanami
|
|
127
125
|
#
|
128
126
|
# @param value [Symbol, String] the format name or content type
|
129
127
|
#
|
128
|
+
# @raise [Hanami::Action::UnknownFormatError] if an unknown format name is given
|
129
|
+
#
|
130
130
|
# @see Config#formats
|
131
131
|
#
|
132
132
|
# @since 2.0.0
|
data/lib/hanami/action.rb
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
begin
|
4
|
-
require "dry/core"
|
5
|
-
require "dry/types"
|
6
|
-
require "hanami/validations"
|
7
|
-
require "hanami/action/validatable"
|
8
|
-
rescue LoadError # rubocop:disable Lint/SuppressedException
|
9
|
-
end
|
10
|
-
|
11
3
|
require "dry/configurable"
|
12
|
-
require "hanami/utils/callbacks"
|
13
4
|
require "hanami/utils"
|
14
|
-
require "hanami/utils/
|
5
|
+
require "hanami/utils/callbacks"
|
15
6
|
require "hanami/utils/kernel"
|
7
|
+
require "hanami/utils/string"
|
16
8
|
require "rack"
|
17
9
|
require "rack/utils"
|
10
|
+
require "zeitwerk"
|
18
11
|
|
19
|
-
require_relative "action/config"
|
20
12
|
require_relative "action/constants"
|
21
|
-
require_relative "action/base_params"
|
22
|
-
require_relative "action/halt"
|
23
|
-
require_relative "action/mime"
|
24
|
-
require_relative "action/rack/file"
|
25
|
-
require_relative "action/request"
|
26
|
-
require_relative "action/response"
|
27
13
|
require_relative "action/errors"
|
28
14
|
|
29
15
|
module Hanami
|
@@ -42,18 +28,37 @@ module Hanami
|
|
42
28
|
#
|
43
29
|
# @api public
|
44
30
|
class Action
|
31
|
+
# @since 2.0.0
|
32
|
+
# @api private
|
33
|
+
def self.gem_loader
|
34
|
+
@gem_loader ||= Zeitwerk::Loader.new.tap do |loader|
|
35
|
+
root = File.expand_path("..", __dir__)
|
36
|
+
loader.tag = "hanami-controller"
|
37
|
+
loader.inflector = Zeitwerk::GemInflector.new("#{root}/hanami-controller.rb")
|
38
|
+
loader.push_dir(root)
|
39
|
+
loader.ignore(
|
40
|
+
"#{root}/hanami-controller.rb",
|
41
|
+
"#{root}/hanami/controller/version.rb",
|
42
|
+
"#{root}/hanami/action/{constants,errors,params,validatable}.rb"
|
43
|
+
)
|
44
|
+
loader.inflector.inflect("csrf_protection" => "CSRFProtection")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
gem_loader.setup
|
49
|
+
|
50
|
+
# Make conditional requires after Zeitwerk setup so any internal autoloading works as expected
|
51
|
+
begin
|
52
|
+
require "hanami/validations"
|
53
|
+
require_relative "action/validatable"
|
54
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
55
|
+
end
|
56
|
+
|
45
57
|
extend Dry::Configurable(config_class: Config)
|
46
58
|
|
47
59
|
# See {Config} for individual setting accessor API docs
|
48
60
|
setting :handled_exceptions, default: {}
|
49
|
-
setting :formats, default: Config::
|
50
|
-
setting :default_request_format, constructor: -> (format) {
|
51
|
-
Utils::Kernel.Symbol(format) unless format.nil?
|
52
|
-
}
|
53
|
-
setting :default_response_format, constructor: -> (format) {
|
54
|
-
Utils::Kernel.Symbol(format) unless format.nil?
|
55
|
-
}
|
56
|
-
setting :accepted_formats, default: []
|
61
|
+
setting :formats, default: Config::Formats.new, mutable: true
|
57
62
|
setting :default_charset
|
58
63
|
setting :default_headers, default: {}, constructor: -> (headers) { headers.compact }
|
59
64
|
setting :cookies, default: {}, constructor: -> (cookie_options) {
|
@@ -65,8 +70,8 @@ module Hanami
|
|
65
70
|
Pathname(File.expand_path(dir || Dir.pwd)).realpath
|
66
71
|
}
|
67
72
|
setting :public_directory, default: Config::DEFAULT_PUBLIC_DIRECTORY
|
68
|
-
setting :before_callbacks, default: Utils::Callbacks::Chain.new,
|
69
|
-
setting :after_callbacks, default: Utils::Callbacks::Chain.new,
|
73
|
+
setting :before_callbacks, default: Utils::Callbacks::Chain.new, mutable: true
|
74
|
+
setting :after_callbacks, default: Utils::Callbacks::Chain.new, mutable: true
|
70
75
|
|
71
76
|
# @!scope class
|
72
77
|
|
@@ -75,7 +80,7 @@ module Hanami
|
|
75
80
|
#
|
76
81
|
# @example Access inside class body
|
77
82
|
# class Show < Hanami::Action
|
78
|
-
# config.
|
83
|
+
# config.format :json
|
79
84
|
# end
|
80
85
|
#
|
81
86
|
# @return [Config]
|
@@ -266,34 +271,12 @@ module Hanami
|
|
266
271
|
config.after_callbacks.prepend(...)
|
267
272
|
end
|
268
273
|
|
269
|
-
# Restrict the access to the specified mime type symbols.
|
270
|
-
#
|
271
|
-
# @param formats[Array<Symbol>] one or more symbols representing mime type(s)
|
272
|
-
#
|
273
|
-
# @raise [Hanami::Action::UnknownFormatError] if the symbol cannot
|
274
|
-
# be converted into a mime type
|
275
|
-
#
|
276
|
-
# @since 0.1.0
|
277
|
-
#
|
278
274
|
# @see Config#format
|
279
275
|
#
|
280
|
-
# @
|
281
|
-
#
|
282
|
-
|
283
|
-
|
284
|
-
# accept :html, :json
|
285
|
-
#
|
286
|
-
# def handle(req, res)
|
287
|
-
# # ...
|
288
|
-
# end
|
289
|
-
# end
|
290
|
-
#
|
291
|
-
# # When called with "*/*" => 200
|
292
|
-
# # When called with "text/html" => 200
|
293
|
-
# # When called with "application/json" => 200
|
294
|
-
# # When called with "application/xml" => 415
|
295
|
-
def self.accept(*formats)
|
296
|
-
config.accepted_formats = formats
|
276
|
+
# @since 2.0.0
|
277
|
+
# @api public
|
278
|
+
def self.format(...)
|
279
|
+
config.format(...)
|
297
280
|
end
|
298
281
|
|
299
282
|
# @see Config#handle_exception
|
@@ -331,7 +314,7 @@ module Hanami
|
|
331
314
|
response = build_response(
|
332
315
|
request: request,
|
333
316
|
config: config,
|
334
|
-
content_type: Mime.
|
317
|
+
content_type: Mime.response_content_type_with_charset(request, config),
|
335
318
|
env: env,
|
336
319
|
headers: config.default_headers,
|
337
320
|
sessions_enabled: sessions_enabled?
|
@@ -425,7 +408,7 @@ module Hanami
|
|
425
408
|
# @since 2.0.0
|
426
409
|
# @api private
|
427
410
|
def enforce_accepted_mime_types(request)
|
428
|
-
return if config.
|
411
|
+
return if config.formats.empty?
|
429
412
|
|
430
413
|
Mime.enforce_accept(request, config) { return halt 406 }
|
431
414
|
Mime.enforce_content_type(request, config) { return halt 415 }
|