searchapi 1.0.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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +175 -0
  3. data/bin/test +14 -0
  4. data/lib/searchapi/error_result.rb +50 -0
  5. data/lib/searchapi/google_finance_options.rb +40 -0
  6. data/lib/searchapi/google_finance_request.rb +26 -0
  7. data/lib/searchapi/google_finance_result.rb +262 -0
  8. data/lib/searchapi/google_flights_options.rb +85 -0
  9. data/lib/searchapi/google_flights_request.rb +25 -0
  10. data/lib/searchapi/google_flights_result.rb +275 -0
  11. data/lib/searchapi/google_images_options.rb +64 -0
  12. data/lib/searchapi/google_images_request.rb +26 -0
  13. data/lib/searchapi/google_images_result.rb +133 -0
  14. data/lib/searchapi/google_light_options.rb +43 -0
  15. data/lib/searchapi/google_light_request.rb +26 -0
  16. data/lib/searchapi/google_light_result.rb +198 -0
  17. data/lib/searchapi/google_local_options.rb +40 -0
  18. data/lib/searchapi/google_local_request.rb +26 -0
  19. data/lib/searchapi/google_local_result.rb +85 -0
  20. data/lib/searchapi/google_news_light_options.rb +47 -0
  21. data/lib/searchapi/google_news_light_request.rb +26 -0
  22. data/lib/searchapi/google_news_light_result.rb +94 -0
  23. data/lib/searchapi/google_news_options.rb +53 -0
  24. data/lib/searchapi/google_news_portal_options.rb +40 -0
  25. data/lib/searchapi/google_news_portal_request.rb +89 -0
  26. data/lib/searchapi/google_news_portal_result.rb +137 -0
  27. data/lib/searchapi/google_news_request.rb +26 -0
  28. data/lib/searchapi/google_news_result.rb +129 -0
  29. data/lib/searchapi/google_scholar_options.rb +48 -0
  30. data/lib/searchapi/google_scholar_request.rb +26 -0
  31. data/lib/searchapi/google_scholar_result.rb +195 -0
  32. data/lib/searchapi/google_search_options.rb +67 -0
  33. data/lib/searchapi/google_search_request.rb +26 -0
  34. data/lib/searchapi/google_search_result.rb +301 -0
  35. data/lib/searchapi/helpers.rb +10 -0
  36. data/lib/searchapi/instagram_profile_options.rb +31 -0
  37. data/lib/searchapi/instagram_profile_request.rb +26 -0
  38. data/lib/searchapi/instagram_profile_result.rb +117 -0
  39. data/lib/searchapi/module_methods.rb +80 -0
  40. data/lib/searchapi/request.rb +25 -0
  41. data/lib/searchapi/response_methods.rb +14 -0
  42. data/lib/searchapi/tiktok_profile_options.rb +31 -0
  43. data/lib/searchapi/tiktok_profile_request.rb +26 -0
  44. data/lib/searchapi/tiktok_profile_result.rb +71 -0
  45. data/lib/searchapi/version.rb +3 -0
  46. data/lib/searchapi/youtube_search_options.rb +62 -0
  47. data/lib/searchapi/youtube_search_request.rb +26 -0
  48. data/lib/searchapi/youtube_search_result.rb +411 -0
  49. data/lib/searchapi.rb +70 -0
  50. data/searchapi.gemspec +37 -0
  51. metadata +164 -0
