Skip to content

Commit f5363f4

Browse files
committed
chore: improve handling of JSON body parsing
1 parent 95dba12 commit f5363f4

File tree

7 files changed

+69
-12
lines changed

7 files changed

+69
-12
lines changed

lib/pact_broker/api/resources/default_base_resource.rb

+15-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
module PactBroker
1313
module Api
1414
module Resources
15-
class InvalidJsonError < StandardError ; end
15+
class InvalidJsonError < PactBroker::Error ; end
1616

1717
class DefaultBaseResource < Webmachine::Resource
1818
include PactBroker::Services
@@ -85,12 +85,21 @@ def handle_exception e
8585
PactBroker::Api::Resources::ErrorHandler.call(e, request, response)
8686
end
8787

88-
def params
89-
@params ||= JSON.parse(request.body.to_s, { symbolize_names: true }.merge(PACT_PARSING_OPTIONS)) #Not load! Otherwise it will try to load Ruby classes.
88+
def params(options = {})
89+
return options[:default] if options.key?(:default) && request_body.empty?
90+
91+
symbolize_names = !options.key?(:symbolize_names) || options[:symbolize_names]
92+
if symbolize_names
93+
@params_with_symbol_keys ||= JSON.parse(request_body, { symbolize_names: true }.merge(PACT_PARSING_OPTIONS)) #Not load! Otherwise it will try to load Ruby classes.
94+
else
95+
@params_with_string_keys ||= JSON.parse(request_body, { symbolize_names: false }.merge(PACT_PARSING_OPTIONS)) #Not load! Otherwise it will try to load Ruby classes.
96+
end
97+
rescue JSON::JSONError => e
98+
raise InvalidJsonError.new("Error parsing JSON - #{e.message}")
9099
end
91100

92101
def params_with_string_keys
93-
@params_with_string_keys ||= JSON.parse(request.body.to_s, { symbolize_names: false }.merge(PACT_PARSING_OPTIONS))
102+
params(symbolize_names: false)
94103
end
95104

96105
def pact_params
@@ -99,12 +108,12 @@ def pact_params
99108

100109
def set_json_error_message message
101110
response.headers['Content-Type'] = 'application/hal+json;charset=utf-8'
102-
response.body = {error: message}.to_json
111+
response.body = { error: message }.to_json
103112
end
104113

105114
def set_json_validation_error_messages errors
106115
response.headers['Content-Type'] = 'application/hal+json;charset=utf-8'
107-
response.body = {errors: errors}.to_json
116+
response.body = { errors: errors }.to_json
108117
end
109118

110119
def request_body

lib/pact_broker/api/resources/error_handler.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def self.generate_error_reference
2727
end
2828

2929
def self.reportable?(e)
30-
!e.is_a?(PactBroker::Error) && !e.is_a?(JSON::GeneratorError)
30+
!e.is_a?(PactBroker::Error) && !e.is_a?(JSON::JSONError)
3131
end
3232

3333
def self.log_as_warning?(e)

lib/pact_broker/api/resources/pacticipant.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def known_methods
3131

3232
def from_json
3333
if pacticipant
34-
@pacticipant = pacticipant_service.update params_with_string_keys.merge('name' => pacticipant_name)
34+
@pacticipant = pacticipant_service.update params(symbolize_names: false).merge('name' => pacticipant_name)
3535
else
3636
@pacticipant = pacticipant_service.create params.merge(:name => pacticipant_name)
3737
response.headers["Location"] = pacticipant_url(base_url, pacticipant)

lib/pact_broker/api/resources/provider_pacts_for_verification.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def query
7272
if request.get?
7373
Rack::Utils.parse_nested_query(request.uri.query)
7474
elsif request.post?
75-
params_with_string_keys
75+
params(symbolize_names: false, default: {})
7676
end
7777
end
7878
end

lib/pact_broker/api/resources/verifications.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def create_path
5252
end
5353

5454
def from_json
55-
verification = verification_service.create(next_verification_number, params_with_string_keys, pact, webhook_options)
55+
verification = verification_service.create(next_verification_number, params(symbolize_names: false), pact, webhook_options)
5656
response.body = decorator_for(verification).to_json(user_options: { base_url: base_url })
5757
true
5858
end

lib/pact_broker/api/resources/webhook.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def malformed_request?
3939

4040
def from_json
4141
if webhook
42-
@webhook = webhook_service.update_by_uuid uuid, params_with_string_keys
42+
@webhook = webhook_service.update_by_uuid(uuid, params(symbolize_names: false))
4343
response.body = to_json
4444
else
4545
@webhook = webhook_service.create(uuid, parsed_webhook, consumer, provider)

spec/lib/pact_broker/api/resources/default_base_resource_spec.rb

+49-1
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,62 @@ module PactBroker
44
module Api
55
module Resources
66
describe DefaultBaseResource do
7-
let(:request) { double('request', uri: uri, base_uri: URI("http://example.org/")).as_null_object }
7+
let(:request) { double('request', body: body, uri: uri, base_uri: URI("http://example.org/")).as_null_object }
88
let(:response) { double('response') }
99
let(:uri) { URI('http://example.org/path?query') }
10+
let(:body) { double('body', to_s: body_string) }
11+
let(:body_string) { '' }
1012

1113
subject { BaseResource.new(request, response) }
1214

1315
its(:resource_url) { is_expected.to eq 'http://example.org/path' }
1416

17+
describe "params" do
18+
let(:body_string) { { foo: 'bar' }.to_json }
19+
20+
context "when the body is invalid JSON" do
21+
let(:body_string) { '{' }
22+
23+
it "raises an error" do
24+
expect { subject.params }.to raise_error InvalidJsonError
25+
end
26+
end
27+
28+
context "when the body is empty and a default is provided" do
29+
let(:body_string) { '' }
30+
31+
it "returns the default" do
32+
expect(subject.params(default: 'foo')).to eq 'foo'
33+
end
34+
end
35+
36+
context "when the body is empty and no default is provided" do
37+
let(:body_string) { '' }
38+
39+
it "raises an error" do
40+
expect { subject.params }.to raise_error InvalidJsonError
41+
end
42+
end
43+
44+
context "when symbolize_names is not set" do
45+
it "symbolizes the names" do
46+
expect(subject.params.keys).to eq [:foo]
47+
end
48+
end
49+
50+
context "when symbolize_names is true" do
51+
it "symbolizes the names" do
52+
expect(subject.params(symbolize_names: true).keys).to eq [:foo]
53+
end
54+
end
55+
56+
context "when symbolize_names is false" do
57+
it "does not symbolize the names" do
58+
expect(subject.params(symbolize_names: false).keys).to eq ['foo']
59+
end
60+
end
61+
end
62+
1563
describe "options" do
1664
subject { options "/"; last_response }
1765

0 commit comments

Comments
 (0)