Skip to content

Commit 6e4f740

Browse files
committed
readme improvement
- remove images too big / no value added - polish description in README add symboize_names option if user want to use string as dictionary key (closer to JSON
1 parent 07f6fe5 commit 6e4f740

File tree

6 files changed

+101
-69
lines changed

6 files changed

+101
-69
lines changed

.yardopts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
--markup=markdown
1+
--markup=markdown
2+
--exclude LICENSE

README.md

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
<div align="center">
2-
<h1 align="center">SerpApi Ruby Library</h1>
1+
# SerpApi Ruby Library
32

4-
![serpapi ruby library logo](https://user-images.githubusercontent.com/78694043/235409962-7afe3a25-9272-4d56-9678-9972b771453b.png)
3+
[![serpapi-ruby](https://github.com/serpapi/serpapi-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/serpapi/serpapi-ruby/actions/workflows/ci.yml) [![Gem Version](https://badge.fury.io/rb/serpapi.svg)](https://badge.fury.io/rb/serpapi)
54

6-
[![Gem Version](https://badge.fury.io/rb/serpapi.svg)](https://badge.fury.io/rb/serpapi) [![serpapi-ruby](https://github.com/serpapi/serpapi-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/serpapi/serpapi-ruby/actions/workflows/ci.yml)
7-
</div>
5+
Integrate search data into your AI workflow, RAG / fine tuning or ruby application using this official wrapper for [SerpApi](https://serpapi.com).
86

9-
Integrate search data into your AI workflow or ruby application. This library is the official wrapper for [SerpApi](https://serpapi.com).
10-
SerpApi supports Google, Google Maps, Google Shopping, Baidu, Yandex, Yahoo, eBay, App Stores, and more.
11-
Fast query at scale a vast range of data, including web search results, flight schedule, stock market data, news headlines, and more.
7+
SerpApi supports Google, Google Maps, Google Shopping, Baidu, Yandex, Yahoo, eBay, App Stores, and [more.](https://serpapi.com).
8+
9+
Fast query at scale a vast range of data, including web search results, flight schedule, stock market data, news headlines, and [more.](https://serpapi.com).
1210

1311
## Features
1412
* `persistent` → Keep socket connection open to save on SSL handshake / reconnection (2x faster). [Search at scale](#Search-At-Scale)
@@ -20,7 +18,7 @@ Fast query at scale a vast range of data, including web search results, flight s
2018

2119
To achieve optimal performance, it is essential to have Ruby 3.1+ (preferably version 3.4) installed.
2220

23-
| Older versions such as Ruby 1.9, 2.x, and JRuby are compatible with [serpapi older library](https://github.com/serpapi/google-search-results-ruby), which continues to function effectively.
21+
| Older versions such as Ruby 1.9, 2.x, and JRuby are compatible with [serpapi older library](https://github.com/serpapi/google-search-results-ruby), which continues to function effectively. see [migration guide](#Migration-quick-guide) if you are using the older library.
2422

2523
### Bundler
2624
```ruby
@@ -53,7 +51,10 @@ Environment variables are a secure, safe, and easy way to manage secrets.
5351
Ruby accesses these variables from `ENV['SERPAPI_KEY']`.
5452

5553

56-
## Search API advanced Usage
54+
## Search API advanced usage with Google search engine
55+
56+
This example dives into all the available parameters for the Google search engine.
57+
The set of parameters is extensive and depends on the search engine you choose.
5758

5859
```ruby
5960
# load gem
@@ -67,6 +68,7 @@ client = SerpApi::Client.new(
6768
async: false, # non blocking HTTP request see: Search Asynchronous (default: false)
6869
persistent: true, # leave socket connection open for faster response time see: Search at scale (default: true)
6970
timeout: 5, # HTTP timeout in seconds on the client side only. (default: 120s)
71+
symbolize_names: true # turn on/off JSON keys to symbols (default: on more efficient)
7072
)
7173

7274
# search query overview (more fields available depending on search engine)
@@ -91,23 +93,20 @@ params = {
9193
tbs: "custom to be client criteria",
9294
}
9395

94-
# formatted search results as a Hash
95-
# serpapi.com converts HTML -> JSON
96+
# search results as a symbolized Hash (per performance)
9697
results = client.search(params)
9798

98-
# raw search engine html as a String
99-
# serpapi.com acts a proxy to provide high throughputs, no search limit and more.
99+
# search results as a raw HTML string
100100
raw_html = client.html(params) # Corrected parameter reference
101101
```
102-
103-
[SerpApi documentation](https://serpapi.com/search-api).
102+
[SerpApi documentation](https://serpapi.com/search-api).
104103

105104
#### Documentations
106-
107-
* [API documentation](https://rubydoc.info/github/serpapi/serpapi-ruby/master)
105+
This library is well documented, and you can find the following resources:
108106
* [Full documentation on SerpApi.com](https://serpapi.com)
109107
* [Library Github page](https://github.com/serpapi/serpapi-ruby)
110108
* [Library GEM page](https://rubygems.org/gems/serpapi/)
109+
* [Library API documentation](https://rubydoc.info/github/serpapi/serpapi-ruby/master)
111110
* [API health status](https://serpapi.com/status)
112111

113112
## Advanced search API usage
@@ -130,9 +129,7 @@ client = SerpApi::Client.new(engine: 'google', async: true, persistent: true, ap
130129
search_queue = Queue.new
131130
company_list.each do |company|
132131
result = client.search({ q: company })
133-
if result[:search_metadata][:status] =~ /Cached/
134-
puts "#{company}: search results found in cache for: #{company}"
135-
end
132+
puts "#{company}: search results found in cache for: #{company}" if result[:search_metadata][:status] =~ /Cached/
136133

137134
search_queue.push(result[:search_metadata][:id])
138135
end

README.md.erb

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,15 @@ def snippet(format, path, demo = false)
1818
%Q(```#{format}\nrequire 'serpapi'\n#{buf}```\n\n * source code: [#{path}](https://github.com/serpapi/serpapi-ruby/blob/master/#{path}))
1919
end
2020
-%>
21-
<div align="center">
22-
<h1 align="center">SerpApi Ruby Library</h1>
21+
# SerpApi Ruby Library
2322

24-
![serpapi ruby library logo](https://user-images.githubusercontent.com/78694043/235409962-7afe3a25-9272-4d56-9678-9972b771453b.png)
23+
[![serpapi-ruby](https://github.com/serpapi/serpapi-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/serpapi/serpapi-ruby/actions/workflows/ci.yml) [![Gem Version](https://badge.fury.io/rb/serpapi.svg)](https://badge.fury.io/rb/serpapi)
2524

26-
[![Gem Version](https://badge.fury.io/rb/serpapi.svg)](https://badge.fury.io/rb/serpapi) [![serpapi-ruby](https://github.com/serpapi/serpapi-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/serpapi/serpapi-ruby/actions/workflows/ci.yml)
27-
</div>
25+
Integrate search data into your AI workflow, RAG / fine tuning or ruby application using this official wrapper for [SerpApi](https://serpapi.com).
2826

29-
Integrate search data into your AI workflow or ruby application. This library is the official wrapper for [SerpApi](https://serpapi.com).
30-
SerpApi supports Google, Google Maps, Google Shopping, Baidu, Yandex, Yahoo, eBay, App Stores, and more.
31-
Fast query at scale a vast range of data, including web search results, flight schedule, stock market data, news headlines, and more.
27+
SerpApi supports Google, Google Maps, Google Shopping, Baidu, Yandex, Yahoo, eBay, App Stores, and [more.](https://serpapi.com).
28+
29+
Fast query at scale a vast range of data, including web search results, flight schedule, stock market data, news headlines, and [more.](https://serpapi.com).
3230

3331
## Features
3432
* `persistent` → Keep socket connection open to save on SSL handshake / reconnection (2x faster). [Search at scale](#Search-At-Scale)
@@ -40,7 +38,7 @@ Fast query at scale a vast range of data, including web search results, flight s
4038

4139
To achieve optimal performance, it is essential to have Ruby 3.1+ (preferably version 3.4) installed.
4240

43-
| Older versions such as Ruby 1.9, 2.x, and JRuby are compatible with [serpapi older library](https://github.com/serpapi/google-search-results-ruby), which continues to function effectively.
41+
| Older versions such as Ruby 1.9, 2.x, and JRuby are compatible with [serpapi older library](https://github.com/serpapi/google-search-results-ruby), which continues to function effectively. see [migration guide](#Migration-quick-guide) if you are using the older library.
4442

4543
### Bundler
4644
```ruby
@@ -73,7 +71,10 @@ Environment variables are a secure, safe, and easy way to manage secrets.
7371
Ruby accesses these variables from `ENV['SERPAPI_KEY']`.
7472

7573

76-
## Search API advanced Usage
74+
## Search API advanced usage with Google search engine
75+
76+
This example dives into all the available parameters for the Google search engine.
77+
The set of parameters is extensive and depends on the search engine you choose.
7778

7879
```ruby
7980
# load gem
@@ -87,6 +88,7 @@ client = SerpApi::Client.new(
8788
async: false, # non blocking HTTP request see: Search Asynchronous (default: false)
8889
persistent: true, # leave socket connection open for faster response time see: Search at scale (default: true)
8990
timeout: 5, # HTTP timeout in seconds on the client side only. (default: 120s)
91+
symbolize_names: true # turn on/off JSON keys to symbols (default: on more efficient)
9092
)
9193

9294
# search query overview (more fields available depending on search engine)
@@ -111,23 +113,20 @@ params = {
111113
tbs: "custom to be client criteria",
112114
}
113115

114-
# formatted search results as a Hash
115-
# serpapi.com converts HTML -> JSON
116+
# search results as a symbolized Hash (per performance)
116117
results = client.search(params)
117118

118-
# raw search engine html as a String
119-
# serpapi.com acts a proxy to provide high throughputs, no search limit and more.
119+
# search results as a raw HTML string
120120
raw_html = client.html(params) # Corrected parameter reference
121121
```
122-
123-
[SerpApi documentation](https://serpapi.com/search-api).
122+
→ [SerpApi documentation](https://serpapi.com/search-api).
124123

125124
#### Documentations
126-
127-
* [API documentation](https://rubydoc.info/github/serpapi/serpapi-ruby/master)
125+
This library is well documented, and you can find the following resources:
128126
* [Full documentation on SerpApi.com](https://serpapi.com)
129127
* [Library Github page](https://github.com/serpapi/serpapi-ruby)
130128
* [Library GEM page](https://rubygems.org/gems/serpapi/)
129+
* [Library API documentation](https://rubydoc.info/github/serpapi/serpapi-ruby/master)
131130
* [API health status](https://serpapi.com/status)
132131

133132
## Advanced search API usage

lib/serpapi/client.rb

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ module SerpApi
44
# Client for SerpApi.com
55
# powered by HTTP.rb
66
#
7-
# it supports:
7+
# features:
88
# * async non-block search
99
# * persistent HTTP connection
10-
# * many endpoints
10+
# * search API
11+
# * location API
12+
# * account API
13+
# * search archive API
1114
#
1215
class Client
1316
# Backend service URL
@@ -99,7 +102,6 @@ def initialize(params = {})
99102
#
100103
# see: https://serpapi.com/search-api
101104
#
102-
#
103105
# note that the raw response
104106
# from the search engine is converted to JSON by SerpApi.com backend.
105107
# thus, most of the compute power is on the backsdend and not on the client side.
@@ -110,7 +112,10 @@ def search(params = {})
110112
get('/search', :json, params)
111113
end
112114

113-
# html search
115+
# html search perform a search using SerpApi.com
116+
# the output is raw HTML from the search engine.
117+
# it is useful for training AI models, RAG, debugging
118+
# or when you need to parse the HTML yourself.
114119
#
115120
# @return [String] raw html search results directly from the search engine.
116121
def html(params = {})
@@ -120,7 +125,7 @@ def html(params = {})
120125
# Get location using Location API
121126
#
122127
# example: spec/serpapi/location_api_spec.rb
123-
# doc: https://serpapi.com/search-api
128+
# doc: https://serpapi.com/locations-api
124129
#
125130
# @param [Hash] params must includes fields: q, limit
126131
# @return [Array<Hash>] list of matching locations
@@ -129,11 +134,17 @@ def location(params = {})
129134
end
130135

131136
# Retrieve search result from the Search Archive API
132-
#
137+
#
138+
# ```ruby
139+
# client = SerpApi::Client.new(engine: 'google', api_key: ENV['SERPAPI_KEY'])
140+
# results = client.search(q: 'Coffee', location: 'Portland')
141+
# search_id = results[:search_metadata][:id]
142+
# archive_search = client.search_archive(search_id)
143+
# ```
133144
# example: spec/serpapi/client/search_archive_api_spec.rb
134145
# doc: https://serpapi.com/search-archive-api
135146
#
136-
# @param [String|Integer] search_id is returned
147+
# @param [String|Integer] search_id from original search `results[:search_metadata][:id]`
137148
# @param [Symbol] format :json or :html [default: json, optional]
138149
# @return [String|Hash] raw html or JSON / Hash
139150
def search_archive(search_id, format = :json)
@@ -145,9 +156,9 @@ def search_archive(search_id, format = :json)
145156
# Get account information using Account API
146157
#
147158
# example: spec/serpapi/client/account_api_spec.rb
148-
# doc: https://serpapi.com/google-jobs-api
159+
# doc: https://serpapi.com/account-api
149160
#
150-
# @param [String] api_key secret key
161+
# @param [String] api_key secret key [optional if already provided to the constructor]
151162
# @return [Hash] account information
152163
def account(api_key = nil)
153164
params = (api_key.nil? ? {} : { api_key: api_key })
@@ -177,7 +188,12 @@ def query(params)
177188
raise SerpApiError, "params must be hash, not: #{params.class}" unless params.instance_of?(Hash)
178189

179190
# merge default params with custom params
180-
q = @params.merge(params)
191+
q = @params.clone.merge(params)
192+
193+
# do not pollute default params with custom params
194+
if q.key?(:symbolize_names)
195+
q.delete(:symbolize_names)
196+
end
181197

182198
# delete empty key/value
183199
q.compact
@@ -188,14 +204,14 @@ def persistent?
188204
persistent
189205
end
190206

191-
# get HTTP query formatted results
207+
# Perform HTTP GET request to the SerpApi.com backend endpoint.
192208
#
193-
# @param [String] endpoint HTTP service uri
209+
# @param [String] endpoint HTTP service URI
194210
# @param [Symbol] decoder type :json or :html
195211
# @param [Hash] params custom search inputs
196-
# @param [Boolean] symbolize_names if true, convert JSON keys to symbols
197-
# @return decoded response as JSON / Hash or String
198-
def get(endpoint, decoder = :json, params = {}, symbolize_names = true)
212+
# @param [Boolean] symbolize_names if true, convert JSON keys to symbols more memory efficient.
213+
# @return [String|Hash] raw HTML or decoded response as JSON / Hash
214+
def get(endpoint, decoder = :json, params = {})
199215
# execute get via open socket
200216
response = if persistent?
201217
@socket.get(endpoint, params: query(params))
@@ -208,6 +224,11 @@ def get(endpoint, decoder = :json, params = {}, symbolize_names = true)
208224
when :json
209225
# read http response
210226
begin
227+
# user can turn on/off JSON keys to symbols
228+
# this is more memory efficient, but not always needed
229+
symbolize_names = params.key?(:symbolize_names) ? params[:symbolize_names] : true
230+
231+
# parse JSON response with Ruby standard library
211232
data = JSON.parse(response.body, symbolize_names: symbolize_names)
212233
if data.instance_of?(Hash) && data.key?(:error)
213234
raise SerpApiError, "HTTP request failed with error: #{data[:error]} from url: https://#{BACKEND}#{endpoint}, params: #{params}, decoder: #{decoder}, response status: #{response.status} "

lib/serpapi/error.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module SerpApi
33
# SerpApiException wraps any errors related to the SerpApi client.
44
class SerpApiError < StandardError
55
# List the specific types of errors handled by the Error class.
6+
# - HTTP response errors from SerpApi.com
67
# - Missing API key
78
# - Credit limit
89
# - Incorrect query

spec/serpapi/client/client_spec.rb

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,29 @@
55
client = SerpApi::Client.new(engine: 'google', api_key: ENV['SERPAPI_KEY'], timeout: 30)
66
end
77

8-
it 'search for coffee in Austin, TX and receive json results' do
9-
data = client.search(q: 'Coffee', location: 'Austin, TX')
10-
expect(data.size).to be > 5
11-
expect(data.class).to be Hash
12-
expect(data.keys.size).to be > 5
8+
it 'search for coffee in Austin, TX, returns symbolized Hash' do
9+
results = client.search(q: 'Coffee', location: 'Austin, TX')
10+
11+
expect(results.size).to be > 5
12+
expect(results.class).to be Hash
13+
expect(results.keys.size).to be > 5
14+
15+
expect(results.keys).to include(:search_metadata), ':search_metadata should be present in the results'
16+
end
17+
18+
it 'search for coffee in Austin, TX, returns non-symbolized Hash' do
19+
results = client.search(q: 'Coffee', location: 'Austin, TX', symbolize_names: false)
20+
21+
expect(results.size).to be > 5
22+
expect(results.class).to be Hash
23+
expect(results.keys.size).to be > 5
24+
25+
expect(results.keys).to include('search_metadata'), 'search_metadata should be present in the results'
1326
end
1427

15-
it 'search fir coffee in Austin, TX and receive raw HTML' do
16-
data = client.html(q: 'Coffee', location: 'Austin, TX')
17-
expect(data).to match(/coffee/i)
28+
it 'search for coffee in Austin, TX and receive raw HTML' do
29+
results = client.html(q: 'Coffee', location: 'Austin, TX')
30+
expect(results).to match(/coffee/i)
1831
end
1932

2033
it 'missing query' do
@@ -77,7 +90,7 @@
7790
begin
7891
client.send(:get, '/invalid', :html, {})
7992
rescue SerpApi::SerpApiError => e
80-
expect(e.message).to include('HTTP request failed with response status: 404')
93+
expect(e.message).to include(/HTTP request failed with response status: 404 Not Found reponse/), "got #{e.message}"
8194
rescue => e
8295
raise("wrong exception: #{e}")
8396
end
@@ -96,11 +109,11 @@
96109
end
97110

98111
it 'makes a search request with valid parameters' do
99-
response = client.search(q: 'Coffee', location: 'Austin, TX')
100-
expect(response.size).to be > 5
101-
expect(response.class).to be Hash
102-
expect(response.keys.size).to be > 5
103-
expect(response[:search_metadata][:id]).not_to be_nil
112+
results = client.search(q: 'Coffee', location: 'Austin, TX')
113+
expect(results.size).to be > 5
114+
expect(results.class).to be Hash
115+
expect(results.keys.size).to be > 5
116+
expect(results[:search_metadata][:id]).not_to be_nil
104117

105118
expect(client.close).to eq(:clean)
106119
end

0 commit comments

Comments
 (0)