jersey 0.0.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c73c2c478b36fbd1a0574323dcbb7f023264517d
4
- data.tar.gz: d7f9a1f7e5cd742a9de16d62c12b8b9cce788137
3
+ metadata.gz: 8917e3fd5a219b1f47d717b67c220309e0099e53
4
+ data.tar.gz: 877d58392cf2c2ed29f0c716be9ae96e013624d0
5
5
  SHA512:
6
- metadata.gz: 81638bfb73758bf758ae0245c163f88c2bf01c9214736a036c74f00e4a8f3a6309888588e07be9878783835f4ebad5bf02c348be1ec5dbb2adcdac72637d095e
7
- data.tar.gz: 49fc8716d35f5e8b8d1cffb85d912e391c5325b22e8e72a751b9aedebaee14a94f82d9e27727b92773808d660790bcd4f0f9f95914845ac1d002adb499efced3
6
+ metadata.gz: d79189492a2066fc625ad5b89c6fd68874d7c820d65a5def6f506b5de8a9f404cb5e8c1d2cb39db9d83db1c42dfae57668100f2f1883951e150d9c6b3105cc6c
7
+ data.tar.gz: b3321888bd62a38ea83d8552be66df3fc28ec1a64179340cfa1eced4f5ad0da42d9af13b7a0a53ba2dfcd9cd1acc9972a1c1add634471404b95de5f2dc8b48ac
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 2.2.0
5
+ - 2.1.5
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency "sinatra", "~> 1.4"
22
22
  spec.add_dependency 'sinatra-contrib', "~> 1.4"
23
- spec.add_dependency 'env-conf'
23
+ spec.add_dependency 'env-conf', '0.0.4'
24
24
  spec.add_dependency 'request_store'
25
25
  spec.add_development_dependency "bundler", "~> 1.7"
26
26
  spec.add_development_dependency "rake", "~> 10.0"
@@ -1,3 +1,5 @@
1
+ require 'request_store'
2
+
1
3
  module Jersey
2
4
  module API
3
5
  module Middleware
@@ -8,5 +10,17 @@ module Jersey
8
10
 
9
11
  module Helpers
10
12
  end
13
+
14
+ module HTTP
15
+ end
11
16
  end
12
17
  end
18
+
19
+ # jersey
20
+ require 'jersey/http_errors'
21
+ require 'jersey/middleware/request_id'
22
+ require 'jersey/middleware/error_handler'
23
+ require 'jersey/middleware/request_logger'
24
+ require 'jersey/extensions/route_signature'
25
+ require 'jersey/helpers/log'
26
+ require 'jersey/helpers/success'
@@ -1,22 +1,17 @@
1
1
  require "sinatra/base"
2
2
  require 'sinatra/json'
3
3
  require 'json'
4
- require 'request_store'
5
4
 
6
- # jersey
7
- require 'jersey/http_errors'
8
- require 'jersey/middleware/request_id'
9
- require 'jersey/middleware/request_logger'
10
- require 'jersey/extensions/route_signature'
11
- require 'jersey/extensions/error_handler'
12
- require 'jersey/helpers/log'
5
+ # Take over Sinatra's NotFound so we don't have to deal with the
6
+ # not_found block and can raise our own NotFound error
7
+ ::Sinatra.send(:remove_const, :NotFound)
8
+ ::Sinatra.const_set(:NotFound, ::Jersey::HTTP::Errors::NotFound)
13
9
 
14
10
  module Jersey::API
15
11
  class Base < Sinatra::Base
16
12
  include Jersey::HTTP::Errors
17
13
 
18
14
  register Jersey::Extensions::RouteSignature
19
- register Jersey::Extensions::ErrorHandler
20
15
 
21
16
  use Rack::Deflater
22
17
  use Rack::ConditionalGet
@@ -24,8 +19,14 @@ module Jersey::API
24
19
 
25
20
  use Jersey::Middleware::RequestID
26
21
  use Jersey::Middleware::RequestLogger
22
+ use Jersey::Middleware::ErrorHandler
27
23
 
28
24
  helpers Sinatra::JSON
29
25
  helpers Jersey::Helpers::Log
26
+ helpers Jersey::Helpers::Success
27
+
28
+ set :dump_errors, false
29
+ set :raise_errors, true
30
+ set :show_exceptions, false
30
31
  end
31
32
  end
@@ -21,6 +21,7 @@ module Jersey::Extensions
21
21
 
