1
1
# frozen_string_literal: true
2
2
3
- require 'httparty'
3
+ require 'typhoeus'
4
+ require 'oj'
4
5
5
6
module Typesense
6
7
class ApiCall
7
- include HTTParty
8
-
9
8
API_KEY_HEADER_NAME = 'X-TYPESENSE-API-KEY'
10
9
11
10
def initialize ( configuration )
@@ -30,38 +29,38 @@ def post(endpoint, parameters = {})
30
29
31
30
perform_request :post ,
32
31
endpoint ,
33
- body : body ,
34
- headers : default_headers . merge ( headers )
32
+ headers ,
33
+ body : body
35
34
end
36
35
37
36
def put ( endpoint , parameters = { } )
38
37
headers , body = extract_headers_and_body_from ( parameters )
39
38
40
39
perform_request :put ,
41
40
endpoint ,
42
- body : body ,
43
- headers : default_headers . merge ( headers )
41
+ headers ,
42
+ body : body
44
43
end
45
44
46
45
def get ( endpoint , parameters = { } )
47
46
headers , query = extract_headers_and_query_from ( parameters )
48
47
49
48
perform_request :get ,
50
49
endpoint ,
51
- query : query ,
52
- headers : default_headers . merge ( headers )
50
+ headers ,
51
+ params : query
53
52
end
54
53
55
54
def delete ( endpoint , parameters = { } )
56
55
headers , query = extract_headers_and_query_from ( parameters )
57
56
58
57
perform_request :delete ,
59
58
endpoint ,
60
- query : query ,
61
- headers : default_headers . merge ( headers )
59
+ headers ,
60
+ params : query
62
61
end
63
62
64
- def perform_request ( method , endpoint , options = { } )
63
+ def perform_request ( method , endpoint , headers = { } , options = { } )
65
64
@configuration . validate!
66
65
last_exception = nil
67
66
@logger . debug "Performing #{ method . to_s . upcase } request: #{ endpoint } "
@@ -71,24 +70,31 @@ def perform_request(method, endpoint, options = {})
71
70
@logger . debug "Attempting #{ method . to_s . upcase } request Try ##{ num_tries } to Node #{ node [ :index ] } "
72
71
73
72
begin
74
- response_object = self . class . send ( method ,
75
- uri_for ( endpoint , node ) ,
76
- default_options . merge ( options ) )
77
- response_code = response_object . response . code . to_i
78
- set_node_healthcheck ( node , is_healthy : true ) if response_code >= 1 && response_code <= 499
79
-
80
- @logger . debug "Request to Node #{ node [ :index ] } was successfully made (at the network layer). Response Code was #{ response_code } ."
73
+ response = Typhoeus ::Request . new ( uri_for ( endpoint , node ) ,
74
+ {
75
+ method : method ,
76
+ headers : default_headers . merge ( headers ) ,
77
+ timeout : @connection_timeout_seconds
78
+ } . merge ( options ) ) . run
79
+ set_node_healthcheck ( node , is_healthy : true ) if response . code >= 1 && response . code <= 499
80
+
81
+ @logger . debug "Request to Node #{ node [ :index ] } was successfully made (at the network layer). Response Code was #{ response . code } ."
82
+
83
+ parsed_response = if response . headers && ( response . headers [ 'content-type' ] || '' ) . include? ( 'application/json' )
84
+ Oj . load ( response . body )
85
+ else
86
+ response . body
87
+ end
81
88
82
89
# If response is 2xx return the object, else raise the response as an exception
83
- return response_object . parsed_response if response_object . response . code_type <= Net :: HTTPSuccess # 2xx
90
+ return parsed_response if response . code >= 200 && response . code <= 299
84
91
85
- exception_message = ( response_object . parsed_response && response_object . parsed_response [ 'message' ] ) || 'Error'
86
- raise custom_exception_klass_for ( response_object . response ) , exception_message
87
- rescue SocketError , Net ::ReadTimeout , Net ::OpenTimeout ,
88
- EOFError , Net ::HTTPBadResponse , Net ::HTTPHeaderSyntaxError , Net ::ProtocolError ,
92
+ exception_message = ( parsed_response && parsed_response [ 'message' ] ) || 'Error'
93
+ raise custom_exception_klass_for ( response ) , exception_message
94
+ rescue SocketError , EOFError ,
89
95
Errno ::EINVAL , Errno ::ENETDOWN , Errno ::ENETUNREACH , Errno ::ENETRESET , Errno ::ECONNABORTED , Errno ::ECONNRESET ,
90
96
Errno ::ETIMEDOUT , Errno ::ECONNREFUSED , Errno ::EHOSTDOWN , Errno ::EHOSTUNREACH ,
91
- Timeout ::Error , HTTParty :: ResponseError , Typesense ::Error ::ServerError , Typesense ::Error ::HTTPStatus0Error => e
97
+ Typesense ::Error :: TimeoutError , Typesense ::Error ::ServerError , Typesense ::Error ::HTTPStatus0Error => e
92
98
# Rescue network layer exceptions and HTTP 5xx errors, so the loop can continue.
93
99
# Using loops for retries instead of rescue...retry to maintain consistency with client libraries in
94
100
# other languages that might not support the same construct.
@@ -108,7 +114,7 @@ def perform_request(method, endpoint, options = {})
108
114
def extract_headers_and_body_from ( parameters )
109
115
if json_request? ( parameters )
110
116
headers = { 'Content-Type' => 'application/json' }
111
- body = sanitize_parameters ( parameters ) . to_json
117
+ body = Oj . dump ( sanitize_parameters ( parameters ) )
112
118
else
113
119
headers = { }
114
120
body = parameters [ :body ]
@@ -199,35 +205,31 @@ def set_node_healthcheck(node, is_healthy:)
199
205
end
200
206
201
207
def custom_exception_klass_for ( response )
202
- response_code_type = response . code_type
203
- if response_code_type <= Net ::HTTPBadRequest # 400
208
+ if response . code == 400
204
209
Typesense ::Error ::RequestMalformed
205
- elsif response_code_type <= Net :: HTTPUnauthorized # 401
210
+ elsif response . code == 401
206
211
Typesense ::Error ::RequestUnauthorized
207
- elsif response_code_type <= Net :: HTTPNotFound # 404
212
+ elsif response . code == 404
208
213
Typesense ::Error ::ObjectNotFound
209
- elsif response_code_type <= Net :: HTTPConflict # 409
214
+ elsif response . code == 409
210
215
Typesense ::Error ::ObjectAlreadyExists
211
- elsif response_code_type <= Net :: HTTPUnprocessableEntity # 422
216
+ elsif response . code == 422
212
217
Typesense ::Error ::ObjectUnprocessable
213
- elsif response_code_type <= Net :: HTTPServerError # 5xx
218
+ elsif response . code >= 500 && response . code <= 599
214
219
Typesense ::Error ::ServerError
215
- elsif response . code . to_i . zero?
220
+ elsif response . timed_out?
221
+ Typesense ::Error ::TimeoutError
222
+ elsif response . code . zero?
216
223
Typesense ::Error ::HTTPStatus0Error
217
224
else
218
225
Typesense ::Error ::HTTPError
219
226
end
220
227
end
221
228
222
- def default_options
223
- {
224
- timeout : @connection_timeout_seconds
225
- }
226
- end
227
-
228
229
def default_headers
229
230
{
230
- API_KEY_HEADER_NAME . to_s => @api_key
231
+ API_KEY_HEADER_NAME . to_s => @api_key ,
232
+ 'User-Agent' => 'Typesense Ruby Client'
231
233
}
232
234
end
233
235
end
0 commit comments