mongoid-api-base 0.1.5 → 0.1.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e236b8693fb490d3c2475d1b58cb0405cde34d41
4
- data.tar.gz: deb977f256953b5fc3ef07526face05d56cfdff7
3
+ metadata.gz: 1e92a91674850278d42ca43d2c4dec1425072229
4
+ data.tar.gz: 44814b2ad35b90e4eba9e709f23550c8906be74c
5
5
  SHA512:
6
- metadata.gz: 93adb1043fc457cd86787928c7475b47732ee86c6a2ad5f197a5575c06016a61889bdb86bcd76eb522e0298e4ca8611f08c16a2000dff5c695dd169838a8a8b6
7
- data.tar.gz: 1b9f5206aeb5e9702f50954a29917743d6dffdf1562a6a8cea8cb4be1b0a0fee890113798661ead3cceead0adaa5b871fa1ed7091beda26e924d3bce8cfa8c64
6
+ metadata.gz: 7abc8f9633476d5c8cc23e3fa937ddd5c14bdf48fd273599a5aaeba15fafaa45266bf99da3f0f09d3fa6fab072825798d1bd0dc0c461a1e1ad9eb6708f1a2d8e
7
+ data.tar.gz: e76fff77fbad9db30d6fd63e92eab0c91d637dc39d672d1016ce139b3d32e48d93131589e75b97ec2e8882a9793466c0fb900873b786528367a1d6be8b8193fe
@@ -1,9 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mongoid-api-base (0.1.5)
4
+ mongoid-api-base (0.1.6)
5
5
  kaminari
6
6
  mongoid (~> 5.0)
7
+ swagger-blocks
7
8
 
8
9
  GEM
9
10
  remote: http://rubygems.org/
@@ -63,6 +64,7 @@ GEM
63
64
  rails-deprecated_sanitizer (>= 1.0.1)
64
65
  rails-html-sanitizer (1.0.3)
65
66
  loofah (~> 2.0)
67
+ swagger-blocks (1.3.2)
66
68
  thread_safe (0.3.5)
67
69
  tzinfo (1.2.2)
68
70
  thread_safe (~> 0.1)