22
22
  json(error: {
23
23
  type: e.class.name.split('::').last,
24
+ request_id: env['REQUEST_ID'],
24
25
  message: e.message,
25
26
  backtrace: e.backtrace
26
27
  })
@@ -0,0 +1,17 @@
1
+ module Jersey::Helpers
2
+ module Success
3
+ def created(*args)
4
+ status(201)
5
+ json(*args)
6
+ end
7
+
8
+ def accepted(*args)
9
+ status(202)
10
+ json(*args)
11
+ end
12
+
13
+ def no_content(*args)
14
+ status(204)
15
+ end
16
+ end
17
+ end
@@ -1,62 +1,57 @@
1
- module Jersey
2
- module HTTP
3
- module Errors
4
- HTTPError = Class.new(StandardError)
5
- ClientError = Class.new(HTTPError)
6
- ServerError = Class.new(HTTPError)
1
+ module Jersey::HTTP
2
+ module Errors
3
+ HTTPError = Class.new(StandardError)
4
+ ClientError = Class.new(HTTPError)
5
+ ServerError = Class.new(HTTPError)
7
6
 
8
- # Define ALL the HTTP errors as constants
9
- FOUR_HUNDRED = [
10
- [400, 'BadRequest', :bad_request],
11
- [401, 'Unauthorized', :unauthorized],
12
- [402, 'PaymentRequired', :payment_required],
13
- [403, 'Forbidden', :forbidden],
14
- [404, 'NotFound', :not_found],
15
- [405, 'MethodNotAllowed', :method_not_allowed],
16
- [406, 'NotAcceptable', :not_acceptable],
17
- [407, 'ProxyAuthenticationRequired', :proxy_authentication_required],
18
- [408, 'RequestTimeout', :request_timeout],
19
- [409, 'Conflict', :conflict],
20
- [410, 'Gone', :gone],
21
- [411, 'LengthRequired', :length_required],
22
- [412, 'PreconditionFailed', :precondition_failed],
23
- [413, 'RequestEntityTooLarge', :request_entity_too_large],
24
- [414, 'RequestURITooLong', :request_uri_too_long],
25
- [415, 'UnsupportedMediaType', :unsupported_media_type],
26
- [416, 'RequestedRangeNotSatisfiable', :requested_range_not_satisfiable],
27
- [417, 'ExpectationFailed', :expectation_failed],
28
- [422, 'UnprocessableEntity', :unprocessable_entity],
29
- [423, 'Locked', :locked],
30
- [424, 'FailedDependency', :failed_dependency],
31
- [426, 'UpgradeRequired', :upgrade_required],
32
- ]
7
+ # Define ALL the HTTP errors as constants
8
+ FOUR_HUNDRED = [
9
+ [400, 'BadRequest', :bad_request],
10
+ [401, 'Unauthorized', :unauthorized],
11
+ [402, 'PaymentRequired', :payment_required],
12
+ [403, 'Forbidden', :forbidden],
13
+ [404, 'NotFound', :not_found],
14
+ [405, 'MethodNotAllowed', :method_not_allowed],
15
+ [406, 'NotAcceptable', :not_acceptable],
16
+ [407, 'ProxyAuthenticationRequired', :proxy_authentication_required],
17
+ [408, 'RequestTimeout', :request_timeout],
18
+ [409, 'Conflict', :conflict],
19
+ [410, 'Gone', :gone],
20
+ [411, 'LengthRequired', :length_required],
21
+ [412, 'PreconditionFailed', :precondition_failed],
22
+ [413, 'RequestEntityTooLarge', :request_entity_too_large],
23
+ [414, 'RequestURITooLong', :request_uri_too_long],
24
+ [415, 'UnsupportedMediaType', :unsupported_media_type],
25
+ [416, 'RequestedRangeNotSatisfiable', :requested_range_not_satisfiable],
26
+ [417, 'ExpectationFailed', :expectation_failed],
27
+ [422, 'UnprocessableEntity', :unprocessable_entity],
28
+ [423, 'Locked', :locked],
29
+ [424, 'FailedDependency', :failed_dependency],
30
+ [426, 'UpgradeRequired', :upgrade_required],
31
+ ]
33
32
 
