@@ -22,17 +22,10 @@ module Versioner
22
22
# X-Cascade header to alert Grape::Router to attempt the next matched
23
23
# route.
24
24
class Header < Base
25
+ include VersionerHelpers
26
+
25
27
def before
26
- handler = Grape ::Util ::AcceptHeaderHandler . new (
27
- accept_header : env [ Grape ::Http ::Headers ::HTTP_ACCEPT ] ,
28
- versions : options [ :versions ] ,
29
- **options . fetch ( :version_options ) { { } }
30
- )
31
-
32
- handler . match_best_quality_media_type! (
33
- content_types : content_types ,
34
- allowed_methods : env [ Grape ::Env ::GRAPE_ALLOWED_METHODS ]
35
- ) do |media_type |
28
+ match_best_quality_media_type! do |media_type |
36
29
env . update (
37
30
Grape ::Env ::API_TYPE => media_type . type ,
38
31
Grape ::Env ::API_SUBTYPE => media_type . subtype ,
@@ -42,6 +35,98 @@ def before
42
35
)
43
36
end
44
37
end
38
+
39
+ private
40
+
41
+ def match_best_quality_media_type!
42
+ return unless vendor
43
+
44
+ strict_header_checks!
45
+ media_type = Grape ::Util ::MediaType . best_quality ( accept_header , available_media_types )
46
+ if media_type
47
+ yield media_type
48
+ else
49
+ fail! ( allowed_methods )
50
+ end
51
+ end
52
+
53
+ def allowed_methods
54
+ env [ Grape ::Env ::GRAPE_ALLOWED_METHODS ]
55
+ end
56
+
57
+ def accept_header
58
+ env [ Grape ::Http ::Headers ::HTTP_ACCEPT ]
59
+ end
60
+
61
+ def strict_header_checks!
62
+ return unless strict?
63
+
64
+ accept_header_check!
65
+ version_and_vendor_check!
66
+ end
67
+
68
+ def accept_header_check!
69
+ return if accept_header . present?
70
+
71
+ invalid_accept_header! ( 'Accept header must be set.' )
72
+ end
73
+
74
+ def version_and_vendor_check!
75
+ return if versions . blank? || version_and_vendor?
76
+
77
+ invalid_accept_header! ( 'API vendor or version not found.' )
78
+ end
79
+
80
+ def q_values_mime_types
81
+ @q_values_mime_types ||= Rack ::Utils . q_values ( accept_header ) . map ( &:first )
82
+ end
83
+
84
+ def version_and_vendor?
85
+ q_values_mime_types . any? { |mime_type | Grape ::Util ::MediaType . match? ( mime_type ) }
86
+ end
87
+
88
+ def invalid_accept_header! ( message )
89
+ raise Grape ::Exceptions ::InvalidAcceptHeader . new ( message , error_headers )
90
+ end
91
+
92
+ def invalid_version_header! ( message )
93
+ raise Grape ::Exceptions ::InvalidVersionHeader . new ( message , error_headers )
94
+ end
95
+
96
+ def fail! ( grape_allowed_methods )
97
+ return grape_allowed_methods if grape_allowed_methods . present?
98
+
99
+ media_types = q_values_mime_types . map { |mime_type | Grape ::Util ::MediaType . parse ( mime_type ) }
100
+ vendor_not_found! ( media_types ) || version_not_found! ( media_types )
101
+ end
102
+
103
+ def vendor_not_found! ( media_types )
104
+ return unless media_types . all? { |media_type | media_type &.vendor && media_type . vendor != vendor }
105
+
106
+ invalid_accept_header! ( 'API vendor not found.' )
107
+ end
108
+
109
+ def version_not_found! ( media_types )
110
+ return unless media_types . all? { |media_type | media_type &.version && versions &.exclude? ( media_type . version ) }
111
+
112
+ invalid_version_header! ( 'API version not found.' )
113
+ end
114
+
115
+ def available_media_types
116
+ [ ] . tap do |available_media_types |
117
+ base_media_type = "application/vnd.#{ vendor } "
118
+ content_types . each_key do |extension |
119
+ versions &.reverse_each do |version |
120
+ available_media_types << "#{ base_media_type } -#{ version } +#{ extension } "
121
+ available_media_types << "#{ base_media_type } -#{ version } "
122
+ end
123
+ available_media_types << "#{ base_media_type } +#{ extension } "
124
+ end
125
+
126
+ available_media_types << base_media_type
127
+ available_media_types . concat ( content_types . values . flatten )
128
+ end
129
+ end
45
130
end
46
131
end
47
132
end
0 commit comments