jsend_wrapper-rails 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +306 -0
- data/Rakefile +65 -0
- data/lib/jsend_wrapper/rails/railtie.rb +58 -0
- data/lib/jsend_wrapper/rails/render_option.rb +76 -0
- data/lib/jsend_wrapper/rails/template_handler.rb +43 -0
- data/lib/jsend_wrapper/renderers/error_renderer.rb +67 -0
- data/lib/jsend_wrapper/renderers/fail_renderer.rb +32 -0
- data/lib/jsend_wrapper/renderers/renderer.rb +30 -0
- data/lib/jsend_wrapper/renderers/success_renderer.rb +32 -0
- data/lib/jsend_wrapper/renderers.rb +18 -0
- data/lib/jsend_wrapper-rails.rb +20 -0
- metadata +127 -0
data/README.md
ADDED
@@ -0,0 +1,306 @@
|
|
1
|
+
# Rails JSend Wrapper
|
2
|
+
|
3
|
+
## Usage
|
4
|
+
|
5
|
+
Add the following lines to your Gemfile:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'jsend_wrapper-rails'
|
9
|
+
gem 'jbuilder' # optional
|
10
|
+
```
|
11
|
+
|
12
|
+
### render jsend: ...
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
# Success
|
16
|
+
render jsend: @object
|
17
|
+
render jsend: { success: @object }
|
18
|
+
|
19
|
+
# Fail
|
20
|
+
render jsend: { fail: 'too bad' }
|
21
|
+
|
22
|
+
# Error
|
23
|
+
render jsend: { error: 'too bad' }
|
24
|
+
render jsend: { error: 'too bad', code: 123 }
|
25
|
+
render jsend: { error: 'too bad', data: @object }
|
26
|
+
render jsend: { error: 'too bad', code: 123, data: @object }
|
27
|
+
```
|
28
|
+
|
29
|
+
The elements `code` and `data` are optional for JSend Error containers. If you
|
30
|
+
leave them out, they will be absent from the rendered JSON. Note the differences
|
31
|
+
in these two examples:
|
32
|
+
|
33
|
+
`render jsend: {error: 'too bad'}`
|
34
|
+
|
35
|
+
**Result**:
|
36
|
+
```json
|
37
|
+
{
|
38
|
+
"status": "error",
|
39
|
+
"message": "too bad"
|
40
|
+
}
|
41
|
+
```
|
42
|
+
|
43
|
+
`render jsend: {error: 'too bad', data: nil}`
|
44
|
+
|
45
|
+
**Result**:
|
46
|
+
```json
|
47
|
+
{
|
48
|
+
"status": "error",
|
49
|
+
"message": "too bad",
|
50
|
+
"data": null
|
51
|
+
}
|
52
|
+
```
|
53
|
+
|
54
|
+
|
55
|
+
### Templates (optional)
|
56
|
+
|
57
|
+
If [JBuilder](https://rubygems.org/gems/jbuilder) is available, you can create
|
58
|
+
view files with a `.jsend` (example: `app/views/posts/show.json.jsend`)
|
59
|
+
extension. These views are rendered by `Jbuilder`, exactly as if they were
|
60
|
+
named with a `.jbuilder` extension instead. These views will be wrapped in a
|
61
|
+
JSend Success container.
|
62
|
+
|
63
|
+
**Example**: `app/views/posts/show.json.jsend`
|
64
|
+
```ruby
|
65
|
+
json.title 'The Pragmatic Programmer'
|
66
|
+
json.year 1999
|
67
|
+
```
|
68
|
+
|
69
|
+
**Result**:
|
70
|
+
```json
|
71
|
+
{
|
72
|
+
"status": "success",
|
73
|
+
"data": {
|
74
|
+
"title": "The Pragmatic Programmer",
|
75
|
+
"year": 1999
|
76
|
+
}
|
77
|
+
}
|
78
|
+
```
|
79
|
+
|
80
|
+
### Tips
|
81
|
+
|
82
|
+
#### Handling Errors
|
83
|
+
|
84
|
+
You can use `rescue_from` to automatically handle errors:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
rescue_from ActiveRecord::RecordNotFound do
|
88
|
+
render status: :not_found, jsend: {
|
89
|
+
error: 'record not found', code: 404, data: { id: params[:id] } }
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
**Example**: `GET /posts/1234.json`:
|
94
|
+
```json
|
95
|
+
{
|
96
|
+
"status": "error",
|
97
|
+
"message": "record not found",
|
98
|
+
"code": 404,
|
99
|
+
"data": {
|
100
|
+
"id": "1234"
|
101
|
+
}
|
102
|
+
}
|
103
|
+
```
|
104
|
+
|
105
|
+
## JSend Spec
|
106
|
+
|
107
|
+
* **What?** - Put simply, JSend is a specification that lays down some rules
|
108
|
+
for how [JSON](http://json.org) responses from web servers should be
|
109
|
+
formatted. JSend focuses on application-level (as opposed to protocol- or
|
110
|
+
transport-level) messaging which makes it ideal for use in
|
111
|
+
[REST](http://en.wikipedia.org/wiki/Representational_State_Transfer)-style
|
112
|
+
applications and APIs.
|
113
|
+
* **Why?** - There are lots of web services out there providing JSON data,
|
114
|
+
and each has its own way of formatting responses. Also, developers writing
|
115
|
+
for JavaScript front-ends continually re-invent the wheel on communicating
|
116
|
+
data from their servers. While there are many common patterns for
|
117
|
+
structuring this data, there is no consistency in things like naming or types
|
118
|
+
of responses. Also, this helps promote happiness and unity between backend
|
119
|
+
developers and frontend designers, as everyone can come to expect a common
|
120
|
+
approach to interacting with one another.
|
121
|
+
* **Hold on now, aren't there already specs for this kind of thing?** -
|
122
|
+
Well... no. While there are a few handy specifications for dealing with JSON
|
123
|
+
data, most notably [Douglas Crockford](http://www.crockford.com/)'s
|
124
|
+
[JSONRequest](http://www.json.org/JSONRequest.html) proposal, there's nothing
|
125
|
+
to address the problems of general application-level messaging. More on this
|
126
|
+
later.
|
127
|
+
* **(Why) Should I care?** - If you're a library or framework developer, this
|
128
|
+
gives you a consistent format which your users are more likely to already be
|
129
|
+
familiar with, which means they'll already know how to consume and interact
|
130
|
+
with your code. If you're a web app developer, you won't have to think about
|
131
|
+
how to structure the JSON data in your application, and you'll have existing
|
132
|
+
reference implementations to get you up and running quickly.
|
133
|
+
* **Discuss** - [Mailing list](http://lists.omniti.com/mailman/listinfo/jsend-users)
|
134
|
+
|
135
|
+
### So how's it work?
|
136
|
+
|
137
|
+
A basic JSend-compliant response is as simple as this:
|
138
|
+
```json
|
139
|
+
{
|
140
|
+
"status": "success",
|
141
|
+
"data": {
|
142
|
+
"post": {
|
143
|
+
"id": 1,
|
144
|
+
"title": "A blog post",
|
145
|
+
"body": "Some useful content"
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
```
|
150
|
+
|
151
|
+
When setting up a JSON API, you'll have all kinds of different types of calls
|
152
|
+
and responses. JSend separates responses into some basic types, and defines
|
153
|
+
required and optional keys for each type:
|
154
|
+
|
155
|
+
<table>
|
156
|
+
<thead>
|
157
|
+
<tr>
|
158
|
+
<th>Type</th>
|
159
|
+
<th>Description</th>
|
160
|
+
<th>Required Keys</th>
|
161
|
+
<th>Optional Keys</th>
|
162
|
+
</tr>
|
163
|
+
</thead>
|
164
|
+
<tbody>
|
165
|
+
<tr>
|
166
|
+
<td>success</td>
|
167
|
+
<td>All went well, and (usually) some data was returned.</td>
|
168
|
+
<td>status, data</td>
|
169
|
+
<td></td>
|
170
|
+
</tr>
|
171
|
+
<tr>
|
172
|
+
<td>fail</td>
|
173
|
+
<td>
|
174
|
+
There was a problem with the data submitted, or some pre-condition of
|
175
|
+
the API call wasn't satisfied.
|
176
|
+
</td>
|
177
|
+
<td>status, message</td>
|
178
|
+
<td></td>
|
179
|
+
</tr>
|
180
|
+
<tr>
|
181
|
+
<td>error</td>
|
182
|
+
<td>
|
183
|
+
An error occurred in processing the request, i.e. an exception was
|
184
|
+
thrown.
|
185
|
+
</td>
|
186
|
+
<td>status, message</td>
|
187
|
+
<td>code, data</td>
|
188
|
+
</tr>
|
189
|
+
</tbody>
|
190
|
+
</table>
|
191
|
+
|
192
|
+
### Example response types
|
193
|
+
|
194
|
+
**Success**: When an API call is successful, the JSend object is used as a
|
195
|
+
simple envelope for the results, using the {{{data}}} key, as in the following:
|
196
|
+
|
197
|
+
**`GET /posts.json`:**
|
198
|
+
```json
|
199
|
+
{
|
200
|
+
"status": "success",
|
201
|
+
"data": [
|
202
|
+
{
|
203
|
+
"id": 1,
|
204
|
+
"title": "A blog post",
|
205
|
+
"body": "Some useful content"
|
206
|
+
},
|
207
|
+
{
|
208
|
+
"id": 2,
|
209
|
+
"title": "Another blog post",
|
210
|
+
"body": "More content"
|
211
|
+
},
|
212
|
+
]
|
213
|
+
}
|
214
|
+
```
|
215
|
+
|
216
|
+
**`GET /posts/2.json`:**
|
217
|
+
```json
|
218
|
+
{
|
219
|
+
"status": "success",
|
220
|
+
"data": {
|
221
|
+
"id": 2,
|
222
|
+
"title": "Another blog post",
|
223
|
+
"body": "More content"
|
224
|
+
}
|
225
|
+
}
|
226
|
+
```
|
227
|
+
|
228
|
+
**`DELETE /posts/2.json`:**
|
229
|
+
```json
|
230
|
+
{
|
231
|
+
"status": "success",
|
232
|
+
"data": null
|
233
|
+
}
|
234
|
+
```
|
235
|
+
|
236
|
+
Required keys:
|
237
|
+
* status: Should always be set to "success".
|
238
|
+
* data: Acts as the wrapper for any data returned by the API call. If the call
|
239
|
+
returns no data (as in the last example), data should be set to null.
|
240
|
+
|
241
|
+
**Fail**: When an API call is rejected due to invalid data or call conditions,
|
242
|
+
the JSend object's data key contains an object explaining what went wrong,
|
243
|
+
typically a hash of validation errors. For example:
|
244
|
+
|
245
|
+
**`POST /posts.json`** (with data `body: "Trying to creating a blog post"`):
|
246
|
+
```json
|
247
|
+
{
|
248
|
+
"status": "fail",
|
249
|
+
"data": {
|
250
|
+
"title": "A title is required"
|
251
|
+
}
|
252
|
+
}
|
253
|
+
```
|
254
|
+
|
255
|
+
Required keys:
|
256
|
+
* status: Should always be set to "fail".
|
257
|
+
* data: Again, provides the wrapper for the details of why the request failed.
|
258
|
+
If the reasons for failure correspond to `POST` values, the response
|
259
|
+
object's keys *should* correspond to those `POST` values.
|
260
|
+
|
261
|
+
**Error**: When an API call fails due to an error on the server. For example:
|
262
|
+
|
263
|
+
**`GET /posts.json`**:
|
264
|
+
```json
|
265
|
+
{
|
266
|
+
"status" : "error",
|
267
|
+
"message" : "A title is required"
|
268
|
+
}
|
269
|
+
```
|
270
|
+
|
271
|
+
Required keys:
|
272
|
+
* status: Should always be set to "error".
|
273
|
+
* message: A meaningful, end-user-readable (or at the least log-worthy)
|
274
|
+
message, explaining what went wrong.
|
275
|
+
|
276
|
+
Optional keys:
|
277
|
+
* code: A numeric code corresponding to the error, if applicable
|
278
|
+
* data: A generic container for any other information about the error, i.e. the
|
279
|
+
conditions that caused the error, stack traces, etc.
|
280
|
+
|
281
|
+
### Whither HTTP?
|
282
|
+
|
283
|
+
But wait, you ask, doesn't HTTP already provide a way to communicate response
|
284
|
+
statuses? Why yes, astute reader, it does. So how does the notion of
|
285
|
+
indicating response status in the message body fit within the context of HTTP?
|
286
|
+
Two things:
|
287
|
+
* The official HTTP spec has 41 status codes, and there are many
|
288
|
+
interpretations on how to use each one. JSend, on the other hand, defines a
|
289
|
+
more constrained set of status codes, specifically related to handling JSON
|
290
|
+
traffic in the context of a dynamic web UI.
|
291
|
+
* The spec is meant to be as small, constrained, and generally-applicable as
|
292
|
+
possible. As such, it has to be somewhat self-contained. A common pattern
|
293
|
+
for implementing JSON services is to load a JavaScript file which passes a
|
294
|
+
JSON block into a user-specified callback. JSON-over-XHR handling in many
|
295
|
+
JavaScript frameworks follows similar patterns. As such, the end-user
|
296
|
+
(developer) never has a chance to access the HTTP response itself.
|
297
|
+
|
298
|
+
So where does that leave us? Accounting for deficiencies in the status quo does
|
299
|
+
not negate the usefulness of HTTP compliance. Therefore it is advised that
|
300
|
+
server-side developers use both: provide a JSend response body, and whatever
|
301
|
+
HTTP header(s) are most appropriate to the corresponding body.
|
302
|
+
|
303
|
+
### License
|
304
|
+
|
305
|
+
The JSend specification (this page) is covered under a
|
306
|
+
[License modified BSD License](http://labs.omniti.com/labs/jsend/wiki/License)
|
data/Rakefile
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# jsend_wrapper-rails: Wrap JSON views in JSend containers
|
2
|
+
# Copyright (C) 2014 Jon Sangster
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
require 'rubygems'
|
17
|
+
require 'bundler'
|
18
|
+
require 'rake'
|
19
|
+
require 'jeweler'
|
20
|
+
|
21
|
+
require_relative 'lib/jsend_wrapper/version'
|
22
|
+
|
23
|
+
begin
|
24
|
+
Bundler.setup :default, :development
|
25
|
+
rescue Bundler::BundlerError => e
|
26
|
+
$stderr.puts e.message
|
27
|
+
$stderr.puts 'Run `bundle install` to install missing gems'
|
28
|
+
exit e.status_code
|
29
|
+
end
|
30
|
+
|
31
|
+
Jeweler::Tasks.new do |gem|
|
32
|
+
gem.name = 'jsend_wrapper-rails'
|
33
|
+
gem.version = JsendWrapper::Version.to_s
|
34
|
+
gem.homepage = 'http://github.com/sangster/jsend_wrapper-rails'
|
35
|
+
gem.license = 'GPL 3'
|
36
|
+
gem.summary = 'Wraps JSON in a JSend envelope'
|
37
|
+
gem.description = <<-EOF.strip.gsub /\s+/, ' '
|
38
|
+
Some description here.
|
39
|
+
EOF
|
40
|
+
gem.email = 'jon@ertt.ca'
|
41
|
+
gem.authors = ['Jon Sangster']
|
42
|
+
|
43
|
+
gem.files = Dir['{lib}/**/*', 'Rakefile', 'README.md', 'LICENSE']
|
44
|
+
gem.files.exclude 'lib/jsend_wrapper/version.rb'
|
45
|
+
end
|
46
|
+
|
47
|
+
Jeweler::RubygemsDotOrgTasks.new
|
48
|
+
|
49
|
+
task :pry do
|
50
|
+
exec 'pry --gem'
|
51
|
+
end
|
52
|
+
|
53
|
+
task bump: ['bump:patch']
|
54
|
+
namespace :bump do
|
55
|
+
[:major, :minor, :patch].each do |part|
|
56
|
+
bumper = JsendWrapper::Version::Bumper.new part
|
57
|
+
desc "Bump the version to #{bumper}"
|
58
|
+
task(part) { bumper.bump }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# RSpec
|
63
|
+
require 'rspec/core/rake_task'
|
64
|
+
RSpec::Core::RakeTask.new :spec
|
65
|
+
task default: :spec
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# jsend_wrapper-rails: Wrap JSON views in JSend containers
|
2
|
+
# Copyright (C) 2014 Jon Sangster
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
require 'rails/railtie'
|
17
|
+
|
18
|
+
module JsendWrapper
|
19
|
+
module Rails
|
20
|
+
class Railtie < ::Rails::Railtie
|
21
|
+
initializer 'jsend_wrapper-rails.initialization' do
|
22
|
+
if JsendWrapper::Rails.jbuilder_available?
|
23
|
+
JsendWrapper::Rails.install_template
|
24
|
+
end
|
25
|
+
JsendWrapper::Rails.install_render_option
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
#@return [Boolean] true if the {Jbuilder} gem is available
|
31
|
+
def self.jbuilder_available?
|
32
|
+
require 'jbuilder'
|
33
|
+
true
|
34
|
+
rescue LoadError
|
35
|
+
STDERR.puts 'WARN: Please include the "jbuilder" gem for .jsend templates'
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
# Install a "template handler" for .jsend view files. These files will be
|
40
|
+
# processed with {Jbuilder}, just like .jbuilder view files, but the result
|
41
|
+
# will be wrapped in a "success" JSend wrapper.
|
42
|
+
def self.install_template
|
43
|
+
ActionView::Template.register_template_handler \
|
44
|
+
:jsend, JsendWrapper::Rails::TemplateHandler
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
# Adds the "jsend:" option to {ActiveController::Base#render}
|
49
|
+
def self.install_render_option
|
50
|
+
require_relative 'render_option'
|
51
|
+
|
52
|
+
ActionController::Renderers.add :jsend do |value, _|
|
53
|
+
self.content_type ||= Mime::JSON
|
54
|
+
RenderOption.new(value).render
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# jsend_wrapper-rails: Wrap JSON views in JSend containers
|
2
|
+
# Copyright (C) 2014 Jon Sangster
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
require_relative '../renderers'
|
17
|
+
|
18
|
+
module JsendWrapper
|
19
|
+
# Parses the "render jsend: {...}" command. Valid forms:
|
20
|
+
class RenderOption
|
21
|
+
VALID_TYPES = [:success, :fail, :error]
|
22
|
+
VALID_OPTIONS = [:data, :code, :message]
|
23
|
+
VALID_KEYS = VALID_TYPES + VALID_OPTIONS
|
24
|
+
|
25
|
+
#@param obj [Hash,Object] Examples:
|
26
|
+
# render jsend: @object
|
27
|
+
# render jsend: {success: @object}
|
28
|
+
# render jsend: {fail: @object}
|
29
|
+
# render jsend: {error: @object}
|
30
|
+
# render jsend: {error: @object, code: 123}
|
31
|
+
# render jsend: {error: @object, data: @another_object}
|
32
|
+
# render jsend: {error: @object, code: 123, data: @another_object}
|
33
|
+
def initialize(obj)
|
34
|
+
@hash = normalize obj
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
#@return [String] A string containing the rendered JSON
|
39
|
+
def render
|
40
|
+
renderer.call
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
#@return [Renderer] One of {SuccessRenderer}, {FailRenderer}, or
|
45
|
+
# {ErrorRenderer}
|
46
|
+
def renderer
|
47
|
+
@renderer ||=
|
48
|
+
if @hash.key? :success
|
49
|
+
SuccessRenderer.new @hash[:success]
|
50
|
+
elsif @hash.key? :fail
|
51
|
+
FailRenderer.new @hash[:fail]
|
52
|
+
elsif @hash.key? :error
|
53
|
+
ErrorRenderer.new @hash[:error], @hash.slice(:code, :data)
|
54
|
+
else
|
55
|
+
raise 'render jsend:{...} must include "success:", "fail:", or "error:"'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
|
63
|
+
def normalize(obj)
|
64
|
+
if Hash === obj && jsend_hash?(obj)
|
65
|
+
obj
|
66
|
+
else
|
67
|
+
{success: obj}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def jsend_hash?(hash)
|
73
|
+
hash.keys.all? { |key| VALID_KEYS.include? key }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# jsend_wrapper-rails: Wrap JSON views in JSend containers
|
2
|
+
# Copyright (C) 2014 Jon Sangster
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
module JsendWrapper
|
17
|
+
module Rails
|
18
|
+
class TemplateHandler
|
19
|
+
def self.call(template)
|
20
|
+
json_handler = ActionView::Template.registered_template_handler :jbuilder
|
21
|
+
json = json_handler.call template
|
22
|
+
|
23
|
+
<<-RUBY
|
24
|
+
content = instance_eval #{json.inspect}
|
25
|
+
JsendWrapper::Handlers::Success.new(self).render content
|
26
|
+
RUBY
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
#@param view [ActiveView::Base]
|
31
|
+
def initialize(view)
|
32
|
+
@view = view
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
#@param json [String]
|
37
|
+
def render(json, *)
|
38
|
+
json = 'null' if !json || json.empty?
|
39
|
+
%[{"status":"success","data":#{json}}]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# jsend_wrapper-rails: Wrap JSON views in JSend containers
|
2
|
+
# Copyright (C) 2014 Jon Sangster
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
require_relative 'renderer'
|
17
|
+
|
18
|
+
module JsendWrapper
|
19
|
+
# Wraps the given message in a JSend Error. JSend Errors have two required
|
20
|
+
# elements (status, message) and two optional elements (code, data).
|
21
|
+
class ErrorRenderer < Renderer
|
22
|
+
attr_accessor :message, :has_code, :code, :has_data, :data
|
23
|
+
|
24
|
+
alias_method :code?, :has_code
|
25
|
+
alias_method :data?, :has_data
|
26
|
+
|
27
|
+
#@param message [#to_s]
|
28
|
+
#@param optional [Hash] the optional elements
|
29
|
+
#@option optional [#to_i] :code a numeric code representing the error
|
30
|
+
#@option optional [Object] :data a generic container for any other
|
31
|
+
# information about the error
|
32
|
+
def initialize(message, optional)
|
33
|
+
self.message = message.to_s
|
34
|
+
self.has_code = optional.key? :code
|
35
|
+
self.has_data = optional.key? :data
|
36
|
+
|
37
|
+
self.code = parse_code optional[:code] if code?
|
38
|
+
self.data = optional[:data] if data?
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
#@return [String] the rendered JSON
|
43
|
+
def call
|
44
|
+
%[{"status":"error","message":#{message.to_json}#{optional}}]
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
|
51
|
+
def parse_code(code)
|
52
|
+
if code.respond_to? :to_i
|
53
|
+
code.to_i
|
54
|
+
else
|
55
|
+
raise '"code" must respond to #to_i'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def optional
|
61
|
+
''.tap do |json|
|
62
|
+
json << ',"code":' << code.to_s if code?
|
63
|
+
json << ',"data":' << json_string(data) if data?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# jsend_wrapper-rails: Wrap JSON views in JSend containers
|
2
|
+
# Copyright (C) 2014 Jon Sangster
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
require_relative 'renderer'
|
17
|
+
|
18
|
+
module JsendWrapper
|
19
|
+
# Wraps the given message in a JSend Failure. JSend Failures have two required
|
20
|
+
# elements (status, data).
|
21
|
+
class FailRenderer < Renderer
|
22
|
+
attr_accessor :data
|
23
|
+
|
24
|
+
def initialize(obj)
|
25
|
+
self.data = obj
|
26
|
+
end
|
27
|
+
|
28
|
+
def call
|
29
|
+
%[{"status":"fail","data":#{json_string data}}]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# jsend_wrapper-rails: Wrap JSON views in JSend containers
|
2
|
+
# Copyright (C) 2014 Jon Sangster
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
module JsendWrapper
|
17
|
+
class Renderer
|
18
|
+
protected
|
19
|
+
|
20
|
+
def json_string(obj)
|
21
|
+
if obj.respond_to? :to_json
|
22
|
+
obj.to_json
|
23
|
+
elsif obj.nil?
|
24
|
+
'null'
|
25
|
+
else
|
26
|
+
obj.to_s.to_json
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|