api_responser 1.0.0

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