Skip to content

Commit 32cdb5a

Browse files
committed
improve client behavior to be more resilient
1 parent 6f353ce commit 32cdb5a

File tree

2 files changed

+84
-21
lines changed

2 files changed

+84
-21
lines changed

lib/serpapi/client.rb

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ def initialize(params = {})
7171
@timeout.freeze
7272

7373
# enable HTTP persistent mode
74-
@persistent = params[:persistent] || true
74+
@persistent = true
75+
@persistent = params[:persistent] if params.key?(:persistent)
7576
@persistent.freeze
7677

7778
# delete this client only configuration keys
@@ -206,19 +207,30 @@ def get(endpoint, decoder = :json, params = {}, symbolize_names = true)
206207
case decoder
207208
when :json
208209
# read http response
209-
data = JSON.parse(response.body, symbolize_names: symbolize_names)
210-
if data.instance_of?(Hash) && data.key?(:error)
211-
raise SerpApiError, "HTTP request failed with error: #{data[:error]} from url: https://#{BACKEND}#{endpoint}, params: #{params}, decoder: #{decoder}, response status: #{response.status} "
212-
elsif response.status != 200
213-
raise SerpApiError, "HTTP request failed with response status: #{response.status} reponse: #{data} on get url: https://#{BACKEND}#{endpoint}, params: #{params}, decoder: #{decoder}"
210+
begin
211+
data = JSON.parse(response.body, symbolize_names: symbolize_names)
212+
if data.instance_of?(Hash) && data.key?(:error)
213+
raise SerpApiError, "HTTP request failed with error: #{data[:error]} from url: https://#{BACKEND}#{endpoint}, params: #{params}, decoder: #{decoder}, response status: #{response.status} "
214+
elsif response.status != 200
215+
raise SerpApiError, "HTTP request failed with response status: #{response.status} reponse: #{data} on get url: https://#{BACKEND}#{endpoint}, params: #{params}, decoder: #{decoder}"
216+
end
217+
rescue JSON::ParserError
218+
raise SerpApiError, "JSON parse error: #{response.body} on get url: https://#{BACKEND}#{endpoint}, params: #{params}, decoder: #{decoder}, response status: #{response.status}"
214219
end
215220

216221
# discard response body
217222
response.flush if persistent?
218223

219224
data
220-
else
225+
when :html
226+
# html decoder
227+
if response.status != 200
228+
raise SerpApiError, "HTTP request failed with response status: #{response.status} reponse: #{data} on get url: https://#{BACKEND}#{endpoint}, params: #{params}, decoder: #{decoder}"
229+
end
230+
221231
response.body
232+
else
233+
raise SerpApiError, "not supported decoder: #{decoder}, available: :json, :html"
222234
end
223235
end
224236
end

spec/serpapi/client/client_spec.rb

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
require 'spec_helper'
22

3-
describe 'client full code coverage' do
4-
before(:all) do
5-
@client = SerpApi::Client.new(engine: 'google', api_key: ENV['API_KEY'], timeout: 30)
3+
describe 'set of client test to archieve full code coverage' do
4+
let(:client) do
5+
client = SerpApi::Client.new(engine: 'google', api_key: ENV['SERPAPI_KEY'], timeout: 30)
66
end
77

88
it 'search for coffee in Austin, TX and receive json results' do
9-
data = @client.search(q: 'Coffee', location: 'Austin, TX')
9+
data = client.search(q: 'Coffee', location: 'Austin, TX')
1010
expect(data.size).to be > 5
1111
expect(data.class).to be Hash
1212
expect(data.keys.size).to be > 5
1313
end
1414

1515
it 'search fir coffee in Austin, TX and receive raw HTML' do
16-
data = @client.html(q: 'Coffee', location: 'Austin, TX')
16+
data = client.html(q: 'Coffee', location: 'Austin, TX')
1717
expect(data).to match(/coffee/i)
1818
end
1919

2020
it 'missing query' do
2121
begin
22-
@client.search({})
22+
client.search({})
2323
rescue SerpApi::SerpApiError => e
2424
expect(e.message).to include('Missing query')
2525
rescue => e
@@ -28,48 +28,99 @@
2828
end
2929