@@ -1,5 +1,79 @@
1
- require "csv"
2
- require "action_controller/metal/renderers"
3
- require "renderers/csv"
4
- require "mongoid-api-base/version"
5
- require "mongoid-api-base/concern"
1
+ # =============================================================================
2
+ # MongoidApiBase
3
+ # Rails concern to implement API controllers for Mongoid models.
4
+ # -----------------------------------------------------------------------------
5
+ # Usage Example:
6
+ #
7
+ # include MongoidApiBase
8
+ #
9
+ # defaults resource_class: Journal::JournalPost,
10
+ # per_page: 30
11
+ #
12
+ # has_scope :by_category
13
+ # has_scope :hidden, type: :boolean
14
+ # has_scope :not_hidden, type: :boolean
15
+ #
16
+ # json_config methods: %w(hex slug sorted_categories opengraph_image_url meta_title meta_description),
17
+ # index: {
18
+ # except: %w(body_markdown body_html),
19
+ # methods: %w(hex slug)
20
+ # }
21
+ # -----------------------------------------------------------------------------
22
+ # Some more ideas for future improvements can be pulled from here:
23
+ # - https://github.com/jamesgolick/resource_controller
24
+ # =============================================================================
25
+
26
+ require 'kaminari'
27
+ require 'csv'
28
+ require 'action_controller/metal/renderers'
29
+ require 'renderers/csv'
30
+ require 'swagger/blocks'
31
+ require 'swagger/generator'
32
+ require 'mongoid-api-base/actions'
33
+ require 'mongoid-api-base/base_helpers'
34
+ require 'mongoid-api-base/version'
35
+
36
+ module MongoidApiBase
37
+ extend ActiveSupport::Concern
38
+ included do
39
+ respond_to :json
40
+ respond_to :csv, only: %w(index)
41
+
42
+ class_attribute :resource_class
43
+ class_attribute :per_page
44
+ class_attribute :csv_options
45
+ class_attribute :json_options
46
+
47
+ JSON_DEFAULT_ATTRIBUTES = [ :created_at,
48
+ :updated_at,
49
+ :slug,
50
+ :_position,
51
+ :_list_item_title,
52
+ :_list_item_subtitle,
53
+ :_list_item_thumbnail,
54
+ :_document_versions ].freeze
55
+
56
+ include Actions
57
+ include BaseHelpers
58
+ end
59
+
60
+ class_methods do
61
+ def defaults(options)
62
+ if options.key?(:resource_class)
63
+ self.resource_class = options[:resource_class]
64
+ end
65
+
66
+ if options.key?(:per_page)
67
+ self.per_page = options[:per_page]
68
+ end
69
+ end
70
+
71
+ def csv_config(options={})
72
+ self.csv_options = options
73
+ end
74
+
75
+ def json_config(options)
76
+ self.json_options = options
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,54 @@
1
+ # Holds all default actions for MongoidApiBase.
2
+ module MongoidApiBase
3
+ module Actions
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ def index
7
+ @chain = resource_class
8
+
9
+ apply_scopes_to_chain!
10
+ search_filter_chain!
11
+ paginate_chain!
12
+ set_total_count_header!
13
+
14
+ respond_to do |format|
15
+ format.json { render json: @chain.as_json(json_config(:index)) }
16
+ format.csv { render csv: @chain }
17
+ end
18
+ end
19
+
20
+ def show
21
+ object = find_object
22
+ object = get_object_version(object)
23
+ render json: object.as_json(json_config(:show))
24
+ end
25
+
26
+ def create
27
+ object = build_object
28
+ if object.save
29
+ render json: object.as_json(json_config(:create))
30
+ else
31
+ render json: object.errors, status: :unprocessable_entity
32
+ end
33
+ end
34
+
35
+ def update
36
+ object = find_object
37
+ if object.update_attributes(resource_params)
38
+ render json: object.as_json(json_config(:update))
39
+ else
40
+ render json: object.errors, status: :unprocessable_entity
41
+ end
42
+ end
43
+
44
+ def destroy
45
+ object = find_object
46
+ if object.destroy
47
+ render nothing: true, status: 204
48
+ else
49
+ render json: object.errors, status: :unprocessable_entity
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,115 @@
1
+ # Base helpers for MongoidApiBase work. Some methods here can be overwritten and
2
+ # you will need to do that to customize your controllers.
3
+ module MongoidApiBase
4
+ module BaseHelpers
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ def find_object
8
+ resource_class.find(params[:id])
9
+ end
10
+
11
+ def get_object_version(object)
12
+ version = params[:version]
13
+ if object.respond_to?(:undo, true)
14
+ if version && version.to_i != object.version
15
+ object.undo(nil, from: version.to_i + 1, to: object.version)
16
+ object.version = version
17
+ end
18
+ end
19
+ object
20
+ end
21
+
22
+ def build_object
23
+ resource_class.new(resource_params)
24
+ end
25
+
26
+ def apply_scopes_to_chain!
27
+ if respond_to?(:apply_scopes, true)
28
+ @chain = apply_scopes(@chain)
29
+ end
30
+ end
31
+
32
+ def search_filter_chain!
33
+ query = params[:search]
34
+ if query
35
+ normalized_query = query.to_s.downcase
36
+ @chain = @chain.search(normalized_query, match: :all)
37
+ end
38
+ end
39
+
40
+ def page
41
+ @page ||= params[:page] || false
42
+ end
43
+
44
+ def per_page
45
+ @per_page ||= params[:perPage] || self.class.per_page || 20
46
+ end
47
+
48
+ def paginate_chain!
49
+ @chain = begin
50
+ if page
51
+ @chain.page(page).per(per_page)
52
+ else
53
+ @chain.all
54
+ end
55
+ end
56
+ end
57
+
58
+ def set_total_count_header!
59
+ if page
60
+ response.headers['X-Total-Count'] = @chain.total_count
61
+ else
62
+ response.headers['X-Total-Count'] = @chain.size
63
+ end
64
+ end
65
+
66
+ def resource_class
67
+ @resource_class ||= self.class.resource_class
68
+ @resource_class ||= begin
69
+ namespaced_class = self.class.to_s.split("::").last.
70
+ sub(/Controller$/, "").singularize
71
+ namespaced_class.constantize
72
+ end
73
+ end
74
+
75
+ def resource_request_name
76
+ resource_class.to_s.underscore.gsub("/", "_").gsub("::", "_")
77
+ end
78
+
79
+ def resource_params
80
+ permitted_params
81
+ end
82
+
83
+ def permitted_params
84
+ params.require(resource_request_name).permit!
85
+ end
86
+
87
+ def json_default_options
88
+ @json_default_options ||= begin
89
+ default_options = {}
90
+ json_options = self.class.json_options || {}
91
+ [:only, :except, :methods].each do |name|
92
+ if json_options.key? name
93
+ default_options[name] = json_options[name]
94
+ end
95
+ end
96
+ default_options[:methods] ||= []
97
+ default_options[:methods].concat(JSON_DEFAULT_ATTRIBUTES).uniq!
98
+ default_options
99
+ end
100
+ end
101
+
102
+ def json_config(action)
103
+ json_options = self.class.json_options
104
+ if json_options && json_options.key?(action)
105
+ json_options = json_options[action]
106
+ json_options[:methods] ||= []
107
+ json_options[:methods].concat(JSON_DEFAULT_ATTRIBUTES).uniq!
108
+ json_options
109
+ else
110
+ json_default_options
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -1,3 +1,3 @@
1
1
  module MongoidApiBase
