Skip to content

Commit 0121979

Browse files
curquizatpayet
andauthored
Improve error handler (#65)
* Use the new error handler of MeiliSearch API * Improve the tests to check MS code and type * Add comments * Fix linter errors * Add MeiliSearch::CommunicationError * Upd rubocop_todo * Remove useless byebug * Change minor naming * Remove useless error in get_index * Update lib/meilisearch/error.rb Co-authored-by: Thomas Payet <[email protected]> * Update lib/meilisearch/error.rb Co-authored-by: Thomas Payet <[email protected]> Co-authored-by: Thomas Payet <[email protected]>
1 parent 487e282 commit 0121979

File tree

13 files changed

+164
-104
lines changed

13 files changed

+164
-104
lines changed

.rubocop_todo.yml

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,28 @@
11
# This configuration was generated by
22
# `rubocop --auto-gen-config`
3-
# on 2020-06-04 16:06:38 +0200 using RuboCop version 0.85.0.
3+
# on 2020-07-05 14:27:43 UTC using RuboCop version 0.86.0.
44
# The point is for the user to remove these configuration records
55
# one by one as the offenses are removed from the code base.
66
# Note that changes in the inspected code, or installation of new
77
# versions of RuboCop, may require this file to be generated again.
88

9-
# Offense count: 20
9+
# Offense count: 19
1010
# Configuration parameters: CountComments, ExcludedMethods.
1111
# ExcludedMethods: refine
1212
Metrics/BlockLength:
13-
Max: 463
13+
Max: 465
1414

1515
# Offense count: 1
1616
# Configuration parameters: CountComments.
1717
Metrics/ClassLength:
1818
Max: 190
1919

20-
# Offense count: 2
21-
# Configuration parameters: CountComments, ExcludedMethods.
22-
Metrics/MethodLength:
23-
Max: 11
24-
2520
# Offense count: 1
2621
Naming/AccessorMethodName:
2722
Exclude:
2823
- 'lib/meilisearch/index.rb'
2924

30-
# Offense count: 6
25+
# Offense count: 7
3126
Style/Documentation:
3227
Exclude:
3328
- 'spec/**/*'

lib/meilisearch/client.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ def delete_index(index_uid)
3030
# Usage:
3131
# client.index('indexUID')
3232
def index(index_uid)
33-
raise IndexUidError if index_uid.nil?
34-
3533
index_object(index_uid)
3634
end
3735
alias get_index index

lib/meilisearch/error.rb

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,58 @@
11
# frozen_string_literal: true
22

33
module MeiliSearch
4-
class MeiliSearchError < StandardError; end
5-
class IndexUidError < MeiliSearchError; end
6-
class MeiliSearchTimeoutError < MeiliSearchError
7-
attr_reader :message
4+
class ApiError < StandardError
5+
attr_reader :http_code # e.g. 400, 404...
6+
attr_reader :http_message # e.g. Bad Request, Not Found...
7+
attr_reader :http_body # The response body received from the MeiliSearch API
8+
attr_reader :ms_code # The error code given by the MeiliSearch API
9+
attr_reader :ms_type # The error type given by the MeiliSearch API
10+
attr_reader :ms_link # The documentation link given by the MeiliSearch API
11+
attr_reader :ms_message # The error message given by the MeiliSearch API
12+
attr_reader :message # The detailed error message of this error class
813

9-
def initialize
10-
@message = "MeiliSearchTimeoutError: update wasn't processed in the expected time"
14+
alias code ms_code
15+
alias type ms_type
16+
alias link ms_link
17+
18+
def initialize(http_code, http_message, http_body)
19+
get_meilisearch_error_info(http_body) unless http_body.nil? || http_body.empty?
20+
@http_code = http_code
21+
@http_message = http_message
22+
@ms_message ||= 'MeiliSearch API has not returned any error message'
23+
@ms_link ||= '<no documentation link found>'
24+
@message = "#{http_code} #{http_message} - #{@ms_message.capitalize}. See #{ms_link}."
25+
super(details)
26+
end
27+
28+
def get_meilisearch_error_info(http_body)
29+
@http_body = JSON.parse(http_body)
30+
@ms_code = @http_body['errorCode']
31+
@ms_message = @http_body['message']
32+
@ms_type = @http_body['errorType']
33+
@ms_link = @http_body['errorLink']
1134
end
1235

13-
def to_s
14-
"#{@message}."
36+
def details
37+
"MeiliSearch::ApiError - code: #{@ms_code} - type: #{ms_type} - message: #{@ms_message} - link: #{ms_link}"
1538
end
1639
end
1740

18-
class HTTPError < MeiliSearchError
19-
attr_reader :status
41+
class CommunicationError < StandardError
2042
attr_reader :message
21-
attr_reader :http_body
22-
attr_reader :http_body_message
23-
attr_reader :details
24-
25-
alias code status
26-
alias body http_body
27-
alias body_message http_body_message
28-
29-
def initialize(status, message, http_body, details = nil)
30-
@status = status
31-
unless http_body.nil? || http_body.empty?
32-
@http_body = JSON.parse(http_body)
33-
@http_body_message = @http_body['message']
34-
end
35-
@message = message.capitalize
36-
@message = "#{@message} - #{@http_body_message.capitalize}" unless @http_body_message.nil?
37-
@details = details
43+
44+
def initialize(message)
45+
@message = "An error occurred while trying to connect to the MeiliSearch instance: #{message}"
46+
super(@message)
3847
end
48+
end
3949

40-
def to_s
41-
final_message = @details.nil? ? @message : "#{@message}. #{@details}"
42-
"#{@status}: #{final_message}."
50+
class TimeoutError < StandardError
51+
attr_reader :message
52+
53+
def initialize
54+
@message = 'The update was not processed in the expected time'
55+
super(@message)
4356
end
4457
end
4558
end

lib/meilisearch/http_request.rb

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,57 +16,63 @@ def initialize(url, api_key = nil)
1616
}.compact
1717
end
1818

