braintreehttp 0.1.5 → 0.2.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: 9f5acc4be958983186e9a0ec676bb2cd63ef1826
4
- data.tar.gz: 1df1e3ea5528c38871d9095a5d950dce2858faa5
3
+ metadata.gz: 599bde79b1bc33cd0f46c65d37136855ed422343
4
+ data.tar.gz: 06d2cf5cc5eeda5fad37ba71b07c97f91068331a
5
5
  SHA512:
6
- metadata.gz: cd69056b00f9453007534051a1c64e54e203f10383e48b6848e3e2c04ce93066e607c76dbe4eca87136e0e7c1c2e0c266b2bebfae094096962b2f14177a41279
7
- data.tar.gz: 42179eb6e06bbe238b3f5e4e6022751dc3ef57d06c8254c51d0fa6a73e0dc74096e4e0e54fb2fd9810ed7f334867fc7deddca6068e1e9c804e8a5bcdf28b16c0
6
+ metadata.gz: 81fe0a125d8b991d02e9f3d77171e4b4c18745df78e3f0a6e6c30d01c8edc873952736a047063d45925af236672f2cdc74f2887e175b98c9ebab5d62a7cf87bd
7
+ data.tar.gz: 9375dd0800ea34885828d90b3c3987cd8571ff312d28af415be69840671210fcd4edd63a06de5cc9758783472cfca22630b29c47b778a60f1d478b49ed93adec
@@ -1,10 +1,12 @@
1
+ require_relative './lib/braintreehttp/version'
2
+
1
3
  $:.push File.expand_path("../lib", __FILE__)
2
4
 
3
5
  Gem::Specification.new do |s|
4
6
  s.name = "braintreehttp"
5
7
  s.summary = "BraintreeHttp Client Library"
6
8
  s.description = "Used for generated API clients"
7
- s.version = "0.1.5"
9
+ s.version = VERSION
8
10
  s.license = "MIT"
9
11
  s.author = "Braintree"
10
12
  s.email = "code@getbraintree.com"
@@ -1,10 +1,9 @@
1
1
  require 'json'
2
2
 
3
3
  module BraintreeHttp
4
-
5
4
  class Encoder
6
5
  def initialize
7
- @encoders = [Json.new, Text.new]
6
+ @encoders = [Json.new, Text.new, Multipart.new]
8
7
  end
9
8
 
10
9
  def serialize_request(req)
@@ -16,7 +15,7 @@ module BraintreeHttp
16
15
  enc = _encoder(content_type)
17
16
  raise UnsupportedEncodingError.new("Unable to serialize request with Content-Type #{content_type}. Supported encodings are #{supported_encodings}") unless enc
18
17
 
19
- enc.encode(req.body)
18
+ enc.encode(req)
20
19
  end
21
20
 
22
21
  def deserialize_response(resp, headers)
@@ -43,9 +42,8 @@ module BraintreeHttp
43
42
  end
44
43
 
45
44
  class Json
46
-
47
- def encode(body)
48
- JSON.generate(body)
45
+ def encode(request)
46
+ JSON.generate(request.body)
49
47
  end
50
48
 
51
49
  def decode(body)
@@ -58,9 +56,8 @@ module BraintreeHttp
58
56
  end
59
57
 
60
58
  class Text
61
-
62
- def encode(body)
63
- body.to_s
59
+ def encode(request)
60
+ request.body.to_s
64
61
  end
65
62
 
66
63
  def decode(body)
@@ -71,4 +68,53 @@ module BraintreeHttp
71
68
  /^text\/.*/
72
69
  end
73
70
  end