2
- VERSION = "0.1.5"
2
+ VERSION = '0.1.8'.freeze
3
3
  end
@@ -0,0 +1,182 @@
1
+ # EXTRA LINKS:
2
+ # - https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md
3
+ # - https://github.com/fotinakis/swagger-blocks
4
+ # - https://github.com/westfieldlabs/apivore
5
+ # - https://github.com/notonthehighstreet/svelte
6
+
7
+ module SwaggerGenerator
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ include Swagger::Blocks
12
+ end
13
+
14
+ class_methods do
15
+ REJECT_NAMES = %w(_id _keywords created_at updated_at).freeze
16
+ ALLOW_TYPES = %w(Object String)
17
+
18
+ def generate_swagger
19
+ generate_swagger_schemas
20
+ generate_swagger_paths
21
+ end
22
+
23
+ def collection_name
24
+ @collection_name ||= to_s.split("::").last.sub(/Controller$/, '')
25
+ end
26
+
27
+ def resource_name
28
+ @resource_name ||= collection_name.singularize
29
+ end
30
+
31
+ def generate_swagger_schemas
32
+ name = resource_name
33
+
34
+ if resource_class
35
+ # TODO: add support for resource class option
36
+ else
37
+ resource_class = name.constantize
38
+ end
39
+
40
+ swagger_schema name do
41
+ # TODO: autogenerate list of required fields
42
+ # key :required, %w(name email)
43
+
44
+ resource_class.fields.each do |name, options|
45
+ type = options.type.to_s
46
+ if ALLOW_TYPES.include? type
47
+ unless REJECT_NAMES.include? name
48
+ property name do
49
+ key :type, :string
50
+ # TODO: autodetect property type
51
+ # key :format, 'date-time'
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ def generate_swagger_paths
60
+ name = resource_name
61
+ plural = collection_name
62
+ path = plural.underscore
63
+ tags = [ plural ]
64
+
65
+ swagger_path "/#{ path }" do
66
+ operation :get do
67
+ key :tags, tags
68
+ key :operationId, "index#{ plural }"
69
+ key :produces, %w(application/json text/csv)
70
+
71
+ parameter do
72
+ key :name, :page
73
+ key :in, :query
74
+ key :required, false
75
+ key :type, :integer
76
+ key :format, :int32
77
+ end
78
+
79
+ parameter do
80
+ key :name, :perPage
81
+ key :in, :query
82
+ key :required, false
83
+ key :type, :integer
84
+ key :format, :int32
85
+ end
86
+
87
+ parameter do
88
+ key :name, :search
89
+ key :in, :query
90
+ key :required, false
91
+ key :type, :string
92
+ end
93
+
94
+ response 200 do
95
+ schema type: :array do
96
+ items do
97
+ key :'$ref', name
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ operation :post do
104
+ key :tags, tags
105
+ key :operationId, "create#{ plural }"
106
+ key :produces, %w(application/json)
107
+ parameter do
108
+ key :name, name.underscore.to_sym
109
+ key :in, :form
110
+ key :required, true
111
+ schema do
112
+ key :'$ref', name # input
113
+ end
114
+ end
115
+ response 200 do
116
+ schema do
117
+ key :'$ref', name
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ swagger_path "/#{ path }/{id}" do
124
+ operation :get do
125
+ key :tags, tags
126
+ key :operationId, "show#{ name }ById"
127
+ key :produces, %w(application/json)
128
+ parameter do
129
+ key :name, :id
130
+ key :in, :path
131
+ key :required, true
132
+ key :type, :string
133
+ end
134
+ response 200 do
135
+ schema do
136
+ key :'$ref', name
137
+ end
138
+ end
139
+ end
140
+
141
+ operation :put do
142
+ key :tags, tags
143
+ key :operationId, "update#{ name }"
144
+ key :produces, %w(application/json)
145
+ parameter do
146
+ key :name, :id
147
+ key :in, :path
148
+ key :required, true
149
+ key :type, :string
150
+ end
151
+ parameter do
152
+ key :name, name.underscore.to_sym
153
+ key :in, :form
154
+ key :required, true
155
+ schema do
156
+ key :'$ref', name # input
157
+ end
158
+ end
159
+ response 200 do
160
+ schema do
161
+ key :'$ref', name
162
+ end
163
+ end
164
+ end
165
+
166
+ operation :delete do
167
+ key :tags, tags
168
+ key :operationId, "delete#{ name }"
169
+ parameter do
170
+ key :name, :id
171
+ key :in, :path
172
+ key :required, true
173
+ key :type, :string
174
+ end
175
+ response 204 do
176
+ key :description, "#{ name } deleted"
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
@@ -19,7 +19,9 @@ Gem::Specification.new do |s|
19
19
  s.platform = Gem::Platform::RUBY
