rack-jsonr 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +21 -0
- data/Gemfile +2 -0
- data/README.md +97 -0
- data/Rakefile +16 -0
- data/lib/rack/jsonr.rb +2 -0
- data/lib/rack/jsonr/jsonr.rb +68 -0
- data/lib/rack/jsonr/version.rb +3 -0
- data/rack-jsonr.gemspec +21 -0
- metadata +67 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MDA2OThmZDYxODcxMjA3ZjQzMjc0YzJjMzhjMDdkYmNmM2NhZjk1OQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ODE2M2M2ZTgzM2I0MjNjMjRlOTgxZGI0Mjk4MTc0MDUzNTUxOWRkZg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ODk0ZmU3YWFiZmViMDI2YTVhYTM4NjNkMDNlNjk5MjhiOGRhY2NiNWMzNDdj
|
10
|
+
OTg4MmNiOTc0NDliYWEyOWM0YjE2ZDJjNDMxMDVmNzg2Y2JkZDMzMmI5ZmNl
|
11
|
+
NGM5MWFlYjdmNGMyNGM2MDUxYjYwYmViNmU1MDZmOGVhODY5NGE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZTJjYTFkNjNkMzFiNjYwZGQ4YWUxMTc3NDZlYjBjZDRjOTlmMjIyMjA3YTBj
|
14
|
+
ZjZkN2U1MTJkYmM5NDBkYjljNDJiYzFlNzU4NzZkYmE2MTA1Y2JiYmZkMDcy
|
15
|
+
MGJkYjMxZDNmODZhM2FhNGZiMzg5NWM4NzVlMDdkZjk5MDJkNDM=
|
data/.gitignore
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
coverage
|
6
|
+
InstalledFiles
|
7
|
+
lib/bundler/man
|
8
|
+
pkg
|
9
|
+
rdoc
|
10
|
+
spec/reports
|
11
|
+
test/tmp
|
12
|
+
test/version_tmp
|
13
|
+
tmp
|
14
|
+
|
15
|
+
# YARD artifacts
|
16
|
+
.yardoc
|
17
|
+
_yardoc
|
18
|
+
doc/
|
19
|
+
.DS_Store
|
20
|
+
.idea/
|
21
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
rack-jsonr
|
2
|
+
===========
|
3
|
+
|
4
|
+
A Rack middleware for delivering JSONR (JSON as a Resource). With JSONR you can use get, post, put, and delete verbs, as
|
5
|
+
well as access the http status, response headers, and the json body, even if there are errors.
|
6
|
+
|
7
|
+
## Setting Up JSONR
|
8
|
+
|
9
|
+
Install the gem:
|
10
|
+
|
11
|
+
gem install rack-jsonr
|
12
|
+
|
13
|
+
In your Gemfile:
|
14
|
+
|
15
|
+
gem 'rack-jsonr', :require => 'rack/jsonr'
|
16
|
+
|
17
|
+
You activate JSONR by including it your config.ru file:
|
18
|
+
|
19
|
+
```
|
20
|
+
use Rack::JSONR
|
21
|
+
run Sinatra::Application
|
22
|
+
```
|
23
|
+
|
24
|
+
## Benefits of JSONR
|
25
|
+
|
26
|
+
There are several benefits to using JSONR over JSONP...
|
27
|
+
|
28
|
+
### Ability to Use POST, PUT and DELETE Verbs
|
29
|
+
|
30
|
+
You can now make POST, PUT and DELETE requests through JSONR calls by including request_method=VERB in your query:
|
31
|
+
|
32
|
+
```
|
33
|
+
http://example.com/request?first_name=Caleb&request_method=PUT&callback=_jqjsp
|
34
|
+
```
|
35
|
+
|
36
|
+
That's it. Rails and Sinatra routes will now recognize it as a PUT request.
|
37
|
+
|
38
|
+
### Access to HTTP Status and Headers
|
39
|
+
|
40
|
+
With JSONR, the returned "http status" is always forced at 200 to ensure the browser always processes the
|
41
|
+
response. The real http status is included along with response headers as additional arguments in the
|
42
|
+
callback. This removes much of the limitations of JSONP.
|
43
|
+
|
44
|
+
### Access to Rich Error Data from the Client
|
45
|
+
|
46
|
+
One big frustration of standard JSONP is that when there is an error (http status greater than 200) there is no way to
|
47
|
+
access the returned JSON. This makes it difficult to handle form errors, for example.
|
48
|
+
|
49
|
+
With JSONR errors, the "http status" is forced at 200, which means you still have access to the response body,
|
50
|
+
http status, and headers.
|
51
|
+
|
52
|
+
## Using JSONR Responses through Existing Libraries
|
53
|
+
|
54
|
+
You can use jQuery or any other libraries that support JSONP with two caveats:
|
55
|
+
|
56
|
+
1. All callbacks will be returns as "success", even if there are errors, since the http status is always returned as 200.
|
57
|
+
Therefore, you'll will need to parse the body of the response to determine if there are errors.
|
58
|
+
|
59
|
+
2. By default you won't have access to the http status and headers returned by JSONR since libraries like jQuery and
|
60
|
+
jQuery-JSONP only read the first arg in the server callback.
|
61
|
+
|
62
|
+
However, there is hope...
|
63
|
+
|
64
|
+
## Using JSONR with jQuery-JSONP
|
65
|
+
|
66
|
+
I'm experimenting with a forked version of jQuery-JSONP, which extends the library to read JSONR while still being
|
67
|
+
backwards compatible with JSONP. It only changes two public methods:
|
68
|
+
|
69
|
+
#### 1. Two optional arguments were appended to the success callback:
|
70
|
+
|
71
|
+
##### success - `function` (`undefined`)
|
72
|
+
|
73
|
+
A function to be called if the request succeeds. The function gets passed three arguments: The JSON object returned from the server, a string describing the status (always `"success"`) and, *_as of version 2.4.0_* the `xOptions` object.
|
74
|
+
|
75
|
+
```js
|
76
|
+
function (json, textStatus, xOptions, httpStatus, httpHeaders) {
|
77
|
+
this; // the xOptions object or xOptions.context if provided
|
78
|
+
}
|
79
|
+
```
|
80
|
+
|
81
|
+
#### 2. Three optional arguments were appended to the error callback:
|
82
|
+
|
83
|
+
##### error - `function` (`undefined`)
|
84
|
+
|
85
|
+
A function to be called if the request fails. The function is passed two arguments: The `xOptions` object and a string describing the type of error that occurred. Possible values for the second argument are `"error"` (the request finished but the JSONR callback was not called) or `"timeout"`.
|
86
|
+
|
87
|
+
```js
|
88
|
+
function (xOptions, textStatus, json, httpStatus, httpHeaders) {
|
89
|
+
this; // the xOptions object or xOptions.context if provided
|
90
|
+
}
|
91
|
+
```
|
92
|
+
|
93
|
+
## What's Next?
|
94
|
+
|
95
|
+
We need to add tests.
|
96
|
+
|
97
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'fileutils'
|
4
|
+
include FileUtils
|
5
|
+
|
6
|
+
# Default Rake task is compile
|
7
|
+
#task :default => :compile
|
8
|
+
|
9
|
+
########################################################################
|
10
|
+
|
11
|
+
Rake::TestTask.new do |t|
|
12
|
+
t.libs.push "lib"
|
13
|
+
t.libs.push "test"
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = false
|
16
|
+
end
|
data/lib/rack/jsonr.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
# A Rack middleware for providing JSONP in a usable way - accepts GET/POST/PUT/DELETE verbs and http status and
|
5
|
+
# headers are readable from the body.
|
6
|
+
#
|
7
|
+
# Based on Rack-JSONP by Flinn Mueller (http://actsasflinn.com/)
|
8
|
+
#
|
9
|
+
class JSONR
|
10
|
+
include Rack::Utils
|
11
|
+
|
12
|
+
def initialize(app)
|
13
|
+
@app = app
|
14
|
+
end
|
15
|
+
|
16
|
+
# Proxies the request to the application, stripping out the JSONP callback
|
17
|
+
# method and padding the response with the appropriate callback format if
|
18
|
+
# the returned body is application/json
|
19
|
+
#
|
20
|
+
# Changes nothing if no <tt>callback</tt> param is specified.
|
21
|
+
#
|
22
|
+
def call(env)
|
23
|
+
status, headers, response = @app.call(env)
|
24
|
+
|
25
|
+
headers = HeaderHash.new(headers)
|
26
|
+
request = Rack::Request.new(env)
|
27
|
+
params = request.params
|
28
|
+
|
29
|
+
if is_jsonp_request?(request) and params['request_method'].present?
|
30
|
+
env['REQUEST_METHOD'] = params['request_method'].upcase if ['POST','PUT','DELETE'].include?(params['request_method'].upcase)
|
31
|
+
end
|
32
|
+
|
33
|
+
if is_jsonp_request?(request) and is_json_response?(headers)
|
34
|
+
response = format_jsonp(request.params.delete('callback'), status, headers, response)
|
35
|
+
status = 200
|
36
|
+
|
37
|
+
# No longer json, its javascript!
|
38
|
+
headers['Content-Type'] = headers['Content-Type'].gsub('json', 'javascript')
|
39
|
+
|
40
|
+
# Set new Content-Length, if it was set before we mutated the response body
|
41
|
+
if headers['Content-Length']
|
42
|
+
length = response.to_ary.inject(0) { |len, part| len + bytesize(part) }
|
43
|
+
headers['Content-Length'] = length.to_s
|
44
|
+
end
|
45
|
+
end
|
46
|
+
[status, headers, response]
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def is_json_response?(headers)
|
52
|
+
headers.key?('Content-Type') && headers['Content-Type'].include?('application/json')
|
53
|
+
end
|
54
|
+
|
55
|
+
def is_jsonp_request?(request)
|
56
|
+
@is_jsonp_request ||= (request.params.include?('callback') and request.get?)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Formats the JSONP padding to include body, headers and http status
|
60
|
+
#
|
61
|
+
def format_jsonp(callback, status, headers, response, x_headers={}, body='')
|
62
|
+
headers.each {|k,v| x_headers[k] = v if (k =~ /^X-.+/i) }
|
63
|
+
response.each {|v| body << v.to_s }
|
64
|
+
["#{callback}(#{body}, #{status}, #{x_headers})"]
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
data/rack-jsonr.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rack/jsonr'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'rack-jsonr'
|
8
|
+
gem.version = Rack::JSONR::VERSION
|
9
|
+
gem.date = '2013-03-17'
|
10
|
+
gem.summary = %q{A Rack middleware for providing enhanced JSONP-type access, but with get, post, put, and delete
|
11
|
+
verbs as well as http status, headers, and a json body that can be read when there are errors.}
|
12
|
+
gem.authors = ['Caleb Clark']
|
13
|
+
gem.email = ['cclark@fanforce.com']
|
14
|
+
gem.homepage = 'http://github.com/calebclark/rack-jsonr'
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
|
20
|
+
gem.add_development_dependency 'rack'
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-jsonr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Caleb Clark
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-03-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- cclark@fanforce.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- .gitignore
|
35
|
+
- Gemfile
|
36
|
+
- README.md
|
37
|
+
- Rakefile
|
38
|
+
- lib/rack/jsonr.rb
|
39
|
+
- lib/rack/jsonr/jsonr.rb
|
40
|
+
- lib/rack/jsonr/version.rb
|
41
|
+
- rack-jsonr.gemspec
|
42
|
+
homepage: http://github.com/calebclark/rack-jsonr
|
43
|
+
licenses: []
|
44
|
+
metadata: {}
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 2.0.3
|
62
|
+
signing_key:
|
63
|
+
specification_version: 4
|
64
|
+
summary: A Rack middleware for providing enhanced JSONP-type access, but with get,
|
65
|
+
post, put, and delete verbs as well as http status, headers, and a json body that
|
66
|
+
can be read when there are errors.
|
67
|
+
test_files: []
|