respect-rails 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 (110) hide show
  1. data/FAQ.md +98 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +291 -0
  4. data/RELATED_WORK.md +47 -0
  5. data/RELEASE_NOTES.md +20 -0
  6. data/Rakefile +32 -0
  7. data/app/assets/javascripts/respect/rails/schemas.js +32 -0
  8. data/app/assets/stylesheets/respect/rails/schemas.css +160 -0
  9. data/app/controllers/respect/rails/schemas_controller.rb +36 -0
  10. data/app/helpers/respect/rails/schemas_helper.rb +78 -0
  11. data/app/views/layouts/respect/rails/schemas.html.erb +14 -0
  12. data/app/views/respect/rails/request_validation_exception.html.erb +38 -0
  13. data/app/views/respect/rails/schemas/doc.html.erb +158 -0
  14. data/app/views/respect/rails/schemas/index.html.erb +4 -0
  15. data/config/routes.rb +4 -0
  16. data/lib/respect/rails/action_def.rb +37 -0
  17. data/lib/respect/rails/action_schema.rb +41 -0
  18. data/lib/respect/rails/application_info.rb +26 -0
  19. data/lib/respect/rails/controller_helper.rb +107 -0
  20. data/lib/respect/rails/engine.rb +63 -0
  21. data/lib/respect/rails/engine_info.rb +27 -0
  22. data/lib/respect/rails/headers_helper.rb +11 -0
  23. data/lib/respect/rails/headers_simplifier.rb +31 -0
  24. data/lib/respect/rails/info.rb +72 -0
  25. data/lib/respect/rails/request_def.rb +38 -0
  26. data/lib/respect/rails/request_helper.rb +101 -0
  27. data/lib/respect/rails/request_schema.rb +102 -0
  28. data/lib/respect/rails/response_def.rb +43 -0
  29. data/lib/respect/rails/response_helper.rb +67 -0
  30. data/lib/respect/rails/response_schema.rb +84 -0
  31. data/lib/respect/rails/response_schema_set.rb +60 -0
  32. data/lib/respect/rails/route_info.rb +101 -0
  33. data/lib/respect/rails/version.rb +5 -0
  34. data/lib/respect/rails.rb +74 -0
  35. data/lib/tasks/respect_tasks.rake +4 -0
  36. data/test/dummy/README.rdoc +261 -0
  37. data/test/dummy/Rakefile +7 -0
  38. data/test/dummy/app/assets/javascripts/application.js +15 -0
  39. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  40. data/test/dummy/app/controllers/application_controller.rb +3 -0
  41. data/test/dummy/app/controllers/automatic_validation_controller.rb +300 -0
  42. data/test/dummy/app/controllers/caught_exception_controller.rb +58 -0
  43. data/test/dummy/app/controllers/disabled_controller.rb +37 -0
  44. data/test/dummy/app/controllers/manual_validation_controller.rb +63 -0
  45. data/test/dummy/app/controllers/no_schema_controller.rb +17 -0
  46. data/test/dummy/app/controllers/skipped_automatic_validation_controller.rb +35 -0
  47. data/test/dummy/app/helpers/application_helper.rb +2 -0
  48. data/test/dummy/app/helpers/respect/application_macros.rb +10 -0
  49. data/test/dummy/app/helpers/respect/circle_schema.rb +16 -0
  50. data/test/dummy/app/helpers/respect/point_schema.rb +19 -0
  51. data/test/dummy/app/helpers/respect/rgba_schema.rb +18 -0
  52. data/test/dummy/app/views/automatic_validation/request_format.html.erb +1 -0
  53. data/test/dummy/app/views/automatic_validation/request_format.pdf.erb +1 -0
  54. data/test/dummy/app/views/caught_exception/response_validator.html.erb +1 -0
  55. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  56. data/test/dummy/config/application.rb +58 -0
  57. data/test/dummy/config/boot.rb +10 -0
  58. data/test/dummy/config/database.yml +25 -0
  59. data/test/dummy/config/environment.rb +5 -0
  60. data/test/dummy/config/environments/development.rb +37 -0
  61. data/test/dummy/config/environments/production.rb +67 -0
  62. data/test/dummy/config/environments/test.rb +37 -0
  63. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  64. data/test/dummy/config/initializers/inflections.rb +15 -0
  65. data/test/dummy/config/initializers/mime_types.rb +5 -0
  66. data/test/dummy/config/initializers/respect.rb +9 -0
  67. data/test/dummy/config/initializers/secret_token.rb +7 -0
  68. data/test/dummy/config/initializers/session_store.rb +8 -0
  69. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  70. data/test/dummy/config/locales/en.yml +5 -0
  71. data/test/dummy/config/routes.rb +38 -0
  72. data/test/dummy/config.ru +4 -0
  73. data/test/dummy/db/development.sqlite3 +0 -0
  74. data/test/dummy/db/schema.rb +16 -0
  75. data/test/dummy/db/test.sqlite3 +0 -0
  76. data/test/dummy/lib/exts/Rgba.rb +11 -0
  77. data/test/dummy/lib/exts/circle.rb +11 -0
  78. data/test/dummy/lib/exts/point.rb +11 -0
  79. data/test/dummy/log/development.log +6 -0
  80. data/test/dummy/log/test.log +851 -0
  81. data/test/dummy/public/404.html +26 -0
  82. data/test/dummy/public/422.html +26 -0
  83. data/test/dummy/public/500.html +25 -0
  84. data/test/dummy/public/favicon.ico +0 -0
  85. data/test/dummy/script/rails +6 -0
  86. data/test/functional/automatic_validation_controller_test.rb +131 -0
  87. data/test/functional/caught_exception_controller_test.rb +50 -0
  88. data/test/functional/disabled_controller_test.rb +16 -0
  89. data/test/functional/manual_validation_controller_test.rb +24 -0
  90. data/test/functional/no_schema_controller_test.rb +12 -0
  91. data/test/functional/respect/rails/schemas_controller_test.rb +18 -0
  92. data/test/functional/skipped_automatic_validation_controller_test.rb +12 -0
  93. data/test/headers_can_dumped_in_json.sh +33 -0
  94. data/test/integration/navigation_test.rb +38 -0
  95. data/test/request_headers_validation_in_dev_mode.sh +33 -0
  96. data/test/test_helper.rb +17 -0
  97. data/test/unit/action_schema_test.rb +21 -0
  98. data/test/unit/application_info_test.rb +11 -0
  99. data/test/unit/controller_helper_test.rb +4 -0
  100. data/test/unit/engine_info_test.rb +11 -0
  101. data/test/unit/engine_test.rb +7 -0
  102. data/test/unit/info_test.rb +42 -0
  103. data/test/unit/request_def_test.rb +22 -0
  104. data/test/unit/request_helper_test.rb +67 -0
  105. data/test/unit/request_schema_test.rb +164 -0
  106. data/test/unit/response_def_test.rb +9 -0
  107. data/test/unit/response_helper_test.rb +73 -0
  108. data/test/unit/response_schema_set_test.rb +18 -0
  109. data/test/unit/response_schema_test.rb +147 -0
  110. metadata +334 -0
