Skip to content

Commit 005eaed

Browse files
committed
switch HTTP library to faraday to allow adapter to select HTTP library, and fix test
1 parent 2f6dcbb commit 005eaed

File tree

6 files changed

+48
-53
lines changed

6 files changed

+48
-53
lines changed

Gemfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ source 'https://rubygems.org'
22

33
gemspec
44

5+
group :development, :production do
6+
gem 'faraday', '~> 2.0'
7+
end
8+
59
group :test, :development do
610
# code coloring for yard
711
gem 'redcarpet'
@@ -20,4 +24,3 @@ group :test, :development do
2024
gem "pry-byebug"
2125
end
2226
end
23-

lib/serpapi.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ module SerpApi
44
# see serpapi/serpapi for implementation
55
end
66

7-
# load native ruby dependency
8-
require 'open-uri'
7+
# load faraday HTTP lib
8+
require 'faraday'
9+
10+
# load
911
require 'json'
1012

1113
# implementation

lib/serpapi/client.rb

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class Client
3030
# key can be either a symbol or a string.
3131
#
3232
# @param [Hash] params default for the search
33-
def initialize(params = {})
33+
def initialize(params = {}, adapter = :net_http)
3434
# set default read timeout
3535
@timeout = params[:timeout] || params['timeout'] || 120
3636
@timeout.freeze
@@ -42,6 +42,9 @@ def initialize(params = {})
4242
# set default params safely in memory
4343
@params = params.clone || {}
4444
@params.freeze
45+
46+
# setup connection socket
47+
@socket = Faraday.new(url: "https://#{BACKEND}")
4548
end
4649

4750
# perform a search using SerpApi.com
@@ -104,63 +107,50 @@ def api_key
104107

105108
private
106109

107-
# build url from the search params
108-
#
109-
# @param [String] endpoint HTTP service uri
110-
# @param [Hash] params custom search inputs
111-
# @return formatted HTTPS URL
112-
def build_url(endpoint, params)
113-
# force default
114-
query = (@params || {}).merge(params || {})
110+
# @return [Hash] query parameter
111+
def query(params)
112+
# merge default params with custom params
113+
q = (@params || {}).merge(params || {})
115114

116115
# set ruby client
117-
query[:source] = 'serpapi-ruby:' << SerpApi::VERSION
116+
q[:source] = 'serpapi-ruby:' << SerpApi::VERSION
118117

119118
# delete empty key/value
120-
query.compact!
121-
122-
# HTTP params encoding
123-
encoded_query = URI.encode_www_form(query)
124-
125-
# return URL
126-
URI::HTTPS.build(host: BACKEND, path: endpoint, query: encoded_query)
119+
q.compact
127120
end
128121

129122
# get HTTP query formatted results
130123
#
131124
# @param [String] endpoint HTTP service uri
132125
# @param [Symbol] decoder type :json or :html
133126
# @param [Hash] params custom search inputs
127+
# @param [Boolean] symbolize_names if true, convert JSON keys to symbols
134128
# @return decoded payload as JSON / Hash or String
135-
def get(endpoint, decoder = :json, params = {})
136-
url = build_url(endpoint, params)
137-
payload = URI(url).open(read_timeout: timeout).read
138-
decode(payload, decoder)
139-
rescue OpenURI::HTTPError => err
140-
data = JSON.parse(err.io.read)
141-
if data.key?('error')
142-
raise SerpApiException, "error: #{data['error']} from url: #{url}"
129+
def get(endpoint, decoder = :json, params = {}, symbolize_names = true)
130+
begin
131+
payload = @socket.get(endpoint) do |req|
132+
req.params = query(params)
133+
req.options.timeout = timeout
143134
end
144-
raise SerpApiException, "fail: get url: #{url} response: #{data}"
145-
rescue => err
146-
raise SerpApiException, "fail: get url: #{url} caused by: #{err}"
135+
# read http response
136+
data = payload.body
137+
# decode payload using JSON native parser
138+
if decoder == :json
139+
data = JSON.parse(data, symbolize_names: symbolize_names)
140+
if data.class == Hash && data.key?('error')
141+
raise SerpApiException, "get failed with error: #{data['error']} from url: #{endpoint}, params: #{params}, decoder: #{decoder}, http status: #{payload.status} "
142+
end
143+
if payload.status != 200
144+
raise SerpApiException, "get failed with response status: #{payload.status} reponse: #{data} on get url: #{endpoint}, params: #{params}, decoder: #{decoder}"
145+
end
146+
end
147+
# return raw HTML
148+
return data
149+
rescue Faraday::Error => err
150+
raise SerpApiException, "fail: get url: #{endpoint} caused by #{err.class} : #{err.message} (params: #{params}, decoder: #{decoder})"
147151
end
148152
end
149153

150-
# decode HTTP payload either as :json or :html
151-
#
152-
# @param [String] payload to decode
153-
# @param [Symbol] decoder type :json or :html
154-
# @return decoded payload as JSON / Hash or HTML / String
155-
def decode(payload, decoder)
156-
case decoder
157-
when :json
158-
JSON.parse(payload, symbolize_names: true)
159-
when :html
160-
payload
161-
else
162-
msg = "not supported decoder #{decoder}. should be: :html or :json (Symbol)"
163-
raise SerpApiException, msg
164-
end
165-
end
154+
end
155+
166156
end

spec/serpapi/client/account_api_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,7 @@
2525
expect(account_info[:account_id]).not_to be_empty
2626
expect(account_info[:api_key]).not_to be_empty
2727
expect(account_info[:account_email]).not_to be_empty
28+
29+
puts "search left: #{account_info[:plan_searches_left]}"
2830
end
2931
end

spec/serpapi/client/client_spec.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
describe 'client full coverage' do
44
before(:all) do
5-
pp Module.constants.select { |c| c.to_s =~ /SerpApi/ }
65
@client = SerpApi::Client.new(engine: 'google', api_key: ENV['API_KEY'], timeout: 30)
76
end
87

@@ -59,7 +58,7 @@
5958
begin
6059
@client.search({})
6160
rescue SerpApi::Errors::SerpApiException => e
62-
expect(e.message).to include('fail: get url')
61+
expect(e.message).to include('get failed with response')
6362
rescue => e
6463
raise("wrong exception: #{e}")
6564
end

spec/serpapi/client/location_api_spec.rb

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@
33
describe 'SerpApi Location API' do
44
it 'Get normalized location for Austin, TX' do
55
client = SerpApi::Client.new(api_key: ENV['API_KEY'])
6-
location_list = client.location(q: 'Austin', limit: 3)
7-
expect(location_list.size).to eq(3)
6+
location_list = client.location(q: 'Austin, TX', limit: 3)
7+
expect(location_list.size).to eq(1)
88

99
first = location_list.first
10-
expect(first[:id]).to eq('585069bdee19ad271e9bc072')
10+
expect(first[:id]).not_to be_nil
1111
expect(first[:name]).to eq('Austin, TX')
1212
expect(first[:country_code]).to eq('US')
1313
expect(first[:target_type]).to eq('DMA Region')
14-
expect(first[:reach]).to eq(5_560_000)
1514
expect(first[:gps]).to eq([-97.7430608, 30.267153])
1615
expect(first[:keys]).to eq(%w[austin tx texas united states])
1716
expect(first[:canonical_name]).to eq('Austin,TX,Texas,United States')

0 commit comments

Comments
 (0)