rack-jsonr 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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=
@@ -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
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -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
+
@@ -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
@@ -0,0 +1,2 @@
1
+ require_relative 'jsonr/jsonr'
2
+ require_relative 'jsonr/version'
@@ -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
@@ -0,0 +1,3 @@
1
+ class Rack::JSONR
2
+ VERSION = '0.1.1'
3
+ end
@@ -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: []