jsend_wrapper-rails 0.1.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 +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
|