19-
def http_get(path = '', query_params = {})
20-
response = self.class.get(
21-
@base_url + path,
22-
query: query_params,
23-
headers: @headers,
24-
timeout: 1
19+
def http_get(relative_path = '', query_params = {})
20+
send_request(
21+
proc { |path, config| self.class.get(path, config) },
22+
relative_path,
23+
query_params
2524
)
26-
validate(response)
2725
end
2826

29-
def http_post(path = '', body = nil, query_params = nil)
30-
body = body.to_json unless body.nil?
31-
response = self.class.post(
32-
@base_url + path,
33-
{
34-
body: body,
35-
query: query_params,
36-
headers: @headers,
37-
timeout: 1
38-
}.compact
27+
def http_post(relative_path = '', body = nil, query_params = nil)
28+
send_request(
29+
proc { |path, config| self.class.post(path, config) },
30+
relative_path,
31+
query_params,
32+
body
3933
)
40-
validate(response)
4134
end
4235

43-
def http_put(path = '', body = nil, query_params = nil)
44-
body = body.to_json unless body.nil?
45-
response = self.class.put(
46-
@base_url + path,
47-
{
48-
body: body,
49-
query: query_params,
50-
headers: @headers,
51-
timeout: 1
52-
}.compact
36+
def http_put(relative_path = '', body = nil, query_params = nil)
37+
send_request(
38+
proc { |path, config| self.class.put(path, config) },
39+
relative_path,
40+
query_params,
41+
body
5342
)
54-
validate(response)
5543
end
5644

57-
def http_delete(path = '')
58-
response = self.class.delete(
59-
@base_url + path,
60-
headers: @headers,
61-
timeout: 1
45+
def http_delete(relative_path = '')
46+
send_request(
47+
proc { |path, config| self.class.delete(path, config) },
48+
relative_path
6249
)
63-
validate(response)
6450
end
6551

6652
private
6753

54+
def send_request(http_method, relative_path, query_params = nil, body = nil)
55+
config = http_config(query_params, body)
56+
begin
57+
response = http_method.call(@base_url + relative_path, config)
58+
rescue Errno::ECONNREFUSED => e
59+
raise CommunicationError, e.message
60+
end
61+
validate(response)
62+
end
63+
64+
def http_config(query_params, body)
65+
body = body.to_json unless body.nil?
66+
{
67+
headers: @headers,
68+
query: query_params,
69+
body: body,
70+
timeout: 1
71+
}.compact
72+
end
73+
6874
def validate(response)
69-
raise HTTPError.new(response.code, response.message, response.body) unless response.success?
75+
raise ApiError.new(response.code, response.message, response.body) unless response.success?
7076

7177
response.parsed_response
7278
end

lib/meilisearch/index.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def wait_for_pending_update(update_id, timeout_in_ms = 5000, interval_in_ms = 50
113113
end
114114
end
115115
rescue Timeout::Error
116-
raise MeiliSearch::MeiliSearchTimeoutError
116+
raise MeiliSearch::TimeoutError
117117
end
118118

119119
### STATS

spec/meilisearch/client/indexes_spec.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@
3434
it 'fails to create an index with an uid already taken' do
3535
expect do
3636
@client.create_index(@uid1)
37-
end.to raise_meilisearch_http_error_with(400)
37+
end.to raise_meilisearch_api_error_with(400, 'index_already_exists', 'invalid_request_error')
3838
end
3939

4040
it 'fails to create an index with bad UID format' do
4141
expect do
4242
@client.create_index('two words')
43-
end.to raise_meilisearch_http_error_with(400)
43+
end.to raise_meilisearch_api_error_with(400, 'invalid_index_uid', 'invalid_request_error')
4444
end
4545

4646
it 'gets list of indexes' do
@@ -67,11 +67,11 @@
6767

6868
it 'deletes index' do
6969
expect(@client.delete_index(@uid1)).to be_nil
70-
expect { @client.show_index(@uid1) }.to raise_meilisearch_http_error_with(404)
70+
expect { @client.show_index(@uid1) }.to raise_index_not_found_meilisearch_api_error
7171
expect(@client.delete_index(@uid2)).to be_nil
72-
expect { @client.show_index(@uid2) }.to raise_meilisearch_http_error_with(404)
72+
expect { @client.show_index(@uid2) }.to raise_index_not_found_meilisearch_api_error
7373
expect(@client.delete_index(@uid3)).to be_nil
74-
expect { @client.show_index(@uid3) }.to raise_meilisearch_http_error_with(404)
74+
expect { @client.show_index(@uid3) }.to raise_index_not_found_meilisearch_api_error
7575
expect(@client.indexes.count).to eq(0)
7676
end
7777

spec/meilisearch/client/keys_spec.rb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,24 @@
2121
it 'fails to get settings if public key used' do
2222
public_key = @client.keys['public']
2323
new_client = MeiliSearch::Client.new($URL, public_key)
24-
expect { new_client.index(@uid).settings }.to raise_meilisearch_http_error_with(403)
24+
expect do
25+
new_client.index(@uid).settings
26+
end.to raise_meilisearch_api_error_with(403, 'invalid_token', 'authentication_error')
2527
end
2628

2729
it 'fails to get keys if private key used' do
2830
private_key = @client.keys['private']
2931
new_client = MeiliSearch::Client.new($URL, private_key)
30-
expect { new_client.keys }.to raise_meilisearch_http_error_with(403)
32+
expect do
33+
new_client.keys
34+
end.to raise_meilisearch_api_error_with(403, 'invalid_token', 'authentication_error')
3135
end
3236

3337
it 'fails to search if no key used' do
3438
new_client = MeiliSearch::Client.new($URL)
35-
expect { new_client.index(@uid).settings }.to raise_meilisearch_http_error_with(401)
39+
expect do
40+
new_client.index(@uid).settings
41+
end.to raise_meilisearch_api_error_with(401, 'missing_authorization_header', 'authentication_error')
3642
end
3743

3844
it 'succeeds to search when using public key' do

spec/meilisearch/index/base_spec.rb

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,22 @@
4444
new_primary_key = 'id_test'
4545
expect do
4646
@index2.update(primaryKey: new_primary_key)
47-
end.to raise_meilisearch_http_error_with(400)
47+
end.to raise_bad_request_meilisearch_api_error
48+
# temporary, will be raise a 'primary_key_already_present' code in the next MS release
4849
end
4950

5051
it 'deletes index' do
5152
expect(@index1.delete).to be_nil
52-
expect { @index1.show }.to raise_meilisearch_http_error_with(404)
53+
expect { @index1.show }.to raise_index_not_found_meilisearch_api_error
5354
expect(@index2.delete).to be_nil
54-
expect { @index2.show }.to raise_meilisearch_http_error_with(404)
55+
expect { @index2.show }.to raise_index_not_found_meilisearch_api_error
5556
end
5657

5758
it 'fails to manipulate index object after deletion' do
58-
expect { @index2.primary_key }.to raise_meilisearch_http_error_with(404)
59-
expect { @index2.show }.to raise_meilisearch_http_error_with(404)
60-
expect { @index2.update(primaryKey: 'id_test') }.to raise_meilisearch_http_error_with(404)
61-
expect { @index2.delete }.to raise_meilisearch_http_error_with(404)
59+
expect { @index2.primary_key }.to raise_index_not_found_meilisearch_api_error
60+
expect { @index2.show }.to raise_index_not_found_meilisearch_api_error
61+
expect { @index2.update(primaryKey: 'id_test') }.to raise_index_not_found_meilisearch_api_error
62+
expect { @index2.delete }.to raise_index_not_found_meilisearch_api_error
6263
end
6364

6465
it 'works with method aliases' do

spec/meilisearch/index/documents_spec.rb

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@
150150
expect(response).to be_a(Hash)
151151
expect(response).to have_key('updateId')
152152
expect(index.documents.size).to eq(documents.count - 1)
153-
expect { index.document(id) }.to raise_meilisearch_http_error_with(404)
153+
expect { index.document(id) }.to raise_document_not_found_meilisearch_api_error
154154
end
155155

156156
it 'does nothing when trying to delete a document which does not exist' do
@@ -160,7 +160,7 @@
160160
expect(response).to be_a(Hash)
161161
expect(response).to have_key('updateId')
162162
expect(index.documents.size).to eq(documents.count - 1)
163-
expect { index.document(id) }.to raise_meilisearch_http_error_with(404)
163+
expect { index.document(id) }.to raise_document_not_found_meilisearch_api_error
164164
end
165165

166166
it 'deletes one document from index (with delete-batch route)' do
@@ -170,7 +170,7 @@
170170
expect(response).to be_a(Hash)
171171
expect(response).to have_key('updateId')
172172
expect(index.documents.size).to eq(documents.count - 2)
173-
expect { index.document(id) }.to raise_meilisearch_http_error_with(404)
173+
expect { index.document(id) }.to raise_document_not_found_meilisearch_api_error
174174
end
175175

176176
it 'deletes one document from index (with delete-batch route as an array of one uid)' do
@@ -180,7 +180,7 @@
180180
expect(response).to be_a(Hash)
181181
expect(response).to have_key('updateId')
182182
expect(index.documents.size).to eq(documents.count - 3)
183-
expect { index.document(id) }.to raise_meilisearch_http_error_with(404)
183+
expect { index.document(id) }.to raise_document_not_found_meilisearch_api_error
184184
end
185185

186186
it 'deletes multiples documents from index' do
@@ -347,7 +347,10 @@
347347
end
348348

349349
it 'returns a 400' do
350-
expect { index.add_documents(documents) }.to raise_meilisearch_http_error_with(400)
350+
expect do
351+
index.add_documents(documents)
352+
end.to raise_bad_request_meilisearch_api_error
353+
# temporary, will be return a 'missing_primary_key' code in the next MS release
351354
end
352355
end
353356

0 commit comments

Comments
 (0)