api-response_builder 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f94d9f6432b2633b6770e26ab87ebd19fdb919761b7dcea2ed9885cf80973012
4
+ data.tar.gz: 6322f9a05cf5e372a249d827b444c4d44a07c82f9b10099c48f56ed57754167c
5
+ SHA512:
6
+ metadata.gz: df5a399358707342ed4105b981bff36f13aee7575601719a06cfc2546169cdbde9cbaebdb3affd3c18d3f50c3ad8785129d13541d764d08248ddca1aad1196f3
7
+ data.tar.gz: 9afb01c0539ed5e7127c65cfabf046c32ff8c756b7a4624904e41b0753cf1a7e85ebf6c58bfbcffb88642f33d7412048acd00536b9ed2cfa78e0e1777ed57e69
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.0
5
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "https://rubygems.org"
2
+
3
+ # git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in api-response_builder.gemspec
6
+ gemspec
7
+
8
+ gem 'i18n', '~> 0.9.1'
9
+
10
+ gem 'activerecord', '~> 5.0', '>= 5.0.0.1'
11
+
12
+ gem 'active_model_serializers', '~> 0.10.7'
13
+
14
+ # gem 'mysql2'
@@ -0,0 +1,97 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ api-response_builder (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ actionpack (5.1.4)
10
+ actionview (= 5.1.4)
11
+ activesupport (= 5.1.4)
12
+ rack (~> 2.0)
13
+ rack-test (>= 0.6.3)
14
+ rails-dom-testing (~> 2.0)
15
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
16
+ actionview (5.1.4)
17
+ activesupport (= 5.1.4)
18
+ builder (~> 3.1)
19
+ erubi (~> 1.4)
20
+ rails-dom-testing (~> 2.0)
21
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
22
+ active_model_serializers (0.10.7)
23
+ actionpack (>= 4.1, < 6)
24
+ activemodel (>= 4.1, < 6)
25
+ case_transform (>= 0.2)
26
+ jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
27
+ activemodel (5.1.4)
28
+ activesupport (= 5.1.4)
29
+ activerecord (5.1.4)
30
+ activemodel (= 5.1.4)
31
+ activesupport (= 5.1.4)
32
+ arel (~> 8.0)
33
+ activesupport (5.1.4)
34
+ concurrent-ruby (~> 1.0, >= 1.0.2)
35
+ i18n (~> 0.7)
36
+ minitest (~> 5.1)
37
+ tzinfo (~> 1.1)
38
+ arel (8.0.0)
39
+ builder (3.2.3)
40
+ case_transform (0.2)
41
+ activesupport
42
+ concurrent-ruby (1.0.5)
43
+ crass (1.0.3)
44
+ diff-lcs (1.3)
45
+ erubi (1.7.0)
46
+ i18n (0.9.1)
47
+ concurrent-ruby (~> 1.0)
48
+ jsonapi-renderer (0.2.0)
49
+ loofah (2.1.1)
50
+ crass (~> 1.0.2)
51
+ nokogiri (>= 1.5.9)
52
+ mini_portile2 (2.3.0)
53
+ minitest (5.10.3)
54
+ mysql2 (0.4.6)
55
+ nokogiri (1.8.1)
56
+ mini_portile2 (~> 2.3.0)
57
+ rack (2.0.3)
58
+ rack-test (0.8.2)
59
+ rack (>= 1.0, < 3)
60
+ rails-dom-testing (2.0.3)
61
+ activesupport (>= 4.2.0)
62
+ nokogiri (>= 1.6)
63
+ rails-html-sanitizer (1.0.3)
64
+ loofah (~> 2.0)
65
+ rake (10.5.0)
66
+ rspec (3.7.0)
67
+ rspec-core (~> 3.7.0)
68
+ rspec-expectations (~> 3.7.0)
69
+ rspec-mocks (~> 3.7.0)
70
+ rspec-core (3.7.0)
71
+ rspec-support (~> 3.7.0)
72
+ rspec-expectations (3.7.0)
73
+ diff-lcs (>= 1.2.0, < 2.0)
74
+ rspec-support (~> 3.7.0)
75
+ rspec-mocks (3.7.0)
76
+ diff-lcs (>= 1.2.0, < 2.0)
77
+ rspec-support (~> 3.7.0)
78
+ rspec-support (3.7.0)
79
+ thread_safe (0.3.6)
80
+ tzinfo (1.2.4)
81
+ thread_safe (~> 0.1)
82
+
83
+ PLATFORMS
84
+ ruby
85
+
86
+ DEPENDENCIES
87
+ active_model_serializers (~> 0.10.7)
88
+ activerecord (~> 5.0, >= 5.0.0.1)
89
+ api-response_builder!
90
+ bundler (~> 1.16)
91
+ i18n (~> 0.9.1)
92
+ mysql2
93
+ rake (~> 10.0)
94
+ rspec (~> 3.0)
95
+
96
+ BUNDLED WITH
97
+ 1.16.1
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Dass Mk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,350 @@
1
+ # Api::ResponseBuilder
2
+
3
+ Module to build response object for Rails 5 API Applications.
4
+ Depends on `active_model_serializers` gem.
5
+
6
+ Pass a valid / invalid ActiveRecord object or an instance of ActiveRecord::Relation and get response object in following structure.
7
+
8
+ Properties | Description
9
+ ------------ | -------------
10
+ status | 'failure' (or) 'success'
11
+ body | Serialized Object
12
+ messages | Error Description (if any)
13
+ status_code | HTTP Status Code
14
+
15
+
16
+ ## Example
17
+
18
+ ```ruby
19
+ #app/controllers/api/v1/application_controller.rb
20
+ module Api
21
+ module V1
22
+ class ApplicationController < ActionController::API
23
+
24
+ def serializer_responder(resource, config = {})
25
+ response = ::Api::ResponseBuilder::Main.new(resource, config, params).response
26
+ render json: response, status: response[:status_code]
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+
33
+ # app/serializers/v1/user_serializer.rb
34
+ module V1
35
+ # Serializer for User model
36
+ class UserSerializer < ::ActiveModel::Serializer
37
+ attributes :id,
38
+ :firstname,
39
+ :lastname,
40
+ :phone_number,
41
+ :email
42
+ end
43
+ end
44
+
45
+
46
+ # app/controllers/api/v1/users_controller.rb
47
+ module Api
48
+ module V1
49
+ # Defines endpoints for CRUD operations on user model
50
+ class UsersController < ::Api::V1::ApplicationController
51
+
52
+ def index
53
+ users = User.all
54
+ serializer_responder(users, serializer: ::V1::UserSerializer)
55
+ end
56
+
57
+ end
58
+ end
59
+ end
60
+
61
+ ```
62
+
63
+ Response Object for API endpoint `/api/v1/users` will be
64
+
65
+ ```json
66
+ {
67
+ "status": "success",
68
+ "body" :
69
+ [
70
+ {
71
+ "id": 1,
72
+ "firstname": "Kalidas",
73
+ "lastname": "M",
74
+ "phone_number": "+919876543210",
75
+ "email": "kalidasm610@gmail.com"
76
+ },
77
+ {
78
+ "id": 2,
79
+ "firstname": "Dass",
80
+ "lastname": "Mk",
81
+ "phone_number": "+919876543211",
82
+ "email": ""
83
+ }
84
+ ],
85
+ "status_code": "ok"
86
+ }
87
+ ```
88
+
89
+ ## Installation
90
+
91
+ Add this line to your application's Gemfile:
92
+
93
+ ```ruby
94
+ gem 'api-response_builder'
95
+ ```
96
+
97
+ And then execute:
98
+
99
+ $ bundle
100
+
101
+ Or install it yourself as:
102
+
103
+ $ gem install api-response_builder
104
+
105
+ ## Usage
106
+
107
+ #### ApplicationController - Setup
108
+ By taking advantage of Ruby's inheritance and Rails's app structure, few instance methods in application controller can be used to handle all scenarios for rendering json response across entire application.
109
+
110
+ ```ruby
111
+ module Api
112
+ module V1
113
+ class ApplicationController < ActionController::API
114
+ # action callbacks
115
+
116
+ # Global Exception Handler for Api Exceptions and StandardError
117
+ rescue_from ::Api::Exception, StandardError do |e|
118
+ handle_api_exception(e)
119
+ end
120
+
121
+ # Global exception handlers for ActiveRecord Exceptions
122
+ rescue_from ::ActiveRecord::RecordNotFound, with: :render_record_not_found
123
+ rescue_from ::ActiveRecord::RecordInvalid, with: :render_record_invalid
124
+ rescue_from ::ActiveRecord::RecordNotDestroyed, with: :render_forbidden
125
+
126
+ # Public methods
127
+ def handle_api_exception(e)
128
+ response = ::Api::ResponseBuilder::Main.new(e, {}, params).response
129
+ render json: response, status: response[:status_code]
130
+ end
131
+
132
+ def render_record_not_found
133
+ handle_api_exception ::Api::Exception.new(
134
+ ::Api::Exception.record_not_found
135
+ )
136
+ end
137
+
138
+ def render_internal_server_error
139
+ handle_api_exception ::Api::Exception.new(
140
+ ::Api::Exception.internal_server_error
141
+ )
142
+ end
143
+
144
+ def render_record_invalid(e)
145
+ # If exception message is not included in arguments, locale message
146
+ # (if present) for record invalid exception will be returned in resp
147
+ exception_message = e.record.errors.full_messages
148
+ exception = ::Api::Exception.new(
149
+ ::Api::Exception.record_invalid, exception_message
150
+ )
151
+ handle_api_exception(exception)
152
+ end
153
+
154
+ def render_forbidden
155
+ handle_api_exception ::Api::Exception.new(
156
+ ::Api::Exception.forbidden_resource
157
+ )
158
+ end
159
+
160
+ def serializer_responder(resource, config = {})
161
+ response = ::Api::ResponseBuilder::Main.new(resource, config, params).response
162
+ # response object also contains corresponding http status code under the key :status_code
163
+ # Including `Http Status Code` as part of API response is generally considered as good practice
164
+ # If all your api responses should have `200 OK` as status code, omit status key in render method
165
+ # Rails, by default, set status code as `200 OK`
166
+ render json: response, status: response[:status_code]
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ ```
173
+
174
+
175
+ #### Passing Additional Information to Response
176
+
177
+ In some cases, meta information may be passed along with response. For example, passing total count of resources for pagination.
178
+
179
+ In order to pass meta info, include `:meta` key-value pair in config object passed to `::Api::ResponseBuilder::Main`.
180
+ It will be reflected in response object under `meta` key
181
+
182
+ Note:
183
+ * config[:serializer] should be `ActiveModel::Serializer` class (if serializer is not passed, it will serialize entire object)
184
+ * `config[:meta]` will accept only hash
185
+
186
+
187
+ ```ruby
188
+ # app/controllers/api/v1/users_controller.rb
189
+ def index
190
+ users = User.all
191
+
192
+ config = {}
193
+ config[:serializer] = UserSerializer
194
+ config[:meta] = { total_count: users.count }
195
+ serializer_responder(users, config)
196
+ end
197
+
198
+ # simple way
199
+ serializer_responder(users, { serializer: UserSerializer, meta: { total_count: users.count } })
200
+ ```
201
+
202
+ ##### Response
203
+
204
+ ```json
205
+ {
206
+ "status": "success",
207
+ "body" :
208
+ [
209
+ {
210
+ "id": 1,
211
+ "firstname": "Kalidas",
212
+ "lastname": "M",
213
+ "phone_number": "+919876543210",
214
+ "email": "kalidasm610@gmail.com"
215
+ },
216
+ {
217
+ "id": 2,
218
+ "firstname": "Dass",
219
+ "lastname": "Mk",
220
+ "phone_number": "+919876543211",
221
+ "email": ""
222
+ }
223
+ ],
224
+ "status_code": "ok",
225
+ "meta": {
226
+ "total_count": 2
227
+ }
228
+ }
229
+ ```
230
+
231
+
232
+ #### API Exceptions
233
+
234
+ Following exceptions are handled by this gem as there are the most commonly used.
235
+
236
+ EXCEPTION | HTTP Status Code
237
+ ------------ | -------------
238
+ INTERNAL_SERVER_ERROR | :internal_server_error (500)
239
+ RECORD_NOT_FOUND | :not_found (404)
240
+ RECORD_INVALID | ::unprocessable_entity (422)
241
+ RECORD_NOT_DESTROYED | :forbidden (403)
242
+ FORBIDDEN_RESOURCE | :forbidden (403)
243
+ UNAUTHORIZED_ACCESS | :unauthorized (401)
244
+
245
+ For futher information, take a look at the [Code](https://github.com/kalidasm/rails-api-response-builder/blob/master/lib/api/exception.rb)
246
+
247
+
248
+ ##### Error Messages for API Exceptions
249
+
250
+ All the error messages for these exceptions are rendered from I18n locales (`en.api_response.messages.#{key}`)
251
+
252
+ Key represents lower-cased version of exception names listed above
253
+
254
+ Example :
255
+
256
+ ```yml
257
+ en:
258
+ api_response:
259
+ messages:
260
+ internal_server_error: "Internal server error."
261
+ record_not_found: "The resource you are looking for does not exist."
262
+ record_invalid: "Validation Failed"
263
+ record_not_destroyed: "Failed to delete the resource"
264
+ forbidden_resource: "You don't have sufficient privileges to perform this operation"
265
+ unauthorized_access: "You are not authorized to perform this operation"
266
+ ```
267
+
268
+ ##### Raising API Exception inside controllers
269
+
270
+ ```ruby
271
+ def update_credit_score
272
+ # code to authorization info for current user
273
+ unless user_authorized?
274
+ raise ::Api::Exception.new(
275
+ ::Api::Exception.unauthorized_access
276
+ )
277
+ end
278
+ # Code to Update the credit score
279
+ end
280
+ ```
281
+
282
+ Response would be
283
+
284
+ ```json
285
+ {
286
+ "status": "failure",
287
+ "messages": {
288
+ "errors": ["You are not authorized to perform this operation"]
289
+ },
290
+ "status_code": "unprocessable_entity",
291
+ "meta": {}
292
+ }
293
+ ```
294
+
295
+ If you want to override the default error message in a specific scenario,
296
+
297
+ ```ruby
298
+ def update_credit_score
299
+ # code to authorization info for current user
300
+ unless user_authorized?
301
+ custom_error_message = 'You are not allowed to update credit score'
302
+
303
+ raise ::Api::Exception.new(
304
+ ::Api::Exception.unauthorized_access, custom_error_message
305
+ )
306
+ end
307
+ # Code to Update the credit score
308
+ end
309
+ ```
310
+ ```json
311
+ {
312
+ "status": "failure",
313
+ "messages": {
314
+ "errors": ["You are not allowed to update credit score"]
315
+ },
316
+ "status_code": "unprocessable_entity",
317
+ "meta": {}
318
+ }
319
+ ```
320
+
321
+ #### Response Status - Failure / Success
322
+
323
+ Response Object contains a key named `status`. It will have only any one of
324
+ * failure
325
+ * success
326
+
327
+ Status will be `failure` when
328
+ * Resource has any errors
329
+ * Resource is an instance of `::Api::Exception`
330
+ * StandardError is raised
331
+
332
+ Status will be `success` when
333
+ * Resource do not have any errors
334
+ * Resource is *not* an instance of `::Api::Exception`
335
+ * No Exception been raised
336
+
337
+
338
+ ## Development
339
+
340
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
341
+
342
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
343
+
344
+ ## Contributing
345
+
346
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kalidasm/api-response_builder.
347
+
348
+ ## License
349
+
350
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,37 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "api/response_builder/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "api-response_builder"
8
+ spec.version = Api::ResponseBuilder::VERSION
9
+ spec.authors = ["Dass Mk"]
10
+ spec.email = ["kalidasm610@gmail.com"]
11
+
12
+ spec.summary = %q{API Response Builder to keep controllers super-slim}
13
+ spec.description = %q{API Response Builder to keep controllers super-slim}
14
+ spec.homepage = "https://github.com/kalidasm/rails-api-response-builder"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against " \
23
+ # "public gem pushes."
24
+ # end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.16"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "rspec", "~> 3.0"
36
+ spec.add_development_dependency "i18n", "~> 0.7.0"
37
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "api/response_builder"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+ # Base API exception class to create custom exceptions dynamically
3
+ # with a code and message passed
4
+ require 'i18n'
5
+
6
+ module Api
7
+ class Exception < ::StandardError
8
+ attr_accessor :messages
9
+
10
+ def initialize(error_constant, messages = nil)
11
+ @error_constant = error_constant
12
+ @messages = {
13
+ @error_constant[:key].to_s => [messages || @error_constant[:message]]
14
+ }
15
+ end
16
+
17
+ def full_messages
18
+ @messages.values.flatten
19
+ end
20
+
21
+ def status_code
22
+ @error_constant[:status_code]
23
+ end
24
+
25
+ class << self
26
+ def error_constants
27
+ {
28
+ INTERNAL_SERVER_ERROR: {
29
+ message: t(:internal_server_error),
30
+ key: :internal_server_error,
31
+ status_code: :internal_server_error
32
+ },
33
+ RECORD_NOT_FOUND: {
34
+ message: t(:record_not_found),
35
+ key: :record_not_found,
36
+ status_code: :not_found
37
+ },
38
+ RECORD_INVALID: {
39
+ message: t(:record_invalid),
40
+ key: :record_invalid,
41
+ status_code: :unprocessable_entity
42
+ },
43
+ RECORD_NOT_DESTROYED: {
44
+ message: t(:record_not_destroyed),
45
+ key: :record_not_destroyed,
46
+ status_code: :forbidden
47
+ },
48
+ FORBIDDEN_RESOURCE: {
49
+ message: t(:forbidden_resource),
50
+ key: :forbidden_resource,
51
+ status_code: :forbidden
52
+ },
53
+ UNAUTHORIZED_ACCESS: {
54
+ message: t(:unauthorized_access),
55
+ key: :unauthorized_access,
56
+ status_code: :unauthorized
57
+ }
58
+ }
59
+ end
60
+
61
+ private
62
+
63
+ def t(key)
64
+ ::I18n.config.available_locales = :en
65
+ ::I18n.t("api_response.messages.#{key}")
66
+ end
67
+ end
68
+
69
+ error_constants.each do |key, value|
70
+ define_singleton_method(key.downcase) { value }
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,15 @@
1
+ require "api/response_builder/version"
2
+ require "api/response_builder/base"
3
+ require "api/response_builder/data"
4
+ require "api/response_builder/main"
5
+ require "api/response_builder/messages"
6
+ require "api/response_builder/status"
7
+ require "api/response_builder/status_code"
8
+ require "api/exception"
9
+ require "active_record"
10
+ require "active_model_serializers"
11
+
12
+ module Api
13
+ module ResponseBuilder
14
+ end
15
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ module Api
3
+ module ResponseBuilder
4
+ # Base Class for building api response
5
+ class Base
6
+ attr_accessor :resource,
7
+ :config
8
+
9
+ def initialize(resource, config = {})
10
+ @resource = resource
11
+ @config = config
12
+ end
13
+
14
+ protected
15
+
16
+ def active_model_object?
17
+ @resource.is_a?(::ActiveRecord::Base)
18
+ end
19
+
20
+ def hash_object?
21
+ @resource.is_a?(Hash)
22
+ end
23
+
24
+ def resource_has_errors?
25
+ active_model_object? && @resource.errors.any?
26
+ end
27
+
28
+ def collection?
29
+ @resource.is_a?(::ActiveRecord::Relation) || @resource.is_a?(Array)
30
+ end
31
+
32
+ def exception?
33
+ @resource.is_a?(Exception)
34
+ end
35
+
36
+ def other_exception?
37
+ !api_exception? && @resource.is_a?(StandardError)
38
+ end
39
+
40
+ def api_exception?
41
+ @resource.is_a?(::Api::Exception)
42
+ end
43
+
44
+ def invalid_resource?
45
+ return @resource.errors.any? if active_model_object?
46
+ false
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ module Api
3
+ module ResponseBuilder
4
+ # Class which helps in building api response body
5
+ class Data < ::Api::ResponseBuilder::Base
6
+ attr_accessor :data
7
+
8
+ def initialize(resource, config = {})
9
+ super(resource, config)
10
+ @data = nil
11
+ set_data
12
+ end
13
+
14
+ private
15
+
16
+ def set_data
17
+ return if exception?
18
+ set_object_data
19
+ set_collection_data
20
+ end
21
+
22
+ def set_collection_data
23
+ return unless collection?
24
+ @data = ::ActiveModel::Serializer::CollectionSerializer.
25
+ new(resource, config)
26
+ end
27
+
28
+ def set_object_data
29
+ return if invalid_resource?
30
+ serializer = config[:serializer]
31
+ @data = serializer ? serializer.new(resource, config) : resource
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ module Api
3
+ module ResponseBuilder
4
+ # Class which helps in building whole api response
5
+ class Main
6
+ attr_accessor :resource,
7
+ :config,
8
+ :response,
9
+ :params
10
+
11
+ def initialize(resource, config = {}, params = {})
12
+ @resource = resource
13
+ @config = config
14
+ @response = {}
15
+ @params = params
16
+ set_response
17
+ end
18
+
19
+ def set_response
20
+ prepare_response
21
+ response_data = ::Api::ResponseBuilder::Data.new(resource, config).data
22
+ messages = ::Api::ResponseBuilder::Messages.new(resource, config).messages
23
+ status_code = ::Api::ResponseBuilder::StatusCode.new(resource, config).status_code
24
+
25
+ @response[:body] = response_data if response_data.present?
26
+ @response[:messages] = messages if messages.present?
27
+ @response[:status_code] = status_code
28
+ @response[:meta] = (config[:meta].to_h)
29
+ end
30
+
31
+ def prepare_response
32
+ status_msg = ::Api::ResponseBuilder::Status.new(resource, config).status_message
33
+ @response = status_msg.present? ? status_msg : {}
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ module Api
3
+ module ResponseBuilder
4
+ # Class which helps in building messges for api response
5
+ class Messages < ::Api::ResponseBuilder::Base
6
+ attr_accessor :messages
7
+
8
+ def initialize(resource, config = {})
9
+ super(resource, config)
10
+ @messages = {}
11
+ set_messages
12
+ end
13
+
14
+ private
15
+
16
+ def set_messages
17
+ add_errors_if_any
18
+ return unless other_exception?
19
+ exception = ::Api::Exception.internal_server_error
20
+ @messages[:errors] = ::Api::Exception.new(exception, resource.message).
21
+ full_messages
22
+ end
23
+
24
+ def add_errors_if_any
25
+ @messages[:errors] = resource.full_messages if api_exception?
26
+ return unless resource_has_errors?
27
+ @messages[:errors] = resource.errors.full_messages
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ module Api
3
+ module ResponseBuilder
4
+ # Class which helps in building status of api response
5
+ class Status < ::Api::ResponseBuilder::Base
6
+ attr_accessor :status_message
7
+
8
+ def initialize(resource, config = {})
9
+ super(resource, config)
10
+ @status_message = { status: "success" }
11
+ set_status_message
12
+ end
13
+
14
+ private
15
+
16
+ def set_status_message
17
+ return unless resource_has_errors? || api_exception? || other_exception?
18
+ @status_message[:status] = "failure"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module Api
3
+ module ResponseBuilder
4
+ # Class which helps in building status code of api response
5
+ class StatusCode < ::Api::ResponseBuilder::Base
6
+ attr_accessor :status_code,
7
+ :resource
8
+
9
+ def initialize(resource, config = {})
10
+ super(resource, config)
11
+ @resource = resource
12
+ @status_code = :ok
13
+ set_status_code
14
+ end
15
+
16
+ private
17
+
18
+ def set_status_code
19
+ return unless resource_has_errors? || api_exception? || other_exception?
20
+ if resource_has_errors?
21
+ @status_code = :unprocessable_entity
22
+ elsif api_exception?
23
+ # resource is an instance of ApiException class
24
+ @status_code = @resource.status_code
25
+ else
26
+ # other exception which is probably internal server error
27
+ @status_code = :internal_server_error
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ module Api
2
+ module ResponseBuilder
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: api-response_builder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Dass Mk
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-12-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: i18n
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.7.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.7.0
69
+ description: API Response Builder to keep controllers super-slim
70
+ email:
71
+ - kalidasm610@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - Gemfile.lock
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - api-response_builder.gemspec
85
+ - bin/console
86
+ - bin/setup
87
+ - lib/api/exception.rb
88
+ - lib/api/response_builder.rb
89
+ - lib/api/response_builder/base.rb
90
+ - lib/api/response_builder/data.rb
91
+ - lib/api/response_builder/main.rb
92
+ - lib/api/response_builder/messages.rb
93
+ - lib/api/response_builder/status.rb
94
+ - lib/api/response_builder/status_code.rb
95
+ - lib/api/response_builder/version.rb
96
+ homepage: https://github.com/kalidasm/rails-api-response-builder
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.7.3
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: API Response Builder to keep controllers super-slim
120
+ test_files: []