34
- FIVE_HUNDRED = [
35
- [500, 'InternalServerError', :internal_server_error],
36
- [501, 'NotImplemented', :not_implemented],
37
- [502, 'BadGateway', :bad_gateway],
38
- [503, 'ServiceUnavailable', :service_unavailable],
39
- [504, 'GatewayTimeout', :gateway_timeout],
40
- [505, 'HTTPVersionNotSupported', :http_version_not_supported],
41
- [507, 'InsufficientStorage', :insufficient_storage],
42
- [510, 'NotExtended', :not_extended],
43
- ]
33
+ FIVE_HUNDRED = [
34
+ [500, 'InternalServerError', :internal_server_error],
35
+ [501, 'NotImplemented', :not_implemented],
36
+ [502, 'BadGateway', :bad_gateway],
37
+ [503, 'ServiceUnavailable', :service_unavailable],
38
+ [504, 'GatewayTimeout', :gateway_timeout],
39
+ [505, 'HTTPVersionNotSupported', :http_version_not_supported],
40
+ [507, 'InsufficientStorage', :insufficient_storage],
41
+ [510, 'NotExtended', :not_extended],
42
+ ]
44
43
 
45
- (FOUR_HUNDRED + FIVE_HUNDRED).each do |s|
46
- code, const_name, symbol = s[0],s[1],s[2]
47
- if code >= 500
48
- klass = Class.new(ServerError)
49
- else
50
- klass = Class.new(ClientError)
51
- end
52
- klass.const_set(:STATUS_CODE, code)
53
- const_set(const_name,klass)
44
+ # Dynamically Create all the necessary HTTP errors
45
+ # with appropriate status codes
46
+ (FOUR_HUNDRED + FIVE_HUNDRED).each do |s|
47
+ code, const_name, symbol = s[0],s[1],s[2]
48
+ if code >= 500
49
+ klass = Class.new(ServerError)
50
+ else
51
+ klass = Class.new(ClientError)
54
52
  end
55
-
56
- # Take over Sinatra's NotFound so we don't have to deal with the
57
- # not_found block and can raise our own NotFound error
58
- ::Sinatra.send(:remove_const, :NotFound)
59
- ::Sinatra.const_set(:NotFound, ::Jersey::HTTP::Errors::NotFound)
53
+ klass.const_set(:STATUS_CODE, code)
54
+ const_set(const_name,klass)
60
55
  end
61
56
  end
62
57
  end
@@ -9,6 +9,11 @@ module Jersey
9
9
  include Logging::LogError
10
10
  end
11
11
 
12
+ class JsonLogger < JSONLogger
13
+ include Logging::LogTime
14
+ include Logging::LogError
15
+ end
16
+
12
17
  module LoggingSingleton
13
18
  attr_writer :logger
14
19
 
@@ -0,0 +1,40 @@
1
+ module Jersey::Middleware
2
+ class ErrorHandler
3
+ def initialize(app, options = {})
4
+ @app = app
5
+ ib = options[:include_backtrace]
6
+ @include_backtrace = (ib.nil? && ENV['RACK_ENV'] == 'development') || ib
7
+ end
8
+
9
+ def call(env)
10
+ begin
11
+ @app.call(env)
12
+ rescue => e
13
+ # get status code from Jersey Errors
14
+ if e.class.const_defined?(:STATUS_CODE)
15
+ status = e.class::STATUS_CODE
16
+ elsif e.respond_to?(:status_code)
17
+ status = e.status_code
18
+ else
19
+ status = 500
20
+ end
21
+
22
+ headers = {
23
+ 'Content-Type' => 'application/json'
24
+ }
25
+
26
+ body = {error: {
27
+ type: e.class.name.split('::').last,
28
+ request_id: env['REQUEST_ID'] || env['HTTP_REQUEST_ID'],
29
+ message: e.message
30
+ }}
31
+
32
+ if @include_backtrace
33
+ body[:error][:backtrace] = e.backtrace
34
+ end
35
+
36
+ [status, headers, [body.to_json]]
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,3 +1,3 @@
1
1
  module Jersey
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  require_relative 'helper'
2
2
 
3
3
  class ErrorsTest < ApiTest
4
- class SimpleApi < Jersey::API::Base
4
+ class App < Jersey::API::Base
5
5
  get '/test-409' do
6
6
  raise Conflict, "bad"
7
7
  end
@@ -15,10 +15,6 @@ class ErrorsTest < ApiTest
15
15
  end
16
16
  end
17
17
 
18
- def app
19
- SimpleApi
20
- end
21
-
22
18
  def test_not_found
23
19
  get '/not-found'
24
20
  assert_equal(404, last_response.status)
@@ -30,6 +26,7 @@ class ErrorsTest < ApiTest
30
26
  assert_equal(409, last_response.status)