3030
it 'get params' do
31-
expect(@client.params[:api_key]).to eq(ENV['API_KEY'])
31+
expect(client.params[:api_key]).to eq(ENV['SERPAPI_KEY'])
3232
end
3333

3434
it 'api_key' do
35-
expect(@client.api_key).to eq(ENV['API_KEY'])
35+
expect(client.api_key).to eq(ENV['SERPAPI_KEY'])
3636
end
3737

3838
it 'engine' do
39-
expect(@client.engine).to eq('google')
39+
expect(client.engine).to eq('google')
4040
end
4141

4242
it 'timeout' do
43-
expect(@client.timeout).to eq(30)
43+
expect(client.timeout).to eq(30)
44+
end
45+
46+
it 'persistent' do
47+
expect(client.persistent).to be true
4448
end
4549

4650
it 'get bad decoder' do
4751
begin
48-
@client.send(:get, '/search', :bad, {q: 'hello'})
52+
client.send(:get, '/search', :bad, {q: 'hello'})
4953
rescue SerpApi::SerpApiError => e
5054
expect(e.message).to include('not supported decoder')
5155
rescue => e
5256
raise("wrong exception: #{e}")
5357
end
5458
end
59+
60+
it 'get endpoint error' do
61+
expect {
62+
client.send(:get, '/search', :json, {})
63+
}.to raise_error(SerpApi::SerpApiError).with_message(/HTTP request failed with error: Missing query `q` parameter./)
64+
end
65+
66+
it 'get bad endpoint' do
67+
begin
68+
client.send(:get, '/invalid', :json, {})
69+
rescue SerpApi::SerpApiError => e
70+
expect(e.message).to include('JSON parse error')
71+
rescue => e
72+
raise("wrong exception: #{e}")
73+
end
74+
end
75+
76+
it 'get bad html endpoint' do
77+
begin
78+
client.send(:get, '/invalid', :html, {})
79+
rescue SerpApi::SerpApiError => e
80+
expect(e.message).to include('HTTP request failed with response status: 404')
81+
rescue => e
82+
raise("wrong exception: #{e}")
83+
end
84+
end
5585
end
5686

57-
describe 'SerpApi client adapter' do
87+
describe 'SerpApi client with persitency enable' do
88+
5889
let(:client) do
59-
SerpApi::Client.new(engine: 'google', api_key: ENV['API_KEY'], timeout: 10, persistency: true)
90+
SerpApi::Client.new(engine: 'google', api_key: ENV['SERPAPI_KEY'], timeout: 10, persistent: true)
6091
end
6192

62-
it 'makes a search request with valid parameters' do
93+
it 'check socket is open when persistent mode is enabled' do
6394
expect(client.socket).to_not be_nil
95+
expect(client.persistent).to be true
96+
end
97+
98+
it 'makes a search request with valid parameters' do
6499
response = client.search(q: 'Coffee', location: 'Austin, TX')
65100
expect(response.size).to be > 5
66101
expect(response.class).to be Hash
67102
expect(response.keys.size).to be > 5
68103
expect(response[:search_metadata][:id]).not_to be_nil
104+
105+
expect(client.close).to eq(:clean)
69106
end
70107

71108
it 'handles API errors' do
72109
allow(client).to receive(:search).and_raise(SerpApi::SerpApiError)
73110
expect { client.search(q: 'Invalid Query') }.to raise_error(SerpApi::SerpApiError)
74111
end
112+
113+
end
114+
115+
describe 'SerpApi client with persitency disabled' do
116+
it 'check socket is closed when persistent mode is disabled' do
117+
client = SerpApi::Client.new(engine: 'google', api_key: ENV['SERPAPI_KEY'], timeout: 10, persistent: false)
118+
expect(client.persistent).to be false
119+
expect(client.socket).to be_nil
120+
expect(client.close).to be_nil
121+
122+
client.search(q: 'Coffee', location: 'Austin, TX')
123+
expect(client.socket).to be_nil
124+
expect(client.close).to be_nil
125+
end
75126
end

0 commit comments

Comments
 (0)