respondo 0.1.0 → 2.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 +4 -4
- data/CHANGELOG.md +179 -0
- data/README.md +419 -188
- data/lib/respondo/configuration.rb +6 -0
- data/lib/respondo/controller_helpers.rb +272 -67
- data/lib/respondo/pagination.rb +141 -83
- data/lib/respondo/response_builder.rb +48 -19
- data/lib/respondo/version.rb +1 -1
- data/lib/respondo.rb +1 -1
- metadata +2 -2
|
@@ -29,12 +29,18 @@ module Respondo
|
|
|
29
29
|
# config.serializer = ->(obj) { SomeSerializer.new(obj).as_json }
|
|
30
30
|
attr_accessor :serializer
|
|
31
31
|
|
|
32
|
+
# Static key-value pairs merged into every response's meta block.
|
|
33
|
+
# @example
|
|
34
|
+
# config.default_meta = { api_version: "v1", platform: "mobile" }
|
|
35
|
+
attr_accessor :default_meta
|
|
36
|
+
|
|
32
37
|
def initialize
|
|
33
38
|
@default_success_message = "Success"
|
|
34
39
|
@default_error_message = "An error occurred"
|
|
35
40
|
@include_request_id = false
|
|
36
41
|
@camelize_keys = false
|
|
37
42
|
@serializer = nil
|
|
43
|
+
@default_meta = {} # e.g. { api_version: "v1", env: "production" }
|
|
38
44
|
end
|
|
39
45
|
end
|
|
40
46
|
end
|
|
@@ -4,20 +4,39 @@ module Respondo
|
|
|
4
4
|
# Mixed into Rails controllers to provide render_success and render_error.
|
|
5
5
|
#
|
|
6
6
|
# Success helpers (2xx):
|
|
7
|
-
# render_success, render_created, render_accepted,
|
|
8
|
-
#
|
|
7
|
+
# render_success, render_ok, render_created, render_accepted,
|
|
8
|
+
# render_non_authoritative, render_no_content, render_reset_content,
|
|
9
|
+
# render_partial_content, render_multi_status, render_already_reported,
|
|
10
|
+
# render_im_used
|
|
11
|
+
#
|
|
12
|
+
# Informational helpers (1xx):
|
|
13
|
+
# render_continue, render_switching_protocols, render_processing,
|
|
14
|
+
# render_early_hints
|
|
15
|
+
#
|
|
16
|
+
# Redirect helpers (3xx):
|
|
17
|
+
# render_multiple_choices, render_moved_permanently, render_found,
|
|
18
|
+
# render_see_other, render_not_modified, render_temporary_redirect,
|
|
19
|
+
# render_permanent_redirect
|
|
9
20
|
#
|
|
10
21
|
# Client error helpers (4xx):
|
|
11
22
|
# render_bad_request, render_unauthorized, render_payment_required,
|
|
12
23
|
# render_forbidden, render_not_found, render_method_not_allowed,
|
|
13
|
-
# render_not_acceptable,
|
|
14
|
-
#
|
|
15
|
-
# render_precondition_failed,
|
|
16
|
-
#
|
|
24
|
+
# render_not_acceptable, render_proxy_auth_required, render_request_timeout,
|
|
25
|
+
# render_conflict, render_gone, render_length_required,
|
|
26
|
+
# render_precondition_failed, render_payload_too_large, render_uri_too_long,
|
|
27
|
+
# render_unsupported_media_type, render_range_not_satisfiable,
|
|
28
|
+
# render_expectation_failed, render_im_a_teapot, render_misdirected_request,
|
|
29
|
+
# render_unprocessable, render_locked, render_failed_dependency,
|
|
30
|
+
# render_too_early, render_upgrade_required, render_precondition_required,
|
|
31
|
+
# render_too_many_requests, render_request_header_fields_too_large,
|
|
32
|
+
# render_unavailable_for_legal_reasons
|
|
17
33
|
#
|
|
18
34
|
# Server error helpers (5xx):
|
|
19
35
|
# render_server_error, render_not_implemented, render_bad_gateway,
|
|
20
|
-
# render_service_unavailable, render_gateway_timeout
|
|
36
|
+
# render_service_unavailable, render_gateway_timeout,
|
|
37
|
+
# render_http_version_not_supported, render_variant_also_negotiates,
|
|
38
|
+
# render_insufficient_storage, render_loop_detected, render_not_extended,
|
|
39
|
+
# render_network_authentication_required
|
|
21
40
|
module ControllerHelpers
|
|
22
41
|
|
|
23
42
|
# =========================================================================
|
|
@@ -29,19 +48,19 @@ module Respondo
|
|
|
29
48
|
# @param data [Object] payload — AR model, collection, Hash, Array, nil
|
|
30
49
|
# @param message [String] human-readable description
|
|
31
50
|
# @param meta [Hash] extra meta fields merged into the meta block
|
|
32
|
-
# @param
|
|
33
|
-
#
|
|
34
|
-
#
|
|
51
|
+
# @param pagination [Hash, nil] pagination hash built by the caller, e.g.
|
|
52
|
+
# { current_page: 1, per_page: 25, total_pages: 4,
|
|
53
|
+
# total_count: 100, next_page: 2, prev_page: nil }
|
|
54
|
+
# Pass nil (default) to omit pagination from meta.
|
|
35
55
|
# @param status [Symbol, Integer] HTTP status (default: :ok / 200)
|
|
36
|
-
def render_success(data: nil, message: nil, meta: {}, code: nil,
|
|
37
|
-
merged_meta
|
|
56
|
+
def render_success(data: nil, message: nil, meta: {}, code: nil, pagination: nil, status: :ok)
|
|
57
|
+
merged_meta = code ? meta.merge(code: code, status: status) : meta
|
|
38
58
|
|
|
39
59
|
payload = ResponseBuilder.new(
|
|
40
60
|
success: true,
|
|
41
61
|
data: data,
|
|
42
62
|
message: message,
|
|
43
63
|
meta: merged_meta,
|
|
44
|
-
pagy: pagy,
|
|
45
64
|
pagination: pagination,
|
|
46
65
|
request: try(:request)
|
|
47
66
|
).build
|
|
@@ -67,46 +86,132 @@ module Respondo
|
|
|
67
86
|
message: message,
|
|
68
87
|
meta: merged_meta,
|
|
69
88
|
errors: extracted_errors,
|
|
70
|
-
pagination: false,
|
|
71
89
|
request: try(:request)
|
|
72
90
|
).build
|
|
73
91
|
|
|
74
92
|
render json: payload, status: status
|
|
75
93
|
end
|
|
76
94
|
|
|
95
|
+
# =========================================================================
|
|
96
|
+
# 1xx Informational helpers
|
|
97
|
+
# NOTE: 1xx responses are protocol-level and don't carry a body in HTTP/1.1.
|
|
98
|
+
# These helpers return a JSON body for API consistency / logging purposes,
|
|
99
|
+
# but most HTTP clients will not receive them as normal responses.
|
|
100
|
+
# =========================================================================
|
|
101
|
+
|
|
102
|
+
# 100 Continue
|
|
103
|
+
def render_continue(message: "Continue", meta: {})
|
|
104
|
+
render_success(data: nil, message: message, meta: meta, code: 100, status: :continue)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# 101 Switching Protocols
|
|
108
|
+
def render_switching_protocols(message: "Switching protocols", meta: {})
|
|
109
|
+
render_success(data: nil, message: message, meta: meta, code: 101, status: :switching_protocols)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# 102 Processing (WebDAV)
|
|
113
|
+
def render_processing(message: "Processing", meta: {})
|
|
114
|
+
render_success(data: nil, message: message, meta: meta, code: 102, status: :processing)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# 103 Early Hints
|
|
118
|
+
def render_early_hints(message: "Early hints", meta: {})
|
|
119
|
+
render_success(data: nil, message: message, meta: meta, code: 103, status: :early_hints)
|
|
120
|
+
end
|
|
121
|
+
|
|
77
122
|
# =========================================================================
|
|
78
123
|
# 2xx Success helpers
|
|
79
124
|
# =========================================================================
|
|
80
125
|
|
|
81
126
|
# 200 OK — alias for render_success with no pagination (single record)
|
|
82
|
-
def render_ok(data: nil, message: nil, meta: {}, pagination:
|
|
83
|
-
render_success(data: data, message: message, meta: meta, pagination: pagination, code:200, status: :ok)
|
|
127
|
+
def render_ok(data: nil, message: nil, meta: {}, pagination: nil)
|
|
128
|
+
render_success(data: data, message: message, meta: meta, pagination: pagination, code: 200, status: :ok)
|
|
84
129
|
end
|
|
85
130
|
|
|
86
131
|
# 201 Created
|
|
87
|
-
def render_created(data: nil, message: "Created successfully", pagination:
|
|
88
|
-
render_success(data: data, message: message, pagination: pagination, code:201, status: :created)
|
|
132
|
+
def render_created(data: nil, message: "Created successfully", meta: {}, pagination: nil)
|
|
133
|
+
render_success(data: data, message: message, meta: meta, pagination: pagination, code: 201, status: :created)
|
|
89
134
|
end
|
|
90
135
|
|
|
91
136
|
# 202 Accepted — async jobs, background processing
|
|
92
|
-
def render_accepted(data: nil, message: "Request accepted and is being processed")
|
|
93
|
-
render_success(data: data, message: message, pagination:
|
|
137
|
+
def render_accepted(data: nil, message: "Request accepted and is being processed", meta: {}, pagination: nil)
|
|
138
|
+
render_success(data: data, message: message, meta: meta, pagination: pagination, code: 202, status: :accepted)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# 203 Non-Authoritative Information — response from a third-party cache/proxy
|
|
142
|
+
def render_non_authoritative(data: nil, message: "Non-authoritative information", meta: {}, pagination: nil)
|
|
143
|
+
render_success(data: data, message: message, meta: meta, pagination: pagination, code: 203, status: :non_authoritative_information)
|
|
94
144
|
end
|
|
95
145
|
|
|
96
146
|
# 204 No Content — deletions, actions with no response body
|
|
97
147
|
# Note: we still return our standard JSON structure for consistency
|
|
98
|
-
def render_no_content(message: "Deleted successfully")
|
|
99
|
-
render_success(data: nil, message: message, pagination:
|
|
148
|
+
def render_no_content(message: "Deleted successfully", meta: {}, pagination: nil)
|
|
149
|
+
render_success(data: nil, message: message, meta: meta, pagination: pagination, code: 204, status: :ok)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# 205 Reset Content — tell the client to reset the document view
|
|
153
|
+
def render_reset_content(message: "Reset content", meta: {}, pagination: nil)
|
|
154
|
+
render_success(data: nil, message: message, meta: meta, pagination: pagination, code: 205, status: :reset_content)
|
|
100
155
|
end
|
|
101
156
|
|
|
102
157
|
# 206 Partial Content — chunked / range responses
|
|
103
|
-
def render_partial_content(data: nil, message: "Partial content returned", meta: {})
|
|
104
|
-
render_success(data: data, message: message, meta: meta, pagination:
|
|
158
|
+
def render_partial_content(data: nil, message: "Partial content returned", meta: {}, pagination: nil)
|
|
159
|
+
render_success(data: data, message: message, meta: meta, pagination: pagination, code: 206, status: :partial_content)
|
|
105
160
|
end
|
|
106
161
|
|
|
107
|
-
# 207 Multi-Status — batch operations with mixed results
|
|
108
|
-
def render_multi_status(data: nil, message: "Multi-status response", meta: {})
|
|
109
|
-
render_success(data: data, message: message, meta: meta, pagination:
|
|
162
|
+
# 207 Multi-Status (WebDAV) — batch operations with mixed results
|
|
163
|
+
def render_multi_status(data: nil, message: "Multi-status response", meta: {}, pagination: nil)
|
|
164
|
+
render_success(data: data, message: message, meta: meta, pagination: pagination, code: 207, status: :multi_status)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# 208 Already Reported (WebDAV) — members already enumerated
|
|
168
|
+
def render_already_reported(data: nil, message: "Already reported", meta: {}, pagination: nil)
|
|
169
|
+
render_success(data: data, message: message, meta: meta, pagination: pagination, code: 208, status: :already_reported)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# 226 IM Used — instance manipulations applied
|
|
173
|
+
def render_im_used(data: nil, message: "IM used", meta: {}, pagination: nil)
|
|
174
|
+
render_success(data: data, message: message, meta: meta, pagination: pagination, code: 226, status: :im_used)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# =========================================================================
|
|
178
|
+
# 3xx Redirect helpers
|
|
179
|
+
# NOTE: Pass the target URL via meta: render_moved_permanently(meta: { redirect_url: new_url })
|
|
180
|
+
# =========================================================================
|
|
181
|
+
|
|
182
|
+
# 300 Multiple Choices
|
|
183
|
+
def render_multiple_choices(data: nil, message: "Multiple choices available", meta: {}, pagination: nil)
|
|
184
|
+
render_success(data: data, message: message, meta: meta, pagination: pagination, code: 300, status: :multiple_choices)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# 301 Moved Permanently
|
|
188
|
+
def render_moved_permanently(message: "Resource has moved permanently", meta: {}, pagination: nil)
|
|
189
|
+
render_success(data: nil, message: message, meta: meta, pagination: pagination, code: 301, status: :moved_permanently)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# 302 Found (temporary redirect)
|
|
193
|
+
def render_found(message: "Resource temporarily located elsewhere", meta: {}, pagination: nil)
|
|
194
|
+
render_success(data: nil, message: message, meta: meta, pagination: pagination, code: 302, status: :found)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# 303 See Other — redirect to another URI with GET
|
|
198
|
+
def render_see_other(message: "See other resource", meta: {}, pagination: nil)
|
|
199
|
+
render_success(data: nil, message: message, meta: meta, pagination: pagination, code: 303, status: :see_other)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# 304 Not Modified — client cache is still valid
|
|
203
|
+
def render_not_modified(message: "Resource not modified", meta: {}, pagination: nil)
|
|
204
|
+
render_success(data: nil, message: message, meta: meta, pagination: pagination, code: 304, status: :not_modified)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# 307 Temporary Redirect — repeat request with same method to new URL
|
|
208
|
+
def render_temporary_redirect(message: "Temporary redirect", meta: {}, pagination: nil)
|
|
209
|
+
render_success(data: nil, message: message, meta: meta, pagination: pagination, code: 307, status: :temporary_redirect)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# 308 Permanent Redirect — like 301 but method must not change
|
|
213
|
+
def render_permanent_redirect(message: "Permanent redirect", meta: {}, pagination: nil)
|
|
214
|
+
render_success(data: nil, message: message, meta: meta, pagination: pagination, code: 308, status: :permanent_redirect)
|
|
110
215
|
end
|
|
111
216
|
|
|
112
217
|
# =========================================================================
|
|
@@ -114,78 +219,148 @@ module Respondo
|
|
|
114
219
|
# =========================================================================
|
|
115
220
|
|
|
116
221
|
# 400 Bad Request — malformed request, invalid params
|
|
117
|
-
def render_bad_request(message: "Bad request", errors: nil,
|
|
118
|
-
render_error(message: message, errors: errors, code:
|
|
222
|
+
def render_bad_request(message: "Bad request", errors: nil, meta: {})
|
|
223
|
+
render_error(message: message, errors: errors, meta: meta, code: 400, status: :bad_request)
|
|
119
224
|
end
|
|
120
225
|
|
|
121
226
|
# 401 Unauthorized — not authenticated
|
|
122
|
-
def render_unauthorized(message: "Unauthorized", errors: nil,
|
|
123
|
-
render_error(message: message, errors: errors, code:
|
|
227
|
+
def render_unauthorized(message: "Unauthorized", errors: nil, meta: {})
|
|
228
|
+
render_error(message: message, errors: errors, meta: meta, code: 401, status: :unauthorized)
|
|
124
229
|
end
|
|
125
230
|
|
|
126
231
|
# 402 Payment Required — paywalled features
|
|
127
|
-
def render_payment_required(message: "Payment required to access this resource", errors: nil,
|
|
128
|
-
render_error(message: message, errors: errors, code:
|
|
232
|
+
def render_payment_required(message: "Payment required to access this resource", errors: nil, meta: {})
|
|
233
|
+
render_error(message: message, errors: errors, meta: meta, code: 402, status: :payment_required)
|
|
129
234
|
end
|
|
130
235
|
|
|
131
236
|
# 403 Forbidden — authenticated but not authorized
|
|
132
|
-
def render_forbidden(message: "You do not have permission to perform this action", errors: nil,
|
|
133
|
-
render_error(message: message, errors: errors, code:
|
|
237
|
+
def render_forbidden(message: "You do not have permission to perform this action", errors: nil, meta: {})
|
|
238
|
+
render_error(message: message, errors: errors, meta: meta, code: 403, status: :forbidden)
|
|
134
239
|
end
|
|
135
240
|
|
|
136
241
|
# 404 Not Found
|
|
137
|
-
def render_not_found(message: "Resource not found", errors: nil,
|
|
138
|
-
render_error(message: message, errors: errors, code:
|
|
242
|
+
def render_not_found(message: "Resource not found", errors: nil, meta: {})
|
|
243
|
+
render_error(message: message, errors: errors, meta: meta, code: 404, status: :not_found)
|
|
139
244
|
end
|
|
140
245
|
|
|
141
246
|
# 405 Method Not Allowed
|
|
142
|
-
def render_method_not_allowed(message: "HTTP method not allowed", errors: nil,
|
|
143
|
-
render_error(message: message, errors: errors, code:
|
|
247
|
+
def render_method_not_allowed(message: "HTTP method not allowed", errors: nil, meta: {})
|
|
248
|
+
render_error(message: message, errors: errors, meta: meta, code: 405, status: :method_not_allowed)
|
|
144
249
|
end
|
|
145
250
|
|
|
146
251
|
# 406 Not Acceptable — client Accept header can't be satisfied
|
|
147
|
-
def render_not_acceptable(message: "Requested format not acceptable", errors: nil,
|
|
148
|
-
render_error(message: message, errors: errors, code:
|
|
252
|
+
def render_not_acceptable(message: "Requested format not acceptable", errors: nil, meta: {})
|
|
253
|
+
render_error(message: message, errors: errors, meta: meta, code: 406, status: :not_acceptable)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# 407 Proxy Authentication Required
|
|
257
|
+
def render_proxy_auth_required(message: "Proxy authentication required", errors: nil, meta: {})
|
|
258
|
+
render_error(message: message, errors: errors, meta: meta, code: 407, status: :proxy_authentication_required)
|
|
149
259
|
end
|
|
150
260
|
|
|
151
261
|
# 408 Request Timeout
|
|
152
|
-
def render_request_timeout(message: "Request timed out", errors: nil,
|
|
153
|
-
render_error(message: message, errors: errors, code:
|
|
262
|
+
def render_request_timeout(message: "Request timed out", errors: nil, meta: {})
|
|
263
|
+
render_error(message: message, errors: errors, meta: meta, code: 408, status: :request_timeout)
|
|
154
264
|
end
|
|
155
265
|
|
|
156
266
|
# 409 Conflict — duplicate record, state conflict
|
|
157
|
-
def render_conflict(message: "Resource conflict", errors: nil,
|
|
158
|
-
render_error(message: message, errors: errors, code:
|
|
267
|
+
def render_conflict(message: "Resource conflict", errors: nil, meta: {})
|
|
268
|
+
render_error(message: message, errors: errors, meta: meta, code: 409, status: :conflict)
|
|
159
269
|
end
|
|
160
270
|
|
|
161
271
|
# 410 Gone — resource permanently deleted
|
|
162
|
-
def render_gone(message: "Resource no longer available", errors: nil,
|
|
163
|
-
render_error(message: message, errors: errors, code:
|
|
272
|
+
def render_gone(message: "Resource no longer available", errors: nil, meta: {})
|
|
273
|
+
render_error(message: message, errors: errors, meta: meta, code: 410, status: :gone)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# 411 Length Required — Content-Length header missing
|
|
277
|
+
def render_length_required(message: "Content-Length header required", errors: nil, meta: {})
|
|
278
|
+
render_error(message: message, errors: errors, meta: meta, code: 411, status: :length_required)
|
|
164
279
|
end
|
|
165
280
|
|
|
166
281
|
# 412 Precondition Failed — conditional request failed
|
|
167
|
-
def render_precondition_failed(message: "Precondition failed", errors: nil,
|
|
168
|
-
render_error(message: message, errors: errors, code:
|
|
282
|
+
def render_precondition_failed(message: "Precondition failed", errors: nil, meta: {})
|
|
283
|
+
render_error(message: message, errors: errors, meta: meta, code: 412, status: :precondition_failed)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# 413 Payload Too Large — request body exceeds server limit
|
|
287
|
+
def render_payload_too_large(message: "Payload too large", errors: nil, meta: {})
|
|
288
|
+
render_error(message: message, errors: errors, meta: meta, code: 413, status: :payload_too_large)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# 414 URI Too Long — request URI exceeds server limit
|
|
292
|
+
def render_uri_too_long(message: "URI too long", errors: nil, meta: {})
|
|
293
|
+
render_error(message: message, errors: errors, meta: meta, code: 414, status: :uri_too_long)
|
|
169
294
|
end
|
|
170
295
|
|
|
171
296
|
# 415 Unsupported Media Type — wrong Content-Type header
|
|
172
|
-
def render_unsupported_media_type(message: "Unsupported media type", errors: nil,
|
|
173
|
-
render_error(message: message, errors: errors, code:
|
|
297
|
+
def render_unsupported_media_type(message: "Unsupported media type", errors: nil, meta: {})
|
|
298
|
+
render_error(message: message, errors: errors, meta: meta, code: 415, status: :unsupported_media_type)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# 416 Range Not Satisfiable — Range header cannot be fulfilled
|
|
302
|
+
def render_range_not_satisfiable(message: "Range not satisfiable", errors: nil, meta: {})
|
|
303
|
+
render_error(message: message, errors: errors, meta: meta, code: 416, status: :range_not_satisfiable)
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# 417 Expectation Failed — Expect header cannot be met
|
|
307
|
+
def render_expectation_failed(message: "Expectation failed", errors: nil, meta: {})
|
|
308
|
+
render_error(message: message, errors: errors, meta: meta, code: 417, status: :expectation_failed)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# 418 I'm a Teapot — RFC 2324
|
|
312
|
+
def render_im_a_teapot(message: "I'm a teapot", errors: nil, meta: {})
|
|
313
|
+
render_error(message: message, errors: errors, meta: meta, code: 418, status: :im_a_teapot)
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# 421 Misdirected Request — request sent to wrong server
|
|
317
|
+
def render_misdirected_request(message: "Misdirected request", errors: nil, meta: {})
|
|
318
|
+
render_error(message: message, errors: errors, meta: meta, code: 421, status: :misdirected_request)
|
|
174
319
|
end
|
|
175
320
|
|
|
176
321
|
# 422 Unprocessable Entity — validation errors (most common for APIs)
|
|
177
|
-
def render_unprocessable(message: "Validation failed", errors: nil,
|
|
178
|
-
render_error(message: message, errors: errors, code:
|
|
322
|
+
def render_unprocessable(message: "Validation failed", errors: nil, meta: {})
|
|
323
|
+
render_error(message: message, errors: errors, meta: meta, code: 422, status: :unprocessable_content)
|
|
179
324
|
end
|
|
180
325
|
|
|
181
326
|
# 423 Locked — resource is locked
|
|
182
|
-
def render_locked(message: "Resource is locked", errors: nil,
|
|
183
|
-
render_error(message: message, errors: errors, code:
|
|
327
|
+
def render_locked(message: "Resource is locked", errors: nil, meta: {})
|
|
328
|
+
render_error(message: message, errors: errors, meta: meta, code: 423, status: :locked)
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# 424 Failed Dependency (WebDAV) — previous request failed
|
|
332
|
+
def render_failed_dependency(message: "Failed dependency", errors: nil, meta: {})
|
|
333
|
+
render_error(message: message, errors: errors, meta: meta, code: 424, status: :failed_dependency)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# 425 Too Early — server unwilling to risk processing replayed request
|
|
337
|
+
def render_too_early(message: "Too early", errors: nil, meta: {})
|
|
338
|
+
render_error(message: message, errors: errors, meta: meta, code: 425, status: :too_early)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# 426 Upgrade Required — client must switch protocols
|
|
342
|
+
def render_upgrade_required(message: "Upgrade required", errors: nil, meta: {})
|
|
343
|
+
render_error(message: message, errors: errors, meta: meta, code: 426, status: :upgrade_required)
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# 428 Precondition Required — request must be conditional
|
|
347
|
+
def render_precondition_required(message: "Precondition required", errors: nil, meta: {})
|
|
348
|
+
render_error(message: message, errors: errors, meta: meta, code: 428, status: :precondition_required)
|
|
184
349
|
end
|
|
185
350
|
|
|
186
351
|
# 429 Too Many Requests — rate limiting
|
|
187
|
-
def render_too_many_requests(message: "Too many requests. Please slow down.", errors: nil,
|
|
188
|
-
render_error(message: message, errors: errors, code:
|
|
352
|
+
def render_too_many_requests(message: "Too many requests. Please slow down.", errors: nil, meta: {})
|
|
353
|
+
render_error(message: message, errors: errors, meta: meta, code: 429, status: :too_many_requests)
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# 431 Request Header Fields Too Large
|
|
357
|
+
def render_request_header_fields_too_large(message: "Request header fields too large", errors: nil, meta: {})
|
|
358
|
+
render_error(message: message, errors: errors, meta: meta, code: 431, status: :request_header_fields_too_large)
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# 451 Unavailable for Legal Reasons — censored/DMCA etc.
|
|
362
|
+
def render_unavailable_for_legal_reasons(message: "Unavailable for legal reasons", errors: nil, meta: {})
|
|
363
|
+
render_error(message: message, errors: errors, meta: meta, code: 451, status: :unavailable_for_legal_reasons)
|
|
189
364
|
end
|
|
190
365
|
|
|
191
366
|
# =========================================================================
|
|
@@ -193,28 +368,58 @@ module Respondo
|
|
|
193
368
|
# =========================================================================
|
|
194
369
|
|
|
195
370
|
# 500 Internal Server Error
|
|
196
|
-
def render_server_error(message: "An unexpected error occurred", errors: nil,
|
|
197
|
-
render_error(message: message, errors: errors, code:
|
|
371
|
+
def render_server_error(message: "An unexpected error occurred", errors: nil, meta: {})
|
|
372
|
+
render_error(message: message, errors: errors, meta: meta, code: 500, status: :internal_server_error)
|
|
198
373
|
end
|
|
199
374
|
|
|
200
375
|
# 501 Not Implemented — feature not built yet
|
|
201
|
-
def render_not_implemented(message: "This feature is not yet implemented", errors: nil,
|
|
202
|
-
render_error(message: message, errors: errors, code:
|
|
376
|
+
def render_not_implemented(message: "This feature is not yet implemented", errors: nil, meta: {})
|
|
377
|
+
render_error(message: message, errors: errors, meta: meta, code: 501, status: :not_implemented)
|
|
203
378
|
end
|
|
204
379
|
|
|
205
380
|
# 502 Bad Gateway — upstream service failed
|
|
206
|
-
def render_bad_gateway(message: "Bad gateway — upstream service error", errors: nil,
|
|
207
|
-
render_error(message: message, errors: errors, code:
|
|
381
|
+
def render_bad_gateway(message: "Bad gateway — upstream service error", errors: nil, meta: {})
|
|
382
|
+
render_error(message: message, errors: errors, meta: meta, code: 502, status: :bad_gateway)
|
|
208
383
|
end
|
|
209
384
|
|
|
210
385
|
# 503 Service Unavailable — maintenance, overloaded
|
|
211
|
-
def render_service_unavailable(message: "Service temporarily unavailable", errors: nil,
|
|
212
|
-
render_error(message: message, errors: errors, code:
|
|
386
|
+
def render_service_unavailable(message: "Service temporarily unavailable", errors: nil, meta: {})
|
|
387
|
+
render_error(message: message, errors: errors, meta: meta, code: 503, status: :service_unavailable)
|
|
213
388
|
end
|
|
214
389
|
|
|
215
390
|
# 504 Gateway Timeout — upstream service timed out
|
|
216
|
-
def render_gateway_timeout(message: "Gateway timeout — upstream service did not respond", errors: nil,
|
|
217
|
-
render_error(message: message, errors: errors, code:
|
|
391
|
+
def render_gateway_timeout(message: "Gateway timeout — upstream service did not respond", errors: nil, meta: {})
|
|
392
|
+
render_error(message: message, errors: errors, meta: meta, code: 504, status: :gateway_timeout)
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# 505 HTTP Version Not Supported
|
|
396
|
+
def render_http_version_not_supported(message: "HTTP version not supported", errors: nil, meta: {})
|
|
397
|
+
render_error(message: message, errors: errors, meta: meta, code: 505, status: :http_version_not_supported)
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# 506 Variant Also Negotiates — server configuration error
|
|
401
|
+
def render_variant_also_negotiates(message: "Variant also negotiates", errors: nil, meta: {})
|
|
402
|
+
render_error(message: message, errors: errors, meta: meta, code: 506, status: :variant_also_negotiates)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# 507 Insufficient Storage (WebDAV)
|
|
406
|
+
def render_insufficient_storage(message: "Insufficient storage", errors: nil, meta: {})
|
|
407
|
+
render_error(message: message, errors: errors, meta: meta, code: 507, status: :insufficient_storage)
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# 508 Loop Detected (WebDAV)
|
|
411
|
+
def render_loop_detected(message: "Loop detected", errors: nil, meta: {})
|
|
412
|
+
render_error(message: message, errors: errors, meta: meta, code: 508, status: :loop_detected)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# 510 Not Extended — further extensions needed
|
|
416
|
+
def render_not_extended(message: "Not extended", errors: nil, meta: {})
|
|
417
|
+
render_error(message: message, errors: errors, meta: meta, code: 510, status: :not_extended)
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
# 511 Network Authentication Required — must authenticate to access network
|
|
421
|
+
def render_network_authentication_required(message: "Network authentication required", errors: nil, meta: {})
|
|
422
|
+
render_error(message: message, errors: errors, meta: meta, code: 511, status: :network_authentication_required)
|
|
218
423
|
end
|
|
219
424
|
|
|
220
425
|
private
|