@@ -0,0 +1,67 @@
1
+ module SearchAPI
2
+ class GoogleSearchOptions
3
+ include DynamicSchema::Definable
4
+ include Helpers
5
+
6
+ DEVICES = %w[ desktop mobile tablet ]
7
+ SAFE_SEARCH = %w[ active off ]
8
+ TIME_PERIODS = %w[ last_hour last_day last_week last_month last_year ]
9
+ OPTIMIZATION_STRATEGIES = %w[ performance ads ]
10
+
11
+ NORMALIZE_DOWNCASE = ->(v) { v.to_s.downcase }
12
+
13
+ schema do
14
+ # search query (q or kgmid required)
15
+ q String
16
+ kgmid String
17
+
18
+ # device
19
+ device String, in: DEVICES, normalize: NORMALIZE_DOWNCASE
20
+
21
+ # geographic location
22
+ location String
23
+ uule String
24
+
25
+ # localization
26
+ google_domain String
27
+ gl String
28
+ hl String
29
+ lr String
30
+ cr String
31
+
32
+ # filters
33
+ nfpr String
34
+ filter String
35
+ safe String, in: SAFE_SEARCH, normalize: NORMALIZE_DOWNCASE
36
+ time_period String, in: TIME_PERIODS, normalize: NORMALIZE_DOWNCASE
37
+ time_period_min String
38
+ time_period_max String
39
+
40
+ # pagination
41
+ page Integer
42
+
43
+ # optimization
44
+ optimization_strategy String, in: OPTIMIZATION_STRATEGIES, normalize: NORMALIZE_DOWNCASE
45
+ end
46
+
47
+ def self.build( options = nil, &block )
48
+ new( api_options: builder.build( options, &block ) )
49
+ end
50
+
51
+ def self.build!( options = nil, &block )
52
+ new( api_options: builder.build!( options, &block ) )
53
+ end
54
+
55
+ def initialize( options = {}, api_options: nil )
56
+ @options = self.class.builder.build( options || {} )
57
+ @options = api_options.merge( @options ) if api_options
58
+ end
59
+
60
+ def to_h
61
+ result = @options.to_h
62
+ result[ :engine ] = 'google'
63
+ result
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,26 @@
1
+ module SearchAPI
2
+ class GoogleSearchRequest < Request
3
+
4
+ def search( query = nil, options = nil, &block )
5
+ if options
6
+ options = options.is_a?( GoogleSearchOptions ) ? options : GoogleSearchOptions.build!( options.to_h )
7
+ options = options.to_h
8
+ else
9
+ options = { engine: 'google' }
10
+ end
11
+ options[ :q ] = query.to_s if query
12
+
13
+ response = get( "#{ BASE_URI }/search", options, &block )
14
+ attributes = ( JSON.parse( response.body, symbolize_names: true ) rescue nil )
15
+
16
+ result = if response.success?
17
+ GoogleSearchResult.new( attributes || {} )
18
+ else
19
+ ErrorResult.new( response.status, attributes )
20
+ end
21
+
22
+ ResponseMethods.install( response, result )
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,301 @@
1
+ require 'forwardable'
2
+
3
+ module SearchAPI
4
+
5
+ # Search metadata
6
+ GoogleSearchMetadataSchema = DynamicSchema::Struct.define do
7
+ id String
8
+ status String
9
+ created_at String, as: :created_at
10
+ request_time_taken Float, as: :request_time_taken
11
+ parsing_time_taken Float, as: :parsing_time_taken
12
+ total_time_taken Float, as: :total_time_taken
13
+ end
14
+
15
+ class GoogleSearchMetadata < GoogleSearchMetadataSchema
16
+ end
17
+
18
+ # Search parameters
19
+ GoogleSearchParametersSchema = DynamicSchema::Struct.define do
20
+ engine String
21
+ q String
22
+ kgmid String
23
+ location String
24
+ location_used String, as: :location_used
25
+ uule String
26
+ google_domain String, as: :google_domain
27
+ hl String
28
+ gl String
29
+ lr String
30
+ cr String
31
+ device String
32
+ page Integer
33
+ num Integer
34
+ safe String
35
+ filter String
36
+ nfpr String
37
+ time_period String, as: :time_period
38
+ time_period_min String, as: :time_period_min
39
+ time_period_max String, as: :time_period_max
40
+ optimization_strategy String, as: :optimization_strategy
41
+ end
42
+
43
+ class GoogleSearchParameters < GoogleSearchParametersSchema
44
+ end
45
+
46
+ # Search information
47
+ GoogleSearchInformationSchema = DynamicSchema::Struct.define do
48
+ query_displayed String, as: :query_displayed
49
+ total_results Integer, as: :total_results
50
+ page Integer
51
+ time_taken_displayed String, as: :time_taken_displayed
52
+ detected_location String, as: :detected_location
53
+ did_you_mean String, as: :did_you_mean
54
+ end
55
+
56
+ class GoogleSearchInformation < GoogleSearchInformationSchema
57
+ end
58
+
59
+ # Organic result sitelinks
60
+ GoogleSitelinkSchema = DynamicSchema::Struct.define do
61
+ title String
62
+ link String
63
+ end
64
+
65
+ class GoogleSitelink < GoogleSitelinkSchema
66
+ end
67
+
68
+ # Organic result
69
+ GoogleOrganicResultSchema = DynamicSchema::Struct.define do
70
+ position Integer
71
+ title String
72
+ link String
73
+ displayed_link String, as: :displayed_link
74
+ favicon String
75
+ snippet String
76
+ snippet_highlighted_words String, array: true, as: :snippet_highlighted_words
77
+ date String
78
+ sitelinks GoogleSitelink, array: true
79
+ source String
80
+ end
81
+
82
+ class GoogleOrganicResult < GoogleOrganicResultSchema
83
+ end
84
+
85
+ # Ad result
86
+ GoogleAdSchema = DynamicSchema::Struct.define do
87
+ position Integer
88
+ title String
89
+ link String
90
+ displayed_link String, as: :displayed_link
91
+ tracking_link String, as: :tracking_link
92
+ description String
93
+ sitelinks GoogleSitelink, array: true
94
+ end
95
+
96
+ class GoogleAd < GoogleAdSchema
97
+ end
98
+
99
+ # Shopping ad
100
+ GoogleShoppingAdSchema = DynamicSchema::Struct.define do
101
+ position Integer
102
+ title String
103
+ link String
104
+ source String
105
+ price String
106
+ rating Float
107
+ reviews Integer
108
+ thumbnail String
109
+ end
110
+
111
+ class GoogleShoppingAd < GoogleShoppingAdSchema
112
+ end
113
+
114
+ # Knowledge graph
115
+ GoogleKnowledgeGraphSchema = DynamicSchema::Struct.define do
116
+ title String
117
+ type String
118
+ description String
119
+ source Hash
120
+ image String
121
+ attributes Hash
122
+ end
123
+
124
+ class GoogleKnowledgeGraph < GoogleKnowledgeGraphSchema
125
+ end
126
+
127
+ # Related question
128
+ GoogleRelatedQuestionSchema = DynamicSchema::Struct.define do
129
+ question String
130
+ answer String
131
+ title String
132
+ link String
133
+ displayed_link String, as: :displayed_link
134
+ end
135
+
136
+ class GoogleRelatedQuestion < GoogleRelatedQuestionSchema
137
+ end
138
+
139
+ # Related search
140
+ GoogleRelatedSearchSchema = DynamicSchema::Struct.define do
141
+ query String
142
+ link String
143
+ end
144
+
145
+ class GoogleRelatedSearch < GoogleRelatedSearchSchema
146
+ end
147
+
148
+ # Video result
149
+ GoogleVideoSchema = DynamicSchema::Struct.define do
150
+ position Integer
151
+ title String
152
+ link String
153
+ source String
154
+ channel String
155
+ date String
156
+ duration String
157
+ thumbnail String
158
+ end
159
+
160
+ class GoogleVideo < GoogleVideoSchema
161
+ end
162
+
163
+ # Top story
164
+ GoogleTopStorySchema = DynamicSchema::Struct.define do
165
+ title String
166
+ link String
167
+ source String
168
+ date String
169
+ thumbnail String
170
+ end
171
+
172
+ class GoogleTopStory < GoogleTopStorySchema
173
+ end
174
+
175
+ # Local result
176
+ GoogleLocalResultSchema = DynamicSchema::Struct.define do
177
+ position Integer
178
+ title String
179
+ place_id String, as: :place_id
180
+ data_cid String, as: :data_cid
181
+ rating Float
182
+ reviews Integer
183
+ price String
184
+ type String
185
+ address String
186
+ hours String
187
+ phone String
188
+ website String
189
+ thumbnail String
190
+ gps_coordinates Hash, as: :gps_coordinates
191
+ end
192
+
193
+ class GoogleLocalResult < GoogleLocalResultSchema
194
+ end
195
+
196
+ # Pagination
197
+ GooglePaginationSchema = DynamicSchema::Struct.define do
198
+ current Integer
199
+ _value :next, type: Integer
200
+ previous Integer
201
+ end
202
+
203
+ class GooglePagination < GooglePaginationSchema
204
+ end
205
+
206
+ # AI Overview reference link
207
+ GoogleAIOverviewReferenceSchema = DynamicSchema::Struct.define do
208
+ link String
209
+ title String
210
+ source String
211
+ end
212
+
213
+ class GoogleAIOverviewReference < GoogleAIOverviewReferenceSchema
214
+ end
215
+
216
+ # AI Overview text block
217
+ GoogleAIOverviewTextBlockSchema = DynamicSchema::Struct.define do
218
+ text String
219
+ position Integer
220
+ end
221
+
222
+ class GoogleAIOverviewTextBlock < GoogleAIOverviewTextBlockSchema
223
+ end
224
+
225
+ # AI Overview
226
+ GoogleAIOverviewSchema = DynamicSchema::Struct.define do
227
+ text_blocks GoogleAIOverviewTextBlock, array: true, as: :text_blocks
228
+ markdown String
229
+ reference_links GoogleAIOverviewReference, array: true, as: :reference_links
230
+ error String
231
+ end
232
+
233
+ class GoogleAIOverview < GoogleAIOverviewSchema
234
+ end
235
+
236
+ # Answer box
237
+ GoogleAnswerBoxSchema = DynamicSchema::Struct.define do
238
+ type String
239
+ title String
240
+ answer String
241
+ link String
242
+ snippet String
243
+ date String
244
+ thumbnail String
245
+ end
246
+
247
+ class GoogleAnswerBox < GoogleAnswerBoxSchema
248
+ end
249
+
250
+ # Inline image
251
+ GoogleInlineImageSchema = DynamicSchema::Struct.define do
252
+ title String
253
+ source String
254
+ link String
255
+ thumbnail String
256
+ original String
257
+ end
258
+
259
+ class GoogleInlineImage < GoogleInlineImageSchema
260
+ end
261
+
262
+ # Inline images container
263
+ GoogleInlineImagesSchema = DynamicSchema::Struct.define do
264
+ images GoogleInlineImage, array: true
265
+ more_link String, as: :more_link
266
+ end
267
+
268
+ class GoogleInlineImages < GoogleInlineImagesSchema
269
+ end
270
+
271
+ # Main search result
272
+ GoogleSearchResultSchema = DynamicSchema::Struct.define do
273
+ search_metadata GoogleSearchMetadata, as: :search_metadata
274
+ search_parameters GoogleSearchParameters, as: :search_parameters
275
+ search_information GoogleSearchInformation, as: :search_information
276
+ ai_overview GoogleAIOverview, as: :ai_overview
277
+ answer_box GoogleAnswerBox, as: :answer_box
278
+ knowledge_graph GoogleKnowledgeGraph, as: :knowledge_graph
279
+ ads GoogleAd, array: true
280
+ shopping_ads GoogleShoppingAd, array: true, as: :shopping_ads
281
+ organic_results GoogleOrganicResult, array: true, as: :organic_results
282
+ related_questions GoogleRelatedQuestion, array: true, as: :related_questions
283
+ inline_videos GoogleVideo, array: true, as: :inline_videos
284
+ top_stories GoogleTopStory, array: true, as: :top_stories
285
+ local_results GoogleLocalResult, array: true, as: :local_results
286
+ related_searches GoogleRelatedSearch, array: true, as: :related_searches
287
+ pagination GooglePagination
288
+ end
289
+
290
+ class GoogleSearchResult < GoogleSearchResultSchema
291
+ extend Forwardable
292
+ include Enumerable
293
+
294
+ def_delegators :organic_results, :each, :[], :count, :size, :length, :first, :last, :empty?
295
+
296
+ def success?
297
+ true
298
+ end
299
+ end
300
+
301
+ end
@@ -0,0 +1,10 @@
1
+ module SearchAPI
2
+ module Helpers
3
+
4
+ def string_camelize( string )
5
+ words = string.split( /[\s_\-]/ )
6
+ words.map.with_index { | word, index | index.zero? ? word.downcase : word.capitalize }.join
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,31 @@
1
+ module SearchAPI
2
+ class InstagramProfileOptions
3
+ include DynamicSchema::Definable
4
+ include Helpers
5
+
6
+ schema do
7
+ # required
8
+ username String
9
+ end
10
+
11
+ def self.build( options = nil, &block )
12
+ new( api_options: builder.build( options, &block ) )
13
+ end
14
+
15
+ def self.build!( options = nil, &block )
16
+ new( api_options: builder.build!( options, &block ) )
17
+ end
18
+
19
+ def initialize( options = {}, api_options: nil )
20
+ @options = self.class.builder.build( options || {} )
21
+ @options = api_options.merge( @options ) if api_options
22
+ end
23
+
24
+ def to_h
25
+ result = @options.to_h
26
+ result[ :engine ] = 'instagram_profile'
27
+ result
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ module SearchAPI
2
+ class InstagramProfileRequest < Request
3
+
4
+ def profile( username, options = nil, &block )
5
+ if options
6
+ options = options.is_a?( InstagramProfileOptions ) ? options : InstagramProfileOptions.build!( options.to_h )
7
+ options = options.to_h
8
+ else
9
+ options = { engine: 'instagram_profile' }
10
+ end
11
+ options[ :username ] = username.to_s
12
+
13
+ response = get( "#{ BASE_URI }/search", options, &block )
14
+ attributes = ( JSON.parse( response.body, symbolize_names: true ) rescue nil )
15
+
16
+ result = if response.success?
17
+ InstagramProfileResult.new( attributes || {} )
18
+ else
19
+ ErrorResult.new( response.status, attributes )
20
+ end
21
+
22
+ ResponseMethods.install( response, result )
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,117 @@
1
+ require 'forwardable'
2
+
3
+ module SearchAPI
4
+
5
+ # Instagram Search metadata
6
+ InstagramProfileMetadataSchema = DynamicSchema::Struct.define do
7
+ id String
8
+ status String
9
+ created_at String, as: :created_at
10
+ request_time_taken Float, as: :request_time_taken
11
+ parsing_time_taken Float, as: :parsing_time_taken
12
+ total_time_taken Float, as: :total_time_taken
13
+ end
14
+
15
+ class InstagramProfileMetadata < InstagramProfileMetadataSchema
16
+ end
17
+
18
+ # Instagram Search parameters
19
+ InstagramProfileParametersSchema = DynamicSchema::Struct.define do
20
+ engine String
21
+ username String
22
+ end
23
+
24
+ class InstagramProfileParameters < InstagramProfileParametersSchema
25
+ end
26
+
27
+ # Bio link
28
+ InstagramBioLinkSchema = DynamicSchema::Struct.define do
29
+ title String
30
+ url String
31
+ end
32
+
33
+ class InstagramBioLink < InstagramBioLinkSchema
34
+ end
35
+
36
+ # Tagged user
37
+ InstagramTaggedUserSchema = DynamicSchema::Struct.define do
38
+ username String
39
+ x Float
40
+ y Float
41
+ end
42
+
43
+ class InstagramTaggedUser < InstagramTaggedUserSchema
44
+ end
45
+
46
+ # Carousel item
47
+ InstagramCarouselItemSchema = DynamicSchema::Struct.define do
48
+ type String
49
+ link String
50
+ width Integer
51
+ height Integer
52
+ thumbnail String
53
+ end
54
+
55
+ class InstagramCarouselItem < InstagramCarouselItemSchema
56
+ end
57
+
58
+ # Post
59
+ InstagramPostSchema = DynamicSchema::Struct.define do
60
+ position Integer
61
+ id String
62
+ permalink String
63
+ type String
64
+ link String
65
+ width Integer
66
+ height Integer
67
+ thumbnail String
68
+ caption String
69
+ likes Integer
70
+ comments Integer
71
+ iso_date String, as: :iso_date
72
+ tagged_users InstagramTaggedUser, array: true, as: :tagged_users
73
+ carousel_items InstagramCarouselItem, array: true, as: :carousel_items
74
+ end
75
+
76
+ class InstagramPost < InstagramPostSchema
77
+ end
78
+
79
+ # Profile
80
+ InstagramProfileSchema = DynamicSchema::Struct.define do
81
+ username String
82
+ name String
83
+ bio String
84
+ avatar String
85
+ avatar_hd String, as: :avatar_hd
86
+ is_verified [ TrueClass, FalseClass ], as: :is_verified
87
+ is_business [ TrueClass, FalseClass ], as: :is_business
88
+ posts Integer
89
+ followers Integer
90
+ following Integer
91
+ external_link String, as: :external_link
92
+ bio_links InstagramBioLink, array: true, as: :bio_links
93
+ end
94
+
95
+ class InstagramProfile < InstagramProfileSchema
96
+ end
97
+
98
+ # Main Instagram profile result
99
+ InstagramProfileResultSchema = DynamicSchema::Struct.define do
100
+ search_metadata InstagramProfileMetadata, as: :search_metadata
101
+ search_parameters InstagramProfileParameters, as: :search_parameters
102
+ profile InstagramProfile
103
+ posts InstagramPost, array: true
104
+ error String
105
+ end
106
+
107
+ class InstagramProfileResult < InstagramProfileResultSchema
108
+ extend Forwardable
109
+
110
+ def_delegators :profile, :username, :name, :bio, :avatar, :followers, :following
111
+
112
+ def success?
113
+ self.error.nil?
114
+ end
115
+ end
116
+
117
+ end
@@ -0,0 +1,80 @@
1
+ module SearchAPI
2
+ module ModuleMethods
3
+
4
+ def connection( connection = nil )
5
+ @connection = connection if connection
6
+ @connection ||= Faraday.new { | builder | builder.adapter Faraday.default_adapter }
7
+ end
8
+
9
+ def api_key( api_key = nil )
10
+ @api_key = api_key || @api_key
11
+ @api_key
12
+ end
13
+
14
+ # Google Search
15
+ def google( query = nil, options = nil, &block )
16
+ GoogleSearchRequest.new.search( query, options, &block )
17
+ end
18
+
19
+ # YouTube Search
20
+ def youtube( query, options = nil, &block )
21
+ YouTubeSearchRequest.new.search( query, options, &block )
22
+ end
23
+
24
+ # Instagram Profile
25
+ def instagram( username, options = nil, &block )
26
+ InstagramProfileRequest.new.profile( username, options, &block )
27
+ end
28
+
29
+ # TikTok Profile
30
+ def tiktok( username, options = nil, &block )
31
+ TikTokProfileRequest.new.profile( username, options, &block )
32
+ end
33
+
34
+ # Google Finance
35
+ def finance( symbol, options = nil, &block )
36
+ GoogleFinanceRequest.new.quote( symbol, options, &block )
37
+ end
38
+
39
+ # Google Flights
40
+ def flights( options = nil, &block )
41
+ GoogleFlightsRequest.new.search( options, &block )
42
+ end
43
+
44
+ # Google Light (fast, lightweight search)
45
+ def google_light( query, options = nil, &block )
46
+ GoogleLightRequest.new.search( query, options, &block )
47
+ end
48
+
49
+ # Google News
50
+ def news( query, options = nil, &block )
51
+ GoogleNewsRequest.new.search( query, options, &block )
52
+ end
53
+
54
+ # Google News Portal
55
+ def news_portal( query = nil, options = nil, &block )
56
+ GoogleNewsPortalRequest.new.search( query, options, &block )
57
+ end
58
+
59
+ # Google News Light
60
+ def news_light( query, options = nil, &block )
61
+ GoogleNewsLightRequest.new.search( query, options, &block )
62
+ end
63
+
64
+ # Google Images
65
+ def images( query, options = nil, &block )
66
+ GoogleImagesRequest.new.search( query, options, &block )
67
+ end
68
+
69
+ # Google Local
70
+ def local( query, options = nil, &block )
71
+ GoogleLocalRequest.new.search( query, options, &block )
72
+ end
73
+
74
+ # Google Scholar
75
+ def scholar( query = nil, options = nil, &block )
76
+ GoogleScholarRequest.new.search( query, options, &block )
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,25 @@
1
+ module SearchAPI
2
+ class Request
3
+
4
+ BASE_URI = 'https://www.searchapi.io/api/v1'
5
+
6
+ def initialize( connection: nil, api_key: nil )
7
+ @connection = connection || SearchAPI.connection
8
+ @api_key = api_key || SearchAPI.api_key
9
+ raise ArgumentError,
10
+ "The API key is required but was not provided; configure it using " \
11
+ "'SearchAPI.api_key' or pass it directly." unless @api_key
12
+ end
13
+
14
+ protected
15
+
16
+ def get( uri, params = {}, &block )
17
+ @connection.get( uri ) do | request |
18
+ request.headers[ 'Authorization' ] = "Bearer #{ @api_key }"
19
+ request.params = params unless params.empty?
20
+ block.call( request ) if block
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ module SearchAPI
2
+ module ResponseMethods
3
+
4
+ def self.install( response, result )
5
+ response.instance_variable_set( "@_searchapi_result", result )
6
+ response.extend( ResponseMethods )
7
+ end
8
+
9
+ def result
10
+ @_searchapi_result
11
+ end
12
+
13
+ end
14
+ end