71
+
72
+ class Multipart
73
+ def encode(request)
74
+ boundary = DateTime.now.strftime("%Q")
75
+ request.headers["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
76
+
77
+ form_params = []
78
+ request.body.each do |k, v|
79
+ if v.is_a? File
80
+ form_params.push(_add_file_part(k, v))
81
+ else
82
+ form_params.push(_add_form_field(k, v))
83
+ end
84
+ end
85
+
86
+ form_params.collect {|p| "--" + boundary + "#{LINE_FEED}" + p}.join("") + "--" + boundary + "--"
87
+ end
88
+
89
+ def decode(body)
90
+ raise UnsupportedEncodingError.new("Multipart does not support deserialization")
91
+ end
92
+
93
+ def content_type
94
+ /^multipart\/.*/
95
+ end
96
+
97
+ def _add_form_field(key, value)
98
+ return "Content-Disposition: form-data; name=\"#{key}\"#{LINE_FEED}#{LINE_FEED}#{value}#{LINE_FEED}"
99
+ end
100
+
101
+ def _add_file_part(key, file)
102
+ mime_type = _mime_type_for_file_name(file.path)
103
+ return "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{File.basename(file.path)}\"#{LINE_FEED}" +
104
+ "Content-Type: #{mime_type}#{LINE_FEED}#{LINE_FEED}#{file.read}#{LINE_FEED}"
105
+ end
106
+
107
+ def _mime_type_for_file_name(filename)
108
+ file_extension = File.extname(filename).strip.downcase[1..-1]
109
+ if file_extension == "jpeg" || file_extension == "jpg"
110
+ return "image/jpeg"
111
+ elsif file_extension == "png"
112
+ return "image/png"
113
+ elsif file_extension == "pdf"
114
+ return "application/pdf"
115
+ else
116
+ return "application/octet-stream"
117
+ end
118
+ end
119
+ end
74
120
  end
@@ -7,7 +7,7 @@ module BraintreeHttp
7
7
  LINE_FEED = "\r\n"
8
8
 
9
9
  class HttpClient
10
- attr_accessor :environment
10
+ attr_accessor :environment, :encoder
11
11
 
12
12
  def initialize(environment)
13
13
  @environment = environment
@@ -40,65 +40,15 @@ module BraintreeHttp
40
40
  request.headers["User-Agent"] = user_agent
41
41
  end
42
42
 
43
- httpRequest = Net::HTTPGenericRequest.new(request.verb, true, true, request.path, request.headers)
43
+ http_request = Net::HTTPGenericRequest.new(request.verb, true, true, request.path, request.headers)
44
44
 
45
- content_type = request.headers["Content-Type"]
46
- if content_type && content_type.start_with?("multipart/")
47
- boundary = DateTime.now.strftime("%Q")
48
- httpRequest.set_content_type("multipart/form-data; boundary=#{boundary}")
49
-
50
- form_params = []
51
- request.body.each do |k, v|
52
- if v.is_a? File
53
- form_params.push(_add_file_part(k, v))
54
- else
55
- form_params.push(_add_form_field(k, v))
56
- end
57
- end
58
-
59
- httpRequest.body = form_params.collect {|p| "--" + boundary + "#{LINE_FEED}" + p}.join("") + "--" + boundary + "--"
60
- elsif has_body(request)
61
- if request.body.is_a? String
62
- httpRequest.body = request.body
63
- else
64
- httpRequest.body = serialize_request(request)
65
- end
45
+ if has_body(request)
46
+ http_request.body = @encoder.serialize_request(request)
66
47
  end
67
48
 
68
49
  uri = URI(@environment.base_url)
69
50
  Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
70
- _parse_response(http.request(httpRequest))
71
- end
72
- end
73
-
74
- def serialize_request(request)
75
- @encoder.serialize_request(request)
76
- end
77
-
78
- def deserialize_response(response_body, headers)
79
- @encoder.deserialize_response(response_body, headers)
80
- end
81
-
82
- def _add_form_field(key, value)
83
- return "Content-Disposition: form-data; name=\"#{key}\"#{LINE_FEED}#{LINE_FEED}#{value}#{LINE_FEED}"
84
- end
85
-
86
- def _add_file_part(key, file)
87
- mime_type = _mime_type_for_file_name(file.path)
88
- return "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{File.basename(file.path)}\"#{LINE_FEED}" +
89
- "Content-Type: #{mime_type}#{LINE_FEED}#{LINE_FEED}#{file.read}#{LINE_FEED}"
90
- end
91
-
92
- def _mime_type_for_file_name(filename)
93
- file_extension = File.extname(filename).strip.downcase[1..-1]
94
- if file_extension == "jpeg" || file_extension == "jpg"
95
- return "image/jpeg"
96
- elsif file_extension == "png"
97
- return "image/png"
98
- elsif file_extension == "pdf"
99
- return "application/pdf"
100
- else
101
- return "application/octet-stream"
51
+ _parse_response(http.request(http_request))
102
52
  end
103
53
  end
104
54
 
@@ -108,7 +58,7 @@ module BraintreeHttp
108
58
  result = response.body
109
59
  headers = response.to_hash
110
60
  if result && !result.empty?
111
- deserialized = deserialize_response(response.body, headers)
61
+ deserialized = @encoder.deserialize_response(response.body, headers)
112
62
  if deserialized.is_a?(String) || deserialized.is_a?(Array)
113
63
  result = deserialized
114
64
  else
@@ -0,0 +1 @@
1
+ VERSION = "0.2.0"
@@ -36,6 +36,32 @@ describe Encoder do
36
36
  expect(Encoder.new.serialize_request(req)).to eq("some text")
37
37
  end
38
38
 
39
+ it 'serializes the request when content-type == multipart/form-data' do
40
+ http_client = HttpClient.new(@environment)
41
+ file = File.new("README.md", "r")
42
+ req = OpenStruct.new({
43
+ :verb => "POST",
44
+ :path => "/v1/api",
45
+ :headers => {
46
+ "Content-Type" => "multipart/form-data"
47
+ },
48
+ :body => {
49
+ :key => "value",
50
+ :another_key => 1013,
51
+ :readme => file,
52
+ }
53
+ })
54
+
55
+ serialized = Encoder.new.serialize_request(req)
56
+
57
+ expect(serialized).to include("Content-Disposition: form-data; name=\"readme\"; filename=\"README.md\"")
58
+ expect(serialized).to include("Content-Disposition: form-data; name=\"readme\"; filename=\"README.md\"")
59
+ expect(serialized).to include("Content-Disposition: form-data; name=\"key\"")
60
+ expect(serialized).to include("value")
61
+ expect(serialized).to include("Content-Disposition: form-data; name=\"another_key\"")
62
+ expect(serialized).to include("1013")
63
+ end
64
+
39
65
  it 'throws when content-type is not application/json' do
40
66
  req = OpenStruct.new({
41
67
  :headers => {
@@ -58,7 +58,13 @@ describe HttpClient do
58
58
 
59
59
  stub_request(:delete, @environment.base_url + "/path")
60
60
 
61
- req = OpenStruct.new({:verb => "DELETE", :path => "/path"})
61
+ req = OpenStruct.new({
62
+ :verb => "DELETE",
63
+ :path => "/path",
64
+ :headers => {
65
+ "Content-Type" => "text/plain"
66
+ }
67
+ })
62
68
 
63
69
  req.body = "I want to delete the thing"
64
70
 
@@ -157,36 +163,6 @@ describe HttpClient do
157
163
  expect(resp.result.key).to eq('value')
158
164
  end
159
165
 
160
- it "allows subclasses to modify response body" do
161
- WebMock.enable!
162
-
163
- return_data = {
164
- :key => "value"
165
- }
166
-
167
- class JSONHttpClient < HttpClient
168
- def deserialize_response(body, headers)
169
- if headers["content-type"].include? "application/json"
170
- return 'something else'
171
- end
172
-
173
- body
174
- end
175
- end
176
-
177
- http_client = JSONHttpClient.new(@environment)
178
-
179
- stub_request(:get, @environment.base_url + "/v1/api")
180
- .to_return(body: JSON.generate(return_data), status: 200, headers: {"Content-Type" => "application/json"})
181
-
182
- req = OpenStruct.new({:verb => "GET", :path => "/v1/api"})
183
-
184
- resp = http_client.execute(req)
185
-
186
- expect(resp.status_code).to eq(200)
187
- expect(resp.result).to eq('something else')
188
- end
189
-
190
166
  it 'handles json array result' do
191
167
  WebMock.enable!
192
168
 
@@ -204,49 +180,6 @@ describe HttpClient do
204
180
  expect(resp.result).to eq(return_data)
205
181
  end
206
182
 
207
- it "encodes multipart/form-data when a file is present without body" do
208
- WebMock.enable!
209
-
210
- stub_request(:any, @environment.base_url + "/v1/api")
211
-
212
- http_client = HttpClient.new(@environment)
213
- file = File.new("README.md", "r")
214
- req = OpenStruct.new({:verb => "POST", :path => "/v1/api", :headers => {"Content-Type" => "multipart/form-data"}})
215
- req.body = {:readme => file}
216
-
217
- resp = http_client.execute(req)
218
-
219
- assert_requested(:post, @environment.base_url + "/v1/api") { |requested|
220
- requested.body.include? "Content-Disposition: form-data; name=\"readme\"; filename=\"README.md\""
221
- }
222
- end
223
-
224
- it "encodes multipart/form-data when a file is present with body" do
225
- WebMock.enable!
226
-
227
- stub_request(:any, @environment.base_url + "/v1/api")
228
-
229
- http_client = HttpClient.new(@environment)
230
- file = File.new("README.md", "r")
231
-
232
- req = OpenStruct.new({:verb => "POST", :path => "/v1/api", :headers => {"Content-Type" => "multipart/form-data"}})
233
- req.body = {
234
- :key => "value",
235
- :another_key => 1013,
236
- :readme => file,
237
- }
238
-
239
- resp = http_client.execute(req)
240
-
241
- assert_requested(:post, @environment.base_url + "/v1/api") { |requested|
242
- requested.body.include? "Content-Disposition: form-data; name=\"readme\"; filename=\"README.md\""
243
- requested.body.include? "Content-Disposition: form-data; name=\"key\""
244
- requested.body.include? "value"
245
- requested.body.include? "Content-Disposition: form-data; name=\"another_key\""
246
- requested.body.include? "1013"
247
- }
248
- end
249
-
250
183
  it "does not error if no file or body present on a request class" do
251
184
  class Request
252
185
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: braintreehttp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Braintree
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-30 00:00:00.000000000 Z
11
+ date: 2017-10-25 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Used for generated API clients
14
14
  email: code@getbraintree.com
@@ -22,6 +22,7 @@ files:
22
22
  - lib/braintreehttp/environment.rb
23
23
  - lib/braintreehttp/errors.rb
24
24
  - lib/braintreehttp/http_client.rb
25
+ - lib/braintreehttp/version.rb
25
26
  - spec/braintreehttp/encoder_spec.rb
26
27
  - spec/braintreehttp/http_client_spec.rb
27
28
  - spec/spec_helper.rb
@@ -45,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
45
46
  version: '0'
46
47
  requirements: []
47
48
  rubyforge_project: braintreehttp
48
- rubygems_version: 2.6.12
49
+ rubygems_version: 2.2.2
49
50
  signing_key:
50
51
  specification_version: 4
51
52
  summary: BraintreeHttp Client Library