31
27
  assert_equal('Conflict', json['error']['type'])
32
28
  assert_equal('bad', json['error']['message'])
29
+ assert(json['error']['request_id'])
33
30
  end
34
31
 
35
32
  def test_http_errors_500
@@ -37,6 +34,7 @@ class ErrorsTest < ApiTest
37
34
  assert_equal(500, last_response.status)
38
35
  assert_equal('InternalServerError', json['error']['type'])
39
36
  assert_equal('bad', json['error']['message'])
37
+ assert(json['error']['request_id'])
40
38
  end
41
39
 
42
40
  def test_http_errors_Undefined
@@ -44,5 +42,18 @@ class ErrorsTest < ApiTest
44
42
  assert_equal(500, last_response.status)
45
43
  assert_equal('RuntimeError', json['error']['type'])
46
44
  assert_equal('boom!', json['error']['message'])
45
+ assert(json['error']['request_id'])
46
+ end
47
+
48
+ def test_errors_are_logged
49
+ Jersey.logger.stream = StringIO.new
50
+ get '/test-500'
51
+ loglines = logs.lines
52
+ assert_equal(2, loglines.size)
53
+ logdata = Logfmt.parse(loglines[0])
54
+ assert(logdata['at'], 'started')
55
+ logdata = Logfmt.parse(loglines[1])
56
+ assert(logdata['at'], 'finished')
57
+ assert(logdata['status'], '500')
47
58
  end
48
59
  end
@@ -0,0 +1,35 @@
1
+ require_relative 'helper'
2
+
3
+ class SuccessTest < ApiTest
4
+ class App < Jersey::API::Base
5
+ get '/test-201' do
6
+ created({foo: 'baz'})
7
+ end
8
+
9
+ get '/test-202' do
10
+ accepted({foo: 'bar'})
11
+ end
12
+
13
+ get '/test-204' do
14
+ no_content
15
+ end
16
+ end
17
+
18
+ def test_created
19
+ get '/test-201'
20
+ assert_equal(201, last_response.status)
21
+ assert_equal('baz', json['foo'])
22
+ end
23
+
24
+ def test_accepted
25
+ get '/test-202'
26
+ assert_equal(202, last_response.status)
27
+ assert_equal('bar', json['foo'])
28
+ end
29
+
30
+ def test_no_content
31
+ get '/test-204'
32
+ assert_equal(204, last_response.status)
33
+ assert_equal('', last_response.body)
34
+ end
35
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jersey
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - csquared
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-12 00:00:00.000000000 Z
11
+ date: 2015-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: env-conf
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - '='
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.0.4
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - '='
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 0.0.4
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: request_store
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -102,6 +102,7 @@ extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
104
  - ".gitignore"
105
+ - ".travis.yml"
105
106
  - Gemfile
106
107
  - LICENSE.txt
107
108
  - README.md
@@ -114,12 +115,14 @@ files:
114
115
  - lib/jersey/extensions/error_handler.rb
115
116
  - lib/jersey/extensions/route_signature.rb
116
117
  - lib/jersey/helpers/log.rb
118
+ - lib/jersey/helpers/success.rb
117
119
  - lib/jersey/http_errors.rb
118
120
  - lib/jersey/log.rb
119
121
  - lib/jersey/logging/base_logger.rb
120
122
  - lib/jersey/logging/json_logger.rb
121
123
  - lib/jersey/logging/logfmt_logger.rb
122
124
  - lib/jersey/logging/mixins.rb
125
+ - lib/jersey/middleware/error_handler.rb
123
126
  - lib/jersey/middleware/request_id.rb
124
127
  - lib/jersey/middleware/request_logger.rb
125
128
  - lib/jersey/setup.rb
@@ -130,6 +133,7 @@ files:
130
133
  - test/log_test.rb
131
134
  - test/request_logger_test.rb
132
135
  - test/setup_test.rb
136
+ - test/success_test.rb
133
137
  homepage: ''
134
138
  licenses:
135
139
  - MIT
@@ -150,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
154
  version: '0'
151
155
  requirements: []
152
156
  rubyforge_project:
153
- rubygems_version: 2.2.0
157
+ rubygems_version: 2.2.2
154
158
  signing_key:
155
159
  specification_version: 4
156
160
  summary: Write APIs in the New Jersey Style
@@ -160,3 +164,4 @@ test_files:
160
164
  - test/log_test.rb
161
165
  - test/request_logger_test.rb
162
166
  - test/setup_test.rb
167
+ - test/success_test.rb