mongoid-api-base 0.1.5 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
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