api_responser 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 81300d06901f90334a8a2f47154ca0773836b4b0a640923059b62d1e86e48eac
4
+ data.tar.gz: d189a7133d7679a0e788d75d21eeb7bf041166dfd0677326cdc4227c0be97cac
5
+ SHA512:
6
+ metadata.gz: 332bc07fd3079cb4c7bb8743609a146dac88e225bf5c71ecb5f94456b3b34794cb66bc0a7c82468fa2b4b8f46e3a9fd58313a5dc8f733a8fa88d139f63d1af7d
7
+ data.tar.gz: da4e7d004677798c5ac679c31af48c5fa413ade46f12bdc69cceefa0b3abb56a804b305c44a951673a257bafa69b9a1e8cb8276c54a8f49d738b48df58668672
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Nazim T.M.
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 all
13
+ 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 THE
21
+ SOFTWARE.
@@ -0,0 +1,5 @@
1
+ module ApiResponserHelper
2
+ def self.error_handling(code:nil,debug_message:nil,message:nil)
3
+ Logger.new(STDOUT).fatal("Error with code #{code}. Debug message: #{debug_message}. Message: #{message}")
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ {"status":"error","code":<%= @code %>,"message":"<%= @message %>"}
@@ -0,0 +1 @@
1
+ {"status":"success","code":<%= @code %>,"message":"<%= @message %>","records":<%= @records.to_json %>,"records_count":<%= @records_count %>}
@@ -0,0 +1,27 @@
1
+ en:
2
+ api_responser:
3
+ error:
4
+ access_denied: "Access denied"
5
+ page_not_found: "Page not found"
6
+ record_not_found: "Record not found"
7
+ record_not_created: "Record not created: %{message}"
8
+ record_not_updated: "Record not saved: %{message}"
9
+ record_not_deleted: "Record not deleted: %{message}"
10
+ bad_request: "Bad request"
11
+ unauthorized: "Unauthorized"
12
+ forbidden: "Forbidden"
13
+ method_not_allowed: "Method not allowed"
14
+ not_acceptable: "Not acceptable"
15
+ conflict: "Conflict"
16
+ gone: "Gone"
17
+ unsupported_media_type: "Unsupported media type"
18
+ too_many_requests: "Too many requests"
19
+ internal_server_error: "Internal Server Error"
20
+ not_implemented: "Not implemented"
21
+ service_unavailable: "Service unavailable"
22
+ success:
23
+ record_index: "List"
24
+ record_created: "Created"
25
+ record_updated: "Updated"
26
+ record_deleted: "Deleted"
27
+ record_show: "Show"
@@ -0,0 +1,19 @@
1
+ require 'rails'
2
+
3
+ module ApiResponser
4
+ class Railtie < Rails::Railtie
5
+ I18n.load_path += Dir[File.join(File.dirname(__FILE__), '../../config/locales/*.yml')]
6
+
7
+ initializer 'api_responser.add_view_paths' do |app|
8
+ # Adding the gem's views directory to the view paths
9
+ app.config.paths['app/views'].unshift File.expand_path('../../../app/views', __FILE__)
10
+ end
11
+
12
+ initializer 'api_responser.include_helpers' do
13
+ ActiveSupport.on_load(:action_controller_base) do
14
+ require File.expand_path('../../../app/helpers/api_responser_helper', __FILE__)
15
+ include ApiResponserHelper
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,143 @@
1
+ require 'rails'
2
+
3
+ require_relative 'api_responser/railtie' if defined?(Rails)
4
+ module ApiResponser
5
+ # Success responses
6
+ def record_index(records, records_count = nil)
7
+ success_render(code: 200, message: i18n_message(__method__, status:"success"), records: records, records_count: records_count)
8
+ end
9
+
10
+ def record_show(records)
11
+ success_render(code: 200, message: i18n_message(__method__, status:"success"), records: records)
12
+ end
13
+
14
+ def record_created
15
+ api_success(code: 201)
16
+ end
17
+
18
+ def record_updated
19
+ api_success(code: 204)
20
+ end
21
+
22
+ def record_deleted
23
+ api_success(code: 204)
24
+ end
25
+
26
+ # Error responses
27
+ def page_not_found
28
+ error_render(code: 404, message: i18n_message(__method__, status:"error"))
29
+ end
30
+
31
+ def record_not_found
32
+ error_render(code: 404, message: i18n_message(__method__, status:"error"))
33
+ end
34
+
35
+ def record_not_created(message, debug_message = "", report:false)
36
+ error_render(code: 422, message: i18n_message(__method__, status:"error", message: message), debug_message: debug_message, report:report)
37
+ end
38
+
39
+ def record_not_updated(message, debug_message = "", report:false)
40
+ error_render(code: 422, message: i18n_message(__method__, status:"error", message: message), debug_message: debug_message, report:report)
41
+ end
42
+
43
+ def record_not_deleted(message, debug_message = "", report:false)
44
+ error_render(code: 500, message: i18n_message(__method__, status:"error", message: message), debug_message: debug_message, report:report)
45
+ end
46
+
47
+ def bad_request(debug_message = "", report:false)
48
+ error_render(code: 400, message: i18n_message(__method__, status:"error"), debug_message: debug_message, report:report)
49
+ end
50
+
51
+ def unauthorized(debug_message = "", report:false)
52
+ error_render(code: 401, message: i18n_message(__method__, status:"error"), debug_message: debug_message, report:report)
53
+ end
54
+
55
+ def forbidden(debug_message = "", report:false)
56
+ error_render(code: 403, message: i18n_message(__method__, status:"error"), debug_message: debug_message, report:report)
57
+ end
58
+
59
+ def internal_server_error(debug_message = "", report:false)
60
+ error_render(code: 500, message: i18n_message(__method__, status:"error"), debug_message: debug_message, report:report)
61
+ end
62
+
63
+ def method_not_allowed
64
+ error_render(code: 405, message: i18n_message(__method__, status:"error"))
65
+ end
66
+
67
+ def not_acceptable
68
+ error_render(code: 406, message: i18n_message(__method__, status:"error"))
69
+ end
70
+
71
+ def conflict
72
+ error_render(code: 409, message: i18n_message(__method__, status:"error"))
73
+ end
74
+
75
+ def gone
76
+ error_render(code: 410, message: i18n_message(__method__, status:"error"))
77
+ end
78
+
79
+ def unsupported_media_type
80
+ error_render(code: 415, message: i18n_message(__method__, status:"error"))
81
+ end
82
+
83
+ def too_many_requests
84
+ error_render(code: 429, message: i18n_message(__method__, status:"error"))
85
+ end
86
+
87
+
88
+ def not_implemented
89
+ error_render(code: 501, message: i18n_message(__method__, status:"error"))
90
+ end
91
+
92
+ def service_unavailable
93
+ error_render(code: 503, message: i18n_message(__method__, status:"error"))
94
+ end
95
+
96
+ private
97
+
98
+ def api_success(code: 200)
99
+ {status: code}
100
+ end
101
+
102
+
103
+ def success_render(code: 200, message: "", records: nil, records_count: nil)
104
+ @code = code
105
+ @message = message
106
+ @records = records
107
+ @records_count = determine_records_count(records, records_count)
108
+ {json:ERB.new(file_read("success")).result(binding), status: code}
109
+ end
110
+
111
+ def error_render(code: 500, message: "", debug_message: "", report: false)
112
+ @code = code
113
+ @message = message
114
+ error_handling(code: code, message: message, debug_message: debug_message) if report == true
115
+ {json: ERB.new(file_read("error")).result(binding), status: code}
116
+ end
117
+
118
+ def file_read(type = "error")
119
+ if defined?(Rails) && Rails.root
120
+ app_view_path = Rails.root.join('app', 'views', 'api_responser', "#{type}.json.erb")
121
+ else
122
+ app_view_path = File.join(Dir.pwd, 'app', 'views', 'api_responser', "#{type}.json.erb")
123
+ end
124
+
125
+ gem_view_path = File.expand_path("../../app/views/api_responser/#{type}.json.erb", __FILE__)
126
+
127
+ File.exist?(app_view_path) ? File.read(app_view_path) : File.read(gem_view_path)
128
+ end
129
+
130
+ def i18n_message(method_name, status:"error", message: nil)
131
+ message = message.full_messages.join(', ') if message.is_a?(ActiveModel::Errors)
132
+ message = message.join(', ') if message.is_a?(Array)
133
+ I18n.t("api_responser.#{status}.#{method_name}", message: message)
134
+ end
135
+
136
+ def error_handling(code:, message:, debug_message:)
137
+ ApiResponserHelper.error_handling(:code => code, :message => message, :debug_message => debug_message)
138
+ end
139
+
140
+ def determine_records_count(records, records_count)
141
+ records_count || ((records.is_a?(ActiveRecord::Relation) || (records.is_a?(Array))) ? records.count : (records.nil? || records.blank? ? 0 : 1))
142
+ end
143
+ end
data/readme.md ADDED
@@ -0,0 +1,264 @@
1
+ # ApiResponser
2
+
3
+ #### Overview
4
+ The **api_responser** gem is designed to streamline the process of handling API responses in your Rails application. It provides a simple and consistent way to render success and error messages, ensuring your API responses are always well-structured and easy to manage.
5
+
6
+ #### Key Features
7
+ - Standardized Responses: Simplify the way you handle API responses by using a set of predefined methods for success and error messages.
8
+ - Localization Support: Leverage the power of I18n to dynamically translate response messages, making your API more versatile and user-friendly for a global audience.
9
+ - Ease of Use: With intuitive method names and straightforward implementation, integrating api_responser into your Rails application is quick and hassle-free.
10
+ - Maintenance: Reduce the effort required to maintain consistent response structures across your application, making your codebase cleaner and more maintainable.
11
+
12
+ A gem to standardize API responses in Rails applications.
13
+
14
+ All methods return JSON and status.
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'api_responser'
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ ```bash
27
+ bundle install
28
+ ```
29
+
30
+ Or install it yourself as:
31
+
32
+ ```bash
33
+ gem install api_responser
34
+ ```
35
+
36
+ ## Usage
37
+ ### Initialization
38
+ ```ruby
39
+ class ApplicationController < ActionController::Base
40
+ include ApiResponser
41
+ end
42
+ ```
43
+
44
+ ## Success Response list
45
+ #### List of Items
46
+ The *records* argument is required and should be an **Array**. The *records_count* argument is an **Integer** and is optional.\
47
+ If *records_count* is not provided, the count will be calculated from the size of the *records* array
48
+ ```ruby
49
+ def record_index(records, records_count = nil)
50
+ ```
51
+ #### Show Item
52
+ The *records* argument should be a **Hash**. It should contain only one model
53
+ ```ruby
54
+ def record_show(records)
55
+ ```
56
+ #### Item Create / Item Update / Item Delete
57
+ *No arguments* are required
58
+ ```ruby
59
+ def record_created
60
+ ```
61
+ ```ruby
62
+ def record_updated
63
+ ```
64
+ ```ruby
65
+ def record_deleted
66
+ ```
67
+
68
+
69
+
70
+
71
+ ## Error Response list
72
+ #### Page Not Found / Record Not Found / Method Not Allowed / Not Acceptable / Conflict / Gone / Unsupported Media Type / Too Many Requests / Not Implemented / Service Unavailable
73
+ *No arguments* are required
74
+
75
+ ```ruby
76
+ def page_not_found
77
+ ```
78
+ ```ruby
79
+ def record_not_found
80
+ ```
81
+ ```ruby
82
+ def method_not_allowed
83
+ ```
84
+ ```ruby
85
+ def not_acceptable
86
+ ```
87
+ ```ruby
88
+ def conflict
89
+ ```
90
+ ```ruby
91
+ def gone
92
+ ```
93
+ ```ruby
94
+ def unsupported_media_type
95
+ ```
96
+ ```ruby
97
+ def too_many_requests
98
+ ```
99
+ ```ruby
100
+ def not_implemented
101
+ ```
102
+ ```ruby
103
+ def service_unavailable
104
+ ```
105
+
106
+ #### Record Not Created / Record Not Updated / Record Not Deleted
107
+ The *message* argument is required, while the *debug_message* argument is optional.\
108
+ The *report* argument is optional and is useful if you would like to handle *debug_message*.\
109
+ The *message* argument is used to output a message in the JSON response, whereas *debug_message* is useful for providing the real reason for the error (if *report* is **true**).
110
+
111
+ ```ruby
112
+ def record_not_created(message, debug_message = "", report:false)
113
+ ```
114
+ ```ruby
115
+ def record_not_updated(message, debug_message = "", report:false)
116
+ ```
117
+ ```ruby
118
+ def record_not_deleted(message, debug_message = "", report:false)
119
+ ```
120
+
121
+ #### Bad request / Unauthorized / Forbidden / Internal Server Error
122
+ The *debug_message* argument is optional.\
123
+ The *report* argument is optional and is useful if you would like to handle *debug_message*.\
124
+ The *debug_message* is useful for providing the real reason for the error (if *report* is **true**).
125
+
126
+ ```ruby
127
+ def bad_request(debug_message = "", report:false)
128
+ ```
129
+ ```ruby
130
+ def unauthorized(debug_message = "", report:false)
131
+ ```
132
+ ```ruby
133
+ def forbidden(debug_message = "", report:false)
134
+ ```
135
+ ```ruby
136
+ def internal_server_error(debug_message = "", report:false)
137
+ ```
138
+
139
+
140
+ ## Customizing Response Templates
141
+ You can modify the success and error response templates.
142
+ Templates should be located in **app/views/api_responser/**
143
+
144
+ The default templates are:
145
+ #### success.json.erb
146
+ ``` ruby
147
+ {
148
+ "status": "success",
149
+ "code": <%= @code %>,
150
+ "message": "<%= @message %>",
151
+ "records": <%= @records.to_json %>,
152
+ "records_count": <%= @records_count %>
153
+ }
154
+ ```
155
+ #### error.json.erb
156
+ ``` ruby
157
+ {
158
+ "status": "error",
159
+ "code": <%= @code %>,
160
+ "message": "<%= @message %>"
161
+ }
162
+ ```
163
+
164
+ ## Customizing Error Handling
165
+ The gem provides a default error handler in **ApiResponserHelper**:
166
+ ``` ruby
167
+ module ApiResponserHelper
168
+ def error_handling(code: nil, debug_message: nil, message: nil)
169
+ Logger.new(STDOUT).fatal("Error with code #{code}. Debug message: #{debug_message}. Message: #{message}")
170
+ end
171
+ end
172
+ ```
173
+ You can customize this method to handle errors in a way that suits your application's requirements. For example, you might want to log errors to a file or send notifications to an external service.
174
+ Helper should be located in **app/helpers/app_responser_helper.rb**
175
+
176
+
177
+ ## Localization
178
+ **ApiResponser** uses I18n for localization.
179
+
180
+ Default localization located in config/locale/en.yml
181
+
182
+
183
+
184
+ ## Example
185
+ ```ruby
186
+ class ApplicationController < ActionController::Base
187
+ include ApiResponser
188
+ before_action do
189
+ set_model_variable("ModelName")
190
+ end
191
+ before_action :find, only: [:show, :update, :destroy]
192
+
193
+ def index
194
+ itemList = @modelName.all
195
+ render record_index(itemList)
196
+
197
+ # could be using with counter for pagination
198
+ itemList = @modelName.where(:name => "value")
199
+ render record_index(itemList.limit(5), itemList.count)
200
+ end
201
+
202
+ def show
203
+ render record_show(@obj)
204
+ end
205
+
206
+ def create
207
+ item = @modelName.new(model_params)
208
+ if item.save
209
+ render record_created
210
+ else
211
+ render record_not_created(item.errors, report:true)
212
+ end
213
+ end
214
+
215
+ def update
216
+ if @obj.update(model_params)
217
+ render record_updated
218
+ else
219
+ render record_not_updated(@obj.errors, report:true)
220
+ end
221
+ end
222
+
223
+ def destroy
224
+ if @obj.destroy
225
+ render record_deleted
226
+ else
227
+ render record_not_deleted(@obj.errors, report:true)
228
+ end
229
+ end
230
+
231
+
232
+ private
233
+ def find
234
+ @obj = @modelName.find_by(:id => params[:id])
235
+ unless @obj
236
+ render record_not_found
237
+ end
238
+ end
239
+
240
+ def model_params
241
+ params.require(:model).permit(:name)
242
+ end
243
+
244
+ def set_model_variable modelName
245
+ @modelName = modelName.constantize
246
+ end
247
+ end
248
+
249
+ ```
250
+
251
+ [![Buy me a coffee](https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20coffee&emoji=&slug=nmehdiyev&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff)](https://www.buymeacoffee.com/nmehdiyev)
252
+
253
+
254
+
255
+ ## Contributing
256
+
257
+ Pull requests are welcome. For major changes, please open an issue first
258
+ to discuss what you would like to change.
259
+
260
+ Please make sure to update tests as appropriate.
261
+
262
+ ## License
263
+
264
+ [MIT](https://choosealicense.com/licenses/mit/)
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: api_responser
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Nazim Mehdiyev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-07-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: webrick
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: "\n The api_responser gem provides a standardized way to handle API
56
+ responses in a Rails application. \n It includes methods for rendering success
57
+ and error responses, making it easier to manage and maintain \n consistent response
58
+ structures across your application. The gem leverages I18n for localization, allowing
59
+ \n dynamic translation of response messages based on method names.\n "
60
+ email:
61
+ - nazim@mehdiyev.me
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - LICENSE
67
+ - app/helpers/api_responser_helper.rb
68
+ - app/views/api_responser/error.json.erb
69
+ - app/views/api_responser/success.json.erb
70
+ - config/locales/en.yml
71
+ - lib/api_responser.rb
72
+ - lib/api_responser/railtie.rb
73
+ - readme.md
74
+ homepage: https://github.com/nmehdiyev/ApiResponser
75
+ licenses:
76
+ - MIT
77
+ metadata:
78
+ source_code_uri: https://github.com/nmehdiyev/ApiResponser
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubygems_version: 3.4.10
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: A gem to standardize API responses in Rails applications
98
+ test_files: []