openapi-rails 0.3.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 (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +99 -0
  5. data/LICENSE.md +21 -0
  6. data/README.md +61 -0
  7. data/Rakefile +1 -0
  8. data/app/assets/fonts/openapi/DroidSans-Bold.ttf +0 -0
  9. data/app/assets/fonts/openapi/DroidSans.ttf +0 -0
  10. data/app/assets/images/openapi/collapse.gif +0 -0
  11. data/app/assets/images/openapi/expand.gif +0 -0
  12. data/app/assets/images/openapi/explorer_icons.png +0 -0
  13. data/app/assets/images/openapi/favicon-16x16.png +0 -0
  14. data/app/assets/images/openapi/favicon-32x32.png +0 -0
  15. data/app/assets/images/openapi/favicon.ico +0 -0
  16. data/app/assets/images/openapi/logo_small.png +0 -0
  17. data/app/assets/images/openapi/pet_store_api.png +0 -0
  18. data/app/assets/images/openapi/throbber.gif +0 -0
  19. data/app/assets/images/openapi/wordnik_api.png +0 -0
  20. data/app/assets/javascripts/openapi/application.coffee +58 -0
  21. data/app/assets/javascripts/openapi/lib/backbone-min.js +15 -0
  22. data/app/assets/javascripts/openapi/lib/es5-shim.js +2065 -0
  23. data/app/assets/javascripts/openapi/lib/handlebars-4.0.5.js +4608 -0
  24. data/app/assets/javascripts/openapi/lib/highlight.9.1.0.pack.js +2 -0
  25. data/app/assets/javascripts/openapi/lib/highlight.9.1.0.pack_extended.js +34 -0
  26. data/app/assets/javascripts/openapi/lib/jquery-1.8.0.min.js +2 -0
  27. data/app/assets/javascripts/openapi/lib/jquery.ba-bbq.min.js +18 -0
  28. data/app/assets/javascripts/openapi/lib/jquery.slideto.min.js +1 -0
  29. data/app/assets/javascripts/openapi/lib/jquery.wiggle.min.js +8 -0
  30. data/app/assets/javascripts/openapi/lib/js-yaml.min.js +3 -0
  31. data/app/assets/javascripts/openapi/lib/jsoneditor.min.js +11 -0
  32. data/app/assets/javascripts/openapi/lib/lodash.min.js +102 -0
  33. data/app/assets/javascripts/openapi/lib/marked.js +1272 -0
  34. data/app/assets/javascripts/openapi/lib/object-assign-pollyfill.js +23 -0
  35. data/app/assets/javascripts/openapi/lib/swagger-oauth.js +347 -0
  36. data/app/assets/javascripts/openapi/swagger-ui.js +24758 -0
  37. data/app/assets/stylesheets/openapi/application.scss +4 -0
  38. data/app/assets/stylesheets/openapi/print.scss +1367 -0
  39. data/app/assets/stylesheets/openapi/reset.scss +125 -0
  40. data/app/assets/stylesheets/openapi/screen.scss +1497 -0
  41. data/app/assets/stylesheets/openapi/typography.scss +14 -0
  42. data/app/controllers/openapi_controller.rb +24 -0
  43. data/app/views/openapi/index.html.erb +56 -0
  44. data/lib/generators/openapi/config_generator.rb +20 -0
  45. data/lib/generators/openapi/templates/base_controller.rb +6 -0
  46. data/lib/generators/openapi/templates/openapi.rb +21 -0
  47. data/lib/openapi-rails.rb +1 -0
  48. data/lib/openapi.rb +26 -0
  49. data/lib/openapi/configuration.rb +17 -0
  50. data/lib/openapi/engine.rb +32 -0
  51. data/lib/openapi/mongoid/crud_actions.rb +235 -0
  52. data/lib/openapi/mongoid/spec_builder.rb +451 -0
  53. data/lib/openapi/routes_parser.rb +50 -0
  54. data/lib/openapi/version.rb +3 -0
  55. data/lib/rails/routes.rb +20 -0
  56. data/lib/renderers/csv.rb +36 -0
  57. data/lib/swagger/blocks/items_node.rb +7 -0
  58. data/lib/swagger/blocks/property_node.rb +7 -0
  59. data/lib/swagger/blocks/schema_builder.rb +89 -0
  60. data/lib/swagger/blocks/schema_node.rb +7 -0
  61. data/openapi-rails.gemspec +35 -0
  62. metadata +204 -0
@@ -0,0 +1,14 @@
1
+ /* Google Font's Droid Sans */
2
+ @font-face {
3
+ font-family: 'Droid Sans';
4
+ font-style: normal;
5
+ font-weight: 400;
6
+ src: local('Droid Sans'), local('DroidSans'), font-url('openapi/DroidSans.ttf'), format('truetype');
7
+ }
8
+ /* Google Font's Droid Sans Bold */
9
+ @font-face {
10
+ font-family: 'Droid Sans';
11
+ font-style: normal;
12
+ font-weight: 700;
13
+ src: local('Droid Sans Bold'), local('DroidSans-Bold'), font-url('openapi/DroidSans-Bold.ttf'), format('truetype');
14
+ }
@@ -0,0 +1,24 @@
1
+ class OpenapiController < ActionController::Base
2
+ respond_to :json
3
+
4
+ def index
5
+ @specs = Openapi.apis.map do |name, config|
6
+ title = config[:title]
7
+ spec_path = "#{config[:base_path]}/spec"
8
+ [title, spec_path]
9
+ end
10
+
11
+ @default_specification_path = @specs.first ? @specs.first[1] : ''
12
+
13
+ render 'index', layout: false
14
+ end
15
+
16
+ def spec
17
+ name = params[:name] || :default
18
+ config = Openapi.apis[name]
19
+ controllers = config[:controllers]
20
+ json_schema = Swagger::Blocks.build_root_json(controllers)
21
+
22
+ render json: json_schema
23
+ end
24
+ end
@@ -0,0 +1,56 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset='UTF-8'>
5
+ <title>OpenAPI</title>
6
+
7
+ <%= favicon_link_tag 'openapi/favicon-32x32.png', rel: 'icon',
8
+ type: 'image/png',
9
+ sizes: '32x32' %>
10
+
11
+ <%= favicon_link_tag 'openapi/favicon-16x16.png', rel: 'icon',
12
+ type: 'image/png',
13
+ sizes: '16x16' %>
14
+
15
+ <%= stylesheet_link_tag 'openapi/application' %>
16
+ <%= stylesheet_link_tag 'openapi/reset', media: 'print' %>
17
+ <%= stylesheet_link_tag 'openapi/print', media: 'print' %>
18
+ <%= javascript_include_tag 'openapi/application' %>
19
+
20
+ <%= csrf_meta_tags %>
21
+ </head>
22
+
23
+ <body class='swagger-section'>
24
+ <div id='header'>
25
+ <div class='swagger-ui-wrap'>
26
+ <%= link_to openapi_path, id: 'logo' do %>
27
+ <%= image_tag 'openapi/logo_small.png', alt: 'Swagger',
28
+ class: 'logo__img',
29
+ height: 30,
30
+ width: 30 %>
31
+ <span class='logo__title'>OpenAPI</span></a>
32
+ <% end %>
33
+
34
+ <form id='api_selector'>
35
+ <input id='input_baseUrl'
36
+ name='baseUrl'
37
+ type='hidden'
38
+ value='<%= @default_specification_path %>' />
39
+
40
+ <% if @specs.size > 1 %>
41
+ <div class='input'>
42
+ <select id='input_spec'>
43
+ <% @specs.each do |s| %>
44
+ <option value='<%= s[1] %>'><%= s[0]%></option>
45
+ <% end %>
46
+ </select>
47
+ </div>
48
+ <% end %>
49
+ </form>
50
+ </div>
51
+ </div>
52
+
53
+ <div id='message-bar' class='swagger-ui-wrap' data-sw-translate>&nbsp;</div>
54
+ <div id='swagger-ui-container' class='swagger-ui-wrap'></div>
55
+ </body>
56
+ </html>
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ module Openapi
3
+ class ConfigGenerator < Rails::Generators::Base
4
+ desc 'Creates OpenAPI initialization file and Api::BaseController'
5
+
6
+ def self.source_root
7
+ File.expand_path('../templates', __FILE__)
8
+ end
9
+
10
+ def create_config_file
11
+ dest = File.join('config/initializers', 'openapi.rb')
12
+ template 'openapi.rb', dest
13
+ end
14
+
15
+ def create_base_controller_file
16
+ dest = File.join('app/controllers/api', 'base_controller.rb')
17
+ template 'base_controller.rb', dest
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ module Api
2
+ class BaseController < ActionController::Base
3
+ include Openapi::Mongoid::CrudActions
4
+ include Openapi::Mongoid::SpecBuilder
5
+ end
6
+ end
@@ -0,0 +1,21 @@
1
+ Openapi.configure do |config|
2
+ config.apis = {
3
+ default: {
4
+ title: 'Default',
5
+ description: '',
6
+ version: '1.0',
7
+ base_path: '/api',
8
+ controllers: []
9
+ }
10
+ }
11
+ end
12
+
13
+ module BSON
14
+ class ObjectId
15
+ def as_json(*args)
16
+ to_s
17
+ end
18
+
19
+ alias :to_json :as_json
20
+ end
21
+ end
@@ -0,0 +1 @@
1
+ require 'openapi'
data/lib/openapi.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'bson'
2
+ require 'yajl'
3
+ require 'yajl/json_gem'
4
+ require 'swagger/blocks'
5
+ require 'rails/routes'
6
+
7
+ require 'has_scope'
8
+ require 'responders'
9
+ require 'renderers/csv'
10
+ require 'kaminari'
11
+ require 'openapi/mongoid/crud_actions'
12
+
13
+ require 'swagger/blocks/schema_builder'
14
+ require 'swagger/blocks/schema_node'
15
+ require 'swagger/blocks/property_node'
16
+ require 'swagger/blocks/items_node'
17
+ require 'openapi/mongoid/spec_builder'
18
+
19
+ require 'openapi/configuration'
20
+ require 'openapi/routes_parser'
21
+ require 'openapi/engine'
22
+ require 'openapi/version'
23
+
24
+ module Openapi
25
+ extend Configuration
26
+ end
@@ -0,0 +1,17 @@
1
+ module Openapi
2
+ module Configuration
3
+ attr_accessor :apis
4
+
5
+ def configure
6
+ yield self
7
+ end
8
+
9
+ def self.extended(base)
10
+ base.set_default_configuration
11
+ end
12
+
13
+ def set_default_configuration
14
+ self.apis = {}
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ module Openapi
2
+ class Engine < ::Rails::Engine
3
+ initializer 'openapi.assets.precompile', group: :all do |app|
4
+ app.config.assets.precompile += %w(openapi/print.css
5
+ openapi/reset.css
6
+ openapi/logo_small.png
7
+ openapi/favicon-32x32.png
8
+ openapi/favicon-16x16.png)
9
+ end
10
+ end
11
+
12
+ class Railtie < Rails::Railtie
13
+ initializer 'openapi.builders', after: :load_config_initializers do
14
+ Rails.application.reload_routes!
15
+
16
+ Openapi.apis.each do |name, config|
17
+ base_path = config[:base_path] || '/api'
18
+
19
+ config[:controllers].each do |controller|
20
+ controller.build_openapi_specification(base_path: base_path)
21
+ end
22
+
23
+ name = name.to_s.titleize.remove(' ')
24
+ root_klass_name = "#{name}SwaggerRootController"
25
+ klass = Object.const_set root_klass_name, Class.new(SwaggerRoot)
26
+ klass.build_specification(config, config[:controllers])
27
+
28
+ config[:controllers].push klass
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,235 @@
1
+ module Openapi
2
+ module Mongoid
3
+ module CrudActions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ respond_to :json
8
+ respond_to :csv, only: %w(index)
9
+
10
+ class_attribute :resource_class
11
+ class_attribute :per_page
12
+
13
+ ## Actions
14
+
15
+ def index
16
+ @chain = default_scope
17
+
18
+ apply_scopes_to_chain!
19
+ search_filter_chain!
20
+ paginate_chain!
21
+ set_index_headers!
22
+
23
+ respond_to do |format|
24
+ format.json { render json: @chain.as_json(json_config) }
25
+ format.csv { render csv: @chain }
26
+ end
27
+ end
28
+
29
+ def show
30
+ @object = find_object
31
+ set_object_version!
32
+ render json: @object.as_json(json_config)
33
+ end
34
+
35
+ def create
36
+ @object = build_object
37
+
38
+ if @object.save
39
+ render json: @object.as_json(json_config), status: :created
40
+
41
+ else
42
+ log_errors @object.errors
43
+ render json: @object.errors, status: :unprocessable_entity
44
+
45
+ end
46
+ end
47
+
48
+ def update
49
+ @object = find_object
50
+ if @object.update_attributes(resource_params)
51
+ render json: @object.as_json(json_config)
52
+
53
+ else
54
+ log_errors @object.errors
55
+ render json: @object.errors, status: :unprocessable_entity
56
+
57
+ end
58
+ end
59
+
60
+ def destroy
61
+ @object = find_object
62
+
63
+ if @object.destroy
64
+ render nothing: true, status: :no_content
65
+
66
+ else
67
+ log_errors @object.errors
68
+ render json: @object.errors, status: :unprocessable_entity
69
+
70
+ end
71
+ end
72
+
73
+ def response_config
74
+ config = {}
75
+ fields = params[:fields]
76
+ methods = params[:methods]
77
+
78
+ if fields
79
+ only_fields = fields.split(',').select do |field_name|
80
+ resource_class.fields.has_key?(field_name)
81
+ end
82
+ config[:only] = only_fields unless only_fields.empty?
83
+ end
84
+
85
+ if methods
86
+ include_methods = methods.split(',').select do |method_name|
87
+ method = method_name.to_sym
88
+ resource_class.instance_methods(false).include?(method)
89
+ end
90
+ config[:methods] = include_methods unless include_methods.empty?
91
+ end
92
+
93
+ config
94
+ end
95
+ alias csv_config response_config
96
+ alias json_config response_config
97
+
98
+ ## Helpers
99
+
100
+ def log_errors(errors)
101
+ if Rails.env.development?
102
+ logger.info "Errors:\n #{errors.to_h}"
103
+ end
104
+ end
105
+
106
+ def resource_class
107
+ @resource_class ||= self.class.resource_class
108
+ @resource_class ||= self.class.
109
+ to_s.
110
+ split('::').
111
+ last.
112
+ sub(/Controller$/, '').
113
+ singularize.
114
+ constantize
115
+ end
116
+
117
+ def default_scope
118
+ resource_class
119
+ end
120
+
121
+ def find_object
122
+ resource_class.find(params[:id])
123
+ end
124
+
125
+ def build_object
126
+ resource_class.new(resource_params)
127
+ end
128
+
129
+ def support_version?
130
+ @object.respond_to?(:undo, true)
131
+ end
132
+
133
+ def set_object_version!
134
+ version = params[:version]
135
+ if version && support_version? && version.to_i != @object.version
136
+ @object.undo(nil, from: version.to_i + 1, to: @object.version)
137
+ @object.version = version
138
+ end
139
+ end
140
+
141
+ def apply_scopes_to_chain!
142
+ @chain = apply_scopes(@chain)
143
+ end
144
+
145
+ def support_search?
146
+ @chain.respond_to?(:search, true)
147
+ end
148
+
149
+ def search_filter_chain!
150
+ query = params[:search]
151
+ if query && support_search?
152
+ normalized_query = query.to_s.downcase
153
+ @chain = @chain.search(normalized_query, match: :all)
154
+ end
155
+ end
156
+
157
+ def page
158
+ @page ||= params[:page]
159
+ end
160
+
161
+ def per_page
162
+ @per_page ||= (params[:perPage] || self.class.per_page || 50)
163
+ end
164
+
165
+ def paginate_chain!
166
+ @chain = begin
167
+ if page
168
+ @chain.page(page).per(per_page)
169
+ else
170
+ @chain.all
171
+ end
172
+ end
173
+ end
174
+
175
+ def set_index_headers!
176
+ total_objects = page ? @chain.total_count : @chain.size
177
+ response.headers['X-Total-Count'] = total_objects
178
+
179
+ if page and !@chain.last_page?
180
+ url = request.url
181
+ url.gsub!("page=#{page}", "page=#{@chain.next_page}")
182
+ next_page = "<#{url}>; rel=\"next\""
183
+ response.headers['Link'] = next_page
184
+ end
185
+ end
186
+
187
+ def resource_params
188
+ permitted_params
189
+ end
190
+
191
+ # NOTE: here we permit all parameters for ease of development,
192
+ # before release this method should be overriden to allow only
193
+ # permitted parameters.
194
+ def permitted_params
195
+ logger.warn "#{self}: please override `permitted_params` method."
196
+ params.require(resource_request_name).permit!
197
+ end
198
+
199
+ def resource_request_name
200
+ resource_class.
201
+ to_s.
202
+ underscore.
203
+ gsub('/', '_').
204
+ gsub('::', '_')
205
+ end
206
+ end
207
+
208
+ class_methods do
209
+ def index_json_config(hash)
210
+ self.index_json_config = hash
211
+ end
212
+
213
+ def create_json_config(hash)
214
+ self.create_json_config = hash
215
+ end
216
+
217
+ def show_json_config(hash)
218
+ self.show_json_config = hash
219
+ end
220
+
221
+ def update_json_config(hash)
222
+ self.update_json_config = hash
223
+ end
224
+
225
+ def resource_class(name)
226
+ self.resource_class = name
227
+ end
228
+
229
+ def per_page(number)
230
+ self.per_page = number
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end