@@ -0,0 +1,36 @@
1
+ module Respect
2
+ module Rails
3
+ # Controller to get all the information relative to the
4
+ # REST API of this application.
5
+ class SchemasController < ActionController::Base
6
+ def_action_schema :index do |s|
7
+ s.request do |r|
8
+ r.path_parameters do |s|
9
+ s.string "format", in: %w{html json}
10
+ end
11
+ end
12
+ end
13
+
14
+ def index
15
+ respond_to do |format|
16
+ format.html # index.html.erb
17
+ end
18
+ end
19
+
20
+ def_action_schema :doc do |s|
21
+ s.request do |r|
22
+ r.path_parameters do |s|
23
+ s.string "format", in: %w{html json}
24
+ end
25
+ end
26
+ end
27
+
28
+ def doc
29
+ @info = Respect::Rails::Info.new
30
+ respond_to do |format|
31
+ format.html # doc.html.erb
32
+ end
33
+ end
34
+ end
35
+ end # module Rails
36
+ end # module Respect
@@ -0,0 +1,78 @@
1
+ module Respect
2
+ module Rails
3
+ module SchemasHelper
4
+
5
+ def highlight_json_schema(json_schema)
6
+ Respect::JSONSchemaHTMLFormatter.new(json_schema).dump.html_safe
7
+ end
8
+
9
+ # FIXME(Nicolas Despres): Test me.
10
+ def describe_option(name, value)
11
+ result = describe_option_internal(name, value)
12
+ result.html_safe if result
13
+ end
14
+
15
+ def toggler(text, &block)
16
+ @toggler_id ||= -1
17
+ @toggler_id += 1
18
+ toggler_key = "toggle_#@toggler_id"
19
+ content_tag :div do
20
+ result = content_tag(:div, class: "summary") do
21
+ content_tag :a, text, href: "#", onclick: "return toggle(#@toggler_id)", id: "#{toggler_key}_toggle"
22
+ end
23
+ result << content_tag(:div, capture(&block), id: toggler_key, style: "display:none")
24
+ end
25
+ end
26
+
27
+ # FIXME(Nicolas Despres): Make me more generic to all enumerable and test me.
28
+ def flat_each(hash, &block)
29
+ flat_each_rec([], hash, &block)
30
+ end
31
+
32
+ # FIXME(Nicolas Despres): Test me
33
+ def build_parameter_name(path)
34
+ path.first.to_s + path[1..-1].reduce(""){|r, x| r + "[#{x}]" }
35
+ end
36
+
37
+ private
38
+
39
+ def describe_option_internal(name, value)
40
+ case name
41
+ when :doc, :required
42
+ nil
43
+ when :default
44
+ if value.nil?
45
+ nil
46
+ else
47
+ "default to #{value.inspect}"
48
+ end
49
+ when :equal_to
50
+ "Must be equal to #{value.inspect}"
51
+ when :allow_nil
52
+ if value
53
+ "May be null"
54
+ else
55
+ nil
56
+ end
57
+ when :strict
58
+ if value
59
+ "Must contains exactly these parameters"
60
+ else
61
+ nil
62
+ end
63
+ else
64
+ "#{name}: #{value.inspect}"
65
+ end
66
+ end
67
+
68
+ def flat_each_rec(path, hash, &block)
69
+ hash.each do |k, v|
70
+ block.call(path + [k], v)
71
+ if v.is_a?(Respect::HashSchema)
72
+ flat_each_rec(path + [k], v, &block)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <%= content_tag :title, "#{Respect::Rails::Engine.doc_app_name} API" %>
5
+ <%= stylesheet_link_tag "respect/rails/schemas", :media => "all" %>
6
+ <%= javascript_include_tag "respect/rails/schemas" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,38 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Request validation error caught</title>
6
+ <style>
7
+ body { background-color: #fff; color: #333; }
8
+
9
+ body, p, ol, ul, td {
10
+ font-family: helvetica, verdana, arial, sans-serif;
11
+ font-size: 13px;
12
+ line-height: 18px;
13
+ }
14
+
15
+ pre {
16
+ background-color: #eee;
17
+ padding: 10px;
18
+ font-size: 11px;
19
+ white-space: pre-wrap;
20
+ }
21
+
22
+ a { color: #000; }
23
+ a:visited { color: #666; }
24
+ a:hover { color: #fff; background-color:#000; }
25
+ </style>
26
+ </head>
27
+ <body>
28
+ <h1>Request validation error in <%= "#{controller_name.camelize}Controller##{action_name}" %></h1>
29
+ <p>
30
+ Invalid <%= @error.part %> parameters:
31
+ <pre><%= @error.context.join("\n") %></pre>
32
+ </p>
33
+ <p>
34
+ Processed object:
35
+ <%= Respect::JSONSchemaHTMLFormatter.new(@error.object).dump.html_safe %>
36
+ </p>
37
+ </body>
38
+ </html>
@@ -0,0 +1,158 @@
1
+ <h1><%= @info.app.name %> API Documentation</h1>
2
+
3
+ <%= content_tag :p, @info.app.title %>
4
+ <%= content_tag :p, @info.app.description %>
5
+ <p>
6
+ This document describes the <%= @info.app.name %> API interface. It is designed for developers
7
+ who wants to interoperate with <%= @info.app.name %> in their own application.
8
+ </p>
9
+
10
+ <div class="toc">
11
+ <h2 class="title">Table of content</h2>
12
+
13
+ <% @info.toc.keys.sort.each do |controller_name| %>
14
+ <%= content_tag :h3, controller_name.gsub(%r{/}, ' ').titleize %>
15
+ <table>
16
+ <% @info.toc[controller_name].keys.sort.each do |action_name| %>
17
+ <% route = @info.toc[controller_name][action_name] %>
18
+ <tr>
19
+ <%= content_tag :td do %>
20
+ <%= link_to route.spec, doc_path(anchor: route.anchor) %>
21
+ <% end %>
22
+ <%= content_tag :td, route.schema.title, width: "60%" %>
23
+ </tr>
24
+ <% end %>
25
+ </table>
26
+ <% end %>
27
+ </div>
28
+
29
+ <hr>
30
+
31
+ <div class="route">
32
+ <%
33
+ @info.toc.keys.sort.each do |controller_name|
34
+ @info.toc[controller_name].keys.sort.each do |action_name|
35
+
36
+ route = @info.toc[controller_name][action_name]
37
+ action_schema = route.schema
38
+ %>
39
+ <h2 class="title">
40
+ <%= content_tag :a, route.spec, id: route.anchor %>
41
+ </h2>
42
+
43
+ <%= content_tag :p, action_schema.title %>
44
+ <%= content_tag :p, action_schema.description %>
45
+
46
+ <%
47
+ if action_schema.request
48
+ request_schema = action_schema.request
49
+ %>
50
+ <h3>Request</h3>
51
+ <% unless request_schema.headers.documented_properties.empty? %>
52
+ <h4>Headers</h4>
53
+
54
+ <table>
55
+ <% request_schema.headers.each do |name, schema| %>
56
+ <tr>
57
+ <td width="30%">
58
+ <strong><%= name %></strong>
59
+ <br>
60
+ <span class="constraint">
61
+ <%= schema.optional? ? "optional" : "required" %>
62
+ <%= schema.class.statement_name %>
63
+ </span>
64
+ </td>
65
+ <td>
66
+ <% if schema.title %>
67
+ <%= schema.title %>
68
+ <br>
69
+ <% end %>
70
+ <% if schema.description %>
71
+ <%= schema.description %>
72
+ <br>
73
+ <% end %>
74
+ <ul>
75
+ <%
76
+ schema.options.each do |name, value|
77
+ desc = describe_option(name, value)
78
+ if desc %>
79
+ <li><span class="constraint"><%= desc %></span></li>
80
+ <% end %>
81
+ <% end %>
82
+ </ul>
83
+ </td>
84
+ </tr>
85
+ <% end %>
86
+ </table>
87
+
88
+ <%= toggler "Show headers schema" do %>
89
+ <%= highlight_json_schema request_schema.headers.to_h %>
90
+ <% end %>
91
+ <% end %>
92
+
93
+ <%
94
+ [ :path, :query, :body ].each do |name|
95
+ params_schema = request_schema.send("#{name}_parameters")
96
+ unless params_schema.documented_properties.empty? %>
97
+ <h4><%= name.capitalize %> parameters</h4>
98
+
99
+ <table>
100
+ <% flat_each(params_schema) do |path, schema| %>
101
+ <tr>
102
+ <td width="30%">
103
+ <strong><%= build_parameter_name path %></strong>
104
+ <br>
105
+ <span class="constraint">
106
+ <%= schema.optional? ? "optional" : "required" %>
107
+ <%= schema.class.statement_name %>
108
+ </span>
109
+ </td>
110
+ <td>
111
+ <% if schema.title %>
112
+ <%= schema.title %>
113
+ <br>
114
+ <% end %>
115
+ <% if schema.description %>
116
+ <%= schema.description %>
117
+ <br>
118
+ <% end %>
119
+ <ul>
120
+ <%
121
+ schema.options.each do |name, value|
122
+ desc = describe_option(name, value)
123
+ if desc %>
124
+ <li><span class="constraint"><%= desc %></span></li>
125
+ <% end %>
126
+ <% end %>
127
+ </ul>
128
+ </td>
129
+ </tr>
130
+ <% end %>
131
+ </table>
132
+
133
+ <%= toggler "Show #{name} parameters schema" do %>
134
+ <%= highlight_json_schema params_schema.to_h %>
135
+ <% end %>
136
+ <% end %>
137
+ <% end %>
138
+ <% end %>
139
+
140
+ <% unless action_schema.responses.empty? %>
141
+ <% action_schema.responses.each do |status, response_schema| %>
142
+ <h3>Response <%= response_schema.http_status %> [ <%= response_schema.status %> ]</h3>
143
+ <%= content_tag :p, response_schema.title %>
144
+ <%= content_tag :p, response_schema.description %>
145
+ <% unless response_schema.headers.documented_properties.empty? %>
146
+ <h4>Headers</h4>
147
+ <%= highlight_json_schema response_schema.headers.to_h %>
148
+ <% end %>
149
+ <% if response_schema.body %>
150
+ <h4>Body</h4>
151
+ <%= highlight_json_schema response_schema.body.to_h %>
152
+ <% end %>
153
+ <% end %>
154
+ <% end %>
155
+
156
+ <% end %>
157
+ <% end %>
158
+ </div>
@@ -0,0 +1,4 @@
1
+ <h1>Welcome to Respect</h1>
2
+ <ul>
3
+ <li><%= link_to "Documentation", doc_path %></li>
4
+ </ul>
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ Respect::Rails::Engine.routes.draw do
2
+ root to: 'schemas#index', via: :get, format: 'html'
3
+ match '/doc' => 'schemas#doc', via: :get, as: 'doc'
4
+ end
@@ -0,0 +1,37 @@
1
+ module Respect
2
+ module Rails
3
+ class ActionDef
4
+
5
+ class << self
6
+ def eval(*args, &block)
7
+ new(*args).eval(&block)
8
+ end
9
+ end
10
+
11
+ def initialize(*args)
12
+ @action_schema = ActionSchema.new(*args)
13
+ end
14
+
15
+ def eval(&block)
16
+ block.call(self)
17
+ @action_schema
18
+ end
19
+
20
+ def request(&block)
21
+ @action_schema.request = RequestSchema.define(@action_schema.controller_name,
22
+ @action_schema.action_name, &block)
23
+ end
24
+
25
+ def response_for(&block)
26
+ block.call(@action_schema.responses)
27
+ @action_schema.responses
28
+ end
29
+
30
+ # Set the documentation to +text+.
31
+ def documentation(text)
32
+ @action_schema.documentation = text
33
+ end
34
+
35
+ end # class ActionDef
36
+ end # module Rails
37
+ end # module Respect
@@ -0,0 +1,41 @@
1
+ module Respect
2
+ module Rails
3
+ class ActionSchema
4
+ include Respect::DocHelper
5
+
6
+ class << self
7
+ def from_controller(controller_name, action_name)
8
+ klass = "#{controller_name}_controller".classify.safe_constantize
9
+ @schema = klass.new.action_schema(action_name) if klass
10
+ end
11
+
12
+ def define(*args, &block)
13
+ ActionDef.eval(*args, &block)
14
+ end
15
+ end
16
+
17
+ def initialize(controller, action_name)
18
+ @controller = controller
19
+ @action_name = action_name
20
+ @responses = ResponseSchemaSet.new(controller_name, @action_name)
21
+ end
22
+
23
+ attr_reader :controller, :action_name
24
+
25
+ def controller_name
26
+ @controller.controller_name
27
+ end
28
+
29
+ attr_accessor :request
30
+
31
+ attr_reader :responses
32
+
33
+ # Whether there is at least a request schema or one response schema for this action.
34
+ def has_schema?
35
+ request || !responses.empty? || documentation
36
+ end
37
+
38
+ attr_accessor :documentation
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ module Respect
2
+ module Rails
3
+ class ApplicationInfo < EngineInfo
4
+ include Respect::DocHelper
5
+
6
+ def initialize(app_class = ::Rails.application.class)
7
+ super(app_class)
8
+ unless app_class < ::Rails::Application
9
+ raise "'#{app_class}' must be an ancestor of ::Rails::Application."
10
+ end
11
+ @app_class = app_class
12
+ end
13
+
14
+ attr_reader :app_class
15
+
16
+ def name
17
+ Engine.doc_app_name
18
+ end
19
+
20
+ def documentation
21
+ Respect::Rails::Engine.app_documentation
22
+ end
23
+
24
+ end # class ApplicationInfo
25
+ end # module Rails
26
+ end # module Respect
@@ -0,0 +1,107 @@
1
+ module Respect
2
+ module Rails
3
+ module ControllerHelper
4
+ extend ActiveSupport::Concern
5
+
6
+ included do |base|
7
+ around_filter :load_schemas!
8
+ end
9
+
10
+ module ClassMethods
11
+ # Install a handler for {Respect::Rails::RequestValidationError}. It provides a more specific
12
+ # error report than the default exception handler in development. For instance you get the
13
+ # context of where the error happened in the JSON document.
14
+ #
15
+ # Example:
16
+ # # In your ApplicationController class.
17
+ # rescue_from_request_valiation_error if Rails.env.development?
18
+ def rescue_from_request_validation_error
19
+ rescue_from Respect::Rails::RequestValidationError do |exception|
20
+ respond_to do |format|
21
+ format.html do
22
+ @error = exception
23
+ render template: "respect/rails/request_validation_exception", layout: false, status: :internal_server_error
24
+ end
25
+ format.json do
26
+ render json: exception.to_json, status: :internal_server_error
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ # FIXME(Nicolas Despres): Document me.
33
+ def def_action_schema(action_name, &block)
34
+ define_method("#{action_name}_schema") do
35
+ Respect::Rails::ActionSchema.define(self, action_name, &block)
36
+ end
37
+ end
38
+ end
39
+
40
+ # FIXME(Nicolas Despres): Test me!!!
41
+ def action_schema(action = nil)
42
+ action ||= self.action_name
43
+ method_name = "#{action}_schema"
44
+ if self.respond_to?(method_name)
45
+ send(method_name)
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ # This "around" filter calls +validation_request_schema+ and +validation_response_schema+
52
+ # respectively before and after the controller's action.
53
+ def validate_schemas!
54
+ validate_request_schema!
55
+ yield
56
+ validate_response_schema! if Respect::Rails::Engine.validate_response
57
+ end
58
+
59
+ # This "before" filter validates the request.
60
+ def validate_request_schema!
61
+ request.validate_schema
62
+ end
63
+
64
+ # This "after" filter validates the response with the schema associated to the
65
+ # response status if one is found.
66
+ def validate_response_schema!
67
+ load_response_schema!
68
+ response.validate_schema
69
+ end
70
+
71
+ # This "around" filter calls +load_request_schema+ and +load_response_schema+
72
+ # respectively before and after the controller's action. It is useful
73
+ # if you want to do the validation yourself. It only load the action schema
74
+ # and attach the request schema to the request object and the response schema to
75
+ # the response object.
76
+ def load_schemas!
77
+ load_request_schema!
78
+ yield
79
+ if Respect::Rails::Engine.validate_response
80
+ load_response_schema!
81
+ end
82
+ end
83
+
84
+ # This "before" filter load and attach the action schema to the request object.
85
+ # It is safe to call this method several times.
86
+ def load_request_schema!
87
+ request.send(:action_schema=, action_schema) unless request.has_schema?
88
+ end
89
+
90
+ # This "after" filter attach the response schema to the response object.
91
+ # You can safely call this filter multiple times (i.e. from other after
92
+ # filters callbacks).
93
+ def load_response_schema!
94
+ response.send(:schema=, request.response_schema(response.status)) unless response.has_schema?
95
+ end
96
+
97
+ # Before filter which sanitize all request parameters: +params+,
98
+ # +query_parameters+, +path_parameters+ and +request_parameters+.
99
+ # The request is validated first if it has not been yet.
100
+ def sanitize_params!
101
+ request.sanitize_params!
102
+ end
103
+ end # module ControllerHelper
104
+ end # module Rails
105
+ end # module Respect
106
+
107
+ ActionController::Base.send :include, Respect::Rails::ControllerHelper
@@ -0,0 +1,63 @@
1
+ require 'respect'
2
+
3
+ require 'respect/rails/headers_helper'
4
+ require 'respect/rails/request_helper'
5
+ require 'respect/rails/response_helper'
6
+ require 'respect/rails/controller_helper'
7
+
8
+ module Respect
9
+ module Rails
10
+ class Engine < ::Rails::Engine
11
+ isolate_namespace Respect::Rails
12
+ engine_name 'respect'
13
+
14
+ # Whether responses are validated by the +validate_schemas+ around filter.
15
+ # By default this is +true+ in development and test environment and +false+ otherwise.
16
+ mattr_accessor :validate_response
17
+ self.validate_response = (::Rails.env.development? || ::Rails.env.test?)
18
+
19
+ # Whether response validation error are caught. The exception will be rendered in JSON
20
+ # and the HTTP status will be set to 500.
21
+ # By default this is +true+ in development mode only.
22
+ mattr_accessor :catch_response_validation_error
23
+ self.catch_response_validation_error = ::Rails.env.development?
24
+
25
+ # Whether to validate request headers.
26
+ # This option is available because Rails 3 does not support headers well in test mode.
27
+ # It is +false+ by default in test mode to let you do non-headers related functional
28
+ # test anyway.
29
+ # See: https://github.com/rails/rails/issues/6513
30
+ mattr_accessor :disable_request_headers_validation
31
+ self.disable_request_headers_validation = ::Rails.env.test?
32
+
33
+ # Set the application name use in the documentation. By default it is the same
34
+ # as your application class.
35
+ mattr_writer :doc_app_name
36
+ def self.doc_app_name
37
+ @@doc_app_name ||= ::Rails.application.class.parent_name
38
+ end
39
+
40
+ # Default way to setup Respect for Rails.
41
+ def self.setup(&block)
42
+ block.call(self)
43
+ end
44
+
45
+ # Set the documentation of your application. The title would be the first line
46
+ # if followed by an empty line and the description would be the rest.
47
+ # If +text+ is +nil+ the current documentation is returned.
48
+ def self.app_documentation(text = nil)
49
+ if text
50
+ @@app_documentation = text
51
+ else
52
+ @@app_documentation
53
+ end
54
+ end
55
+
56
+ # Include all +helper_modules+ in the DSL definition classes, so that you can use its
57
+ # methods for defining schema.
58
+ def self.helpers(*helper_modules)
59
+ helper_modules.each{|m| Respect.extend_dsl_with(m) }
60
+ end
61
+ end # class Engine
62
+ end # module Rails
63
+ end # module Respect
@@ -0,0 +1,27 @@
1
+ module Respect
2
+ module Rails
3
+ class EngineInfo
4
+ include Comparable
5
+
6
+ def initialize(engine_class)
7
+ unless engine_class < ::Rails::Engine
8
+ raise "'#{engine_class}' must be an ancestor of ::Rails::Engine."
9
+ end
10
+ @engine_class = engine_class
11
+ end
12
+
13
+ attr_reader :engine_class
14
+
15
+ def name
16
+ @engine_class.engine_name.underscore
17
+ end
18
+
19
+ attr_accessor :routes
20
+
21
+ def <=>(other)
22
+ self.name <=> other.name
23
+ end
24
+
25
+ end # class EngineInfo
26
+ end # module Rails
27
+ end # module Respect
@@ -0,0 +1,11 @@
1
+ module Respect
2
+ module Rails
3
+ module HeadersHelper
4
+ def has_key?(header_name)
5
+ super || super(env_name(header_name))
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ ActionDispatch::Http::Headers.send :include, Respect::Rails::HeadersHelper
@@ -0,0 +1,31 @@
1
+ module Respect
2
+ module Rails
3
+ module HeadersSimplifier
4
+ # Copy the given +headers+ hash table but get rid of the
5
+ # _complex_ type at the same time.
6
+ #
7
+ # This is useful if you plan to serialize +headers+ and want to
8
+ # get rid of complex type which may raise errors when serializing.
9
+ def simplify_headers(headers)
10
+ case headers
11
+ when String, Numeric, TrueClass, FalseClass, Symbol, Mime::Type
12
+ headers
13
+ when Array
14
+ result = []
15
+ headers.each do |x|
16
+ v = simplify_headers(x)
17
+ result << v if v
18
+ end
19
+ result
20
+ when Hash
21
+ result = {}
22
+ headers.each do |k, v|
23
+ new_v = simplify_headers(v)
24
+ result[k] = new_v if new_v
25
+ end
26
+ result
27
+ end
28
+ end
29
+ end # module HeadersSimplifier
30
+ end # module Rails
31
+ end # module Respect