20
20
 
21
21
  # Ruby ODM framework for MongoDB
22
- s.add_dependency "mongoid", "~> 5.0"
22
+ s.add_dependency 'mongoid', '~> 5.0'
23
23
  # Clean, powerful, customizable and sophisticated paginator
24
- s.add_dependency "kaminari"
24
+ s.add_dependency 'kaminari'
25
+ # DSL for pure Ruby code blocks that can be turned into JSON
26
+ s.add_dependency 'swagger-blocks'
25
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-api-base
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Kravets
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-17 00:00:00.000000000 Z
11
+ date: 2016-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mongoid
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: swagger-blocks
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  description:
42
56
  email: alex@slatestudio.com
43
57
  executables: []
@@ -52,9 +66,11 @@ files:
52
66
  - README.md
53
67
  - Rakefile
54
68
  - lib/mongoid-api-base.rb
55
- - lib/mongoid-api-base/concern.rb
69
+ - lib/mongoid-api-base/actions.rb
70
+ - lib/mongoid-api-base/base_helpers.rb
56
71
  - lib/mongoid-api-base/version.rb
57
72
  - lib/renderers/csv.rb
73
+ - lib/swagger/generator.rb
58
74
  - mongoid-api-base.gemspec
59
75
  homepage: http://github.com/slate-studio/mongoid-api-base
60
76
  licenses:
@@ -1,216 +0,0 @@
1
- # =============================================================================
2
- # MongoidApiBase
3
- # Rails concern to implement API controllers for Mongoid models.
4
- # -----------------------------------------------------------------------------
5
- # Usage Example:
6
- #
7
- # include MongoidApiBase
8
- #
9
- # defaults resource_class: Journal::JournalPost,
10
- # per_page: 30
11
- #
12
- # has_scope :by_category
13
- # has_scope :hidden, type: :boolean
14
- # has_scope :not_hidden, type: :boolean
15
- #
16
- # json_config methods: %w(hex slug sorted_categories opengraph_image_url meta_title meta_description),
17
- # index: {
18
- # except: %w(body_markdown body_html),
19
- # methods: %w(hex slug)
20
- # }
21
- # =============================================================================
22
- module MongoidApiBase
23
- extend ActiveSupport::Concern
24
- included do
25
- respond_to :json
26
- respond_to :csv, only: %w(index)
27
-
28
- class_attribute :resource_class
29
- class_attribute :per_page
30
- class_attribute :csv_options
31
- class_attribute :json_options
32
-
33
- def index
34
- @chain = resource_class
35
-
36
- apply_scopes_to_chain!
37
- search_filter_chain!
38
- paginate_chain!
39
- set_total_count_header!
40
-
41
- respond_to do |format|
42
- format.json { render json: @chain.as_json(json_config(:index)) }
43
- format.csv { render csv: @chain }
44
- end
45
- end
46
-
47
- def show
48
- object = find_object
49
- object = get_object_version(object)
50
- render json: object.as_json(json_config(:show))
51
- end
52
-
53
- def create
54
- object = build_object
55
- if object.save
56
- render json: object.as_json(json_config(:create))
57
- else
58
- render json: object.errors, status: :unprocessable_entity
59
- end
60
- end
61
-
62
- def update
63
- object = find_object
64
- if object.update_attributes(resource_params)
65
- render json: object.as_json(json_config(:update))
66
- else
67
- render json: object.errors, status: :unprocessable_entity
68
- end
69
- end
70
-
71
- def destroy
72
- object = find_object
73
- if object.destroy
74
- render nothing: true
75
- else
76
- render json: object.errors, status: :unprocessable_entity
77
- end
78
- end
79
-
80
- def find_object
81
- resource_class.find(params[:id])
82
- end
83
-
84
- def get_object_version(object)
85
- version = params[:version]
86
- if version && object.respond_to?(:undo, true)
87
- object.undo(nil, from: version.to_i + 1, to: object.version)
88
- object.version = version
89
- end
90
- object
91
- end
92
-
93
- def build_object
94
- resource_class.new(resource_params)
95
- end
96
-
97
- def apply_scopes_to_chain!
98
- if respond_to?(:apply_scopes, true)
99
- @chain = apply_scopes(@chain)
100
- end
101
- end
102
-
103
- def search_filter_chain!
104
- query = params[:search]
105
- if query
106
- normalized_query = query.to_s.downcase
107
- @chain = @chain.search(normalized_query, match: :all)
108
- end
109
- end
110
-
111
- def page
112
- @page ||= params[:page] || false
113
- end
114
-
115
- def per_page
116
- @per_page ||= params[:perPage] || self.class.per_page || 20
117
- end
118
-
119
- def paginate_chain!
120
- @chain = begin
121
- if page
122
- @chain.page(page).per(per_page)
123
- else
124
- @chain.all
125
- end
126
- end
127
- end
128
-
129
- def set_total_count_header!
130
- if page
131
- response.headers['X-Total-Count'] = @chain.total_count
132
- else
133
- response.headers['X-Total-Count'] = @chain.size
134
- end
135
- end
136
-
137
- def resource_class
138
- @resource_class ||= self.class.resource_class
139
- @resource_class ||= begin
140
- namespaced_class = self.class.to_s.split("::").last.
141
- sub(/Controller$/, "").singularize
142
- namespaced_class.constantize
143
- end
144
- end
145
-
146
- def resource_request_name
147
- resource_class.to_s.underscore.gsub("/", "_").gsub("::", "_")
148
- end
149
-
150
- def resource_params
151
- permitted_params
152
- end
153
-
154
- def permitted_params
155
- params.require(resource_request_name).permit!
156
- end
157
-
158
- def json_default_methods
159
- [ :created_at,
160
- :updated_at,
161
- :slug,
162
- :_position,
163
- :_list_item_title,
164
- :_list_item_subtitle,
165
- :_list_item_thumbnail,
166
- :_document_versions ]
167
- end
168
-
169
- def json_default_options
170
- @json_default_options ||= begin
171
- default_options = {}
172
- json_options = self.class.json_options || {}
173
- [:only, :except, :methods].each do |name|
174
- if json_options.key? name
175
- default_options[name] = json_options[name]
176
- end
177
- end
178
- default_options[:methods] ||= []
179
- default_options[:methods].concat(json_default_methods).uniq!
180
- default_options
181
- end
182
- end
183
-
184
- def json_config(action)
185
- json_options = self.class.json_options
186
- if json_options && json_options.key?(action)
187
- json_options = json_options[action]
188
- json_options[:methods] ||= []
189
- json_options[:methods].concat(json_default_methods).uniq!
190
- json_options
191
- else
192
- json_default_options
193
- end
194
- end
195
- end
196
-
197
- class_methods do
198
- def defaults(options)
199
- if options.key?(:resource_class)
200
- self.resource_class = options[:resource_class]
201
- end
202
-
203
- if options.key?(:per_page)
204
- self.resource_class = options[:per_page]
205
- end
206
- end
207
-
208
- def csv_config(options={})
209
- self.csv_options = options
210
- end
211
-
212
- def json_config(options)
213
- self.json_options = options
214
- end
215
- end
216
- end