Skip to content

Commit 3bb65fc

Browse files
authored
✨ add get by URL methods (#277)
1 parent 8a54706 commit 3bb65fc

5 files changed

Lines changed: 93 additions & 86 deletions

File tree

‎lib/mindee/v2/client.rb‎

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,7 @@ def initialize(api_key: '')
1818
@mindee_api = Mindee::V2::HTTP::MindeeApiV2.new(api_key: api_key)
1919
end
2020

21-
# Retrieves a result from a given queue or URL to the result.
22-
# @param product [Class<Mindee::V2::Product::BaseProduct>] The return class.
23-
# @param resource [String] ID of the inference or URL to the result.
24-
# @return [Mindee::V2::Parsing::BaseResponse]
25-
def get_result(product, resource)
26-
@mindee_api.req_get_result(product, resource)
27-
end
28-
29-
# Retrieves an inference from a given queue or URL to the job.
30-
# @param job_id [String] ID of the job.
31-
# @return [Mindee::V2::Parsing::JobResponse]
32-
def get_job(job_id)
33-
@mindee_api.req_get_job(job_id)
34-
end
35-
36-
# Enqueue a document for async parsing.
21+
# Send a file to the asynchronous processing queue for inference.
3722
# @param product [Class<Mindee::V2::Product::BaseProduct>] The return class.
3823
# @param input_source [Mindee::Input::Source::LocalInputSource, Mindee::Input::Source::URLInputSource]
3924
# The source of the input document (local file or URL).
@@ -51,16 +36,48 @@ def enqueue(
5136
@mindee_api.req_post_product_enqueue(input_source, normalized_params)
5237
end
5338

54-
# Enqueues to an asynchronous endpoint and automatically polls for a response.
55-
#
39+
# Get the status of an inference that was previously enqueued.
40+
# Can be used for polling.
41+
# @param url [String] HTTPS URL to the job.
42+
# @return [Mindee::V2::Parsing::JobResponse]
43+
def get_job_by_url(url)
44+
@mindee_api.req_get_job_by_url(url)
45+
end
46+
47+
# Get the result of an inference that was previously enqueued.
48+
# @param product [Class<Mindee::V2::Product::BaseProduct>] The return class.
49+
# @param url [String] HTTPS URL to the result.
50+
# @return [Mindee::V2::Parsing::BaseResponse]
51+
def get_result_by_url(product, url)
52+
@mindee_api.req_get_result_by_url(product, url)
53+
end
54+
55+
# Get the result of an inference that was previously enqueued.
56+
# Prefer using `get_result_by_url` using the result URL returned by the Job.
57+
# @param product [Class<Mindee::V2::Product::BaseProduct>] The return class.
58+
# @param resource [String] ID of the inference or URL to the result.
59+
# @return [Mindee::V2::Parsing::BaseResponse]
60+
def get_result(product, resource)
61+
@mindee_api.req_get_result_by_id(product, resource)
62+
end
63+
64+
# Get the status of an inference that was previously enqueued.
65+
# Prefer using `get_job_by_url` with the polling URL returned by enqueue.
66+
# @param job_id [String] ID of the job.
67+
# @return [Mindee::V2::Parsing::JobResponse]
68+
def get_job(job_id)
69+
@mindee_api.req_get_job_by_id(job_id)
70+
end
71+
72+
# Send a file to the inference queue and return the results when complete.
5673
# @param product [Class<Mindee::V2::Product::BaseProduct>] The return class.
5774
# @param input_source [Mindee::Input::Source::LocalInputSource, Mindee::Input::Source::URLInputSource]
5875
# The source of the input document (local file or URL).
5976
# @param params [Hash, ClientOptions::BaseProductParameters] Parameters for the inference.
6077
# @param polling_options [Hash, PollingOptions, nil] Parameters for polling.
6178
# @param cancellation_token [Mindee::HTTP::CancellationToken, nil] Token for cancellation.
6279
# @return [Parsing::BaseResponse]
63-
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
80+
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
6481
def enqueue_and_get_result(
6582
product,
6683
input_source,
@@ -84,29 +101,31 @@ def enqueue_and_get_result(
84101

85102
sleep(normalized_params.polling_options.initial_delay_sec)
86103
retry_counter = 1
87-
poll_results = get_job(job_id)
104+
polling_url = enqueue_response.job.polling_url
105+
106+
job_response = get_job_by_url(polling_url)
88107

89108
while retry_counter < normalized_params.polling_options.max_retries
90-
if poll_results.job.status == 'Failed'
109+
if job_response.job.status == 'Failed'
91110
break
92-
elsif !poll_results.job.result_url.nil?
93-
return get_result(product, poll_results.job.result_url)
111+
elsif !job_response.job.result_url.nil?
112+
return get_result_by_url(product, job_response.job.result_url)
94113
end
95114

96115
logger.debug(
97116
"Successfully enqueued inference with job id: #{job_id}.\n" \
98117
"Attempt n°#{retry_counter}/#{normalized_params.polling_options.max_retries}.\n" \
99-
"Job status: #{poll_results.job.status}."
118+
"Job status: #{job_response.job.status}."
100119
)
101120

102121
raise Mindee::Error::MindeeError, 'Enqueueing of the document was canceled.' if cancellation_token&.canceled?
103122

104123
sleep(normalized_params.polling_options.delay_sec)
105-
poll_results = get_job(job_id)
124+
job_response = get_job_by_url(polling_url)
106125
retry_counter += 1
107126
end
108127

109-
error = poll_results.job.error
128+
error = job_response.job.error
110129
unless error.nil?
111130
err_to_raise = Mindee::Error::MindeeHTTPErrorV2.new(error)
112131
# NOTE: purposefully decoupled from the line above, otherwise rubocop thinks `error` is a `message` param.

‎lib/mindee/v2/http/mindee_api_v2.rb‎

Lines changed: 34 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -33,30 +33,44 @@ def req_post_product_enqueue(input_source, params)
3333
end
3434

3535
# Retrieves a result from a given queue.
36-
# @param product [Class<Mindee::V2::Product::BaseProduct>] The return class.
37-
# @param resource [String] ID of the inference or URL to the result.
36+
# @param product [Class<Mindee::V2::Product::BaseProduct>]
37+
# @param inference_id [String] ID of the inference or URL to the result.
3838
# @return [Mindee::V2::Parsing::BaseResponse]
39-
def req_get_result(product, resource)
40-
return req_get_result_url(product.response_type, resource) if uri?(resource)
41-
42-
@settings.check_api_key
43-
response = result_req_get(
44-
resource,
45-
product
46-
)
47-
product.response_type.new(process_response(response))
39+
def req_get_result_by_id(product, inference_id)
40+
req_get_result_by_url(product, "#{@settings.base_url}/v2/products/#{product.slug}/results/#{inference_id}")
4841
end
4942

5043
# Retrieves a queued job.
5144
#
5245
# @param job_id [String] ID of the job or URL to the job.
5346
# @return [Mindee::V2::Parsing::JobResponse]
54-
def req_get_job(job_id)
47+
def req_get_job_by_id(job_id)
48+
req_get_job_by_url("#{@settings.base_url}/v2/jobs/#{job_id}")
49+
end
50+
51+
# Retrieves a queued job from its polling URL.
52+
#
53+
# @param url [String] HTTPS URL to the job.
54+
# @return [Mindee::V2::Parsing::JobResponse]
55+
def req_get_job_by_url(url)
56+
validate_https_url!(url)
5557
@settings.check_api_key
56-
response = poll("#{@settings.base_url}/v2/jobs/#{job_id}")
58+
response = poll(url)
5759
Mindee::V2::Parsing::JobResponse.new(process_response(response))
5860
end
5961

62+
# Retrieves a result from its URL.
63+
#
64+
# @param product [Class<Mindee::V2::Product::BaseProduct>]
65+
# @param url [String] HTTPS URL to the result.
66+
# @return [Mindee::V2::Parsing::BaseResponse]
67+
def req_get_result_by_url(product, url)
68+
validate_https_url!(url)
69+
@settings.check_api_key
70+
response = poll(url)
71+
product.response_type.new(process_response(response))
72+
end
73+
6074
# Retrieves a list of resources with the given criteria.
6175
# @param params [ClientOptions::BaseSearchParameters] Search parameters.
6276
# @return [Mindee::V2::Parsing::Search::BaseSearchResponse] A search response containing the matching
@@ -85,35 +99,15 @@ def req_get_search(params)
8599

86100
private
87101

88-
# @param resource [String] Resource to check.
89-
# @return [Boolean]
90-
def uri?(resource)
91-
uri = URI.parse(resource)
92-
throw Mindee::Error::MindeeError, 'HTTP is not supported.' if uri.scheme == 'http'
93-
uri.scheme == 'https'
94-
rescue URI::BadURIError, URI::InvalidURIError
95-
false
96-
end
97-
98-
# Retrieves a queued job.
99-
#
100-
# @param url [String]
101-
# @return [Mindee::V2::Parsing::JobResponse]
102-
def req_get_job_url(url)
103-
@settings.check_api_key
104-
response = poll(url)
105-
Mindee::V2::Parsing::JobResponse.new(process_response(response))
106-
end
107-
108-
# Retrieves a queued job.
102+
# Validates that a URL uses HTTPS and includes a host.
109103
#
110-
# @param result_class [Class<Mindee::V2::Parsing::BaseResponse>]
111104
# @param url [String]
112-
# @return [Mindee::V2::Parsing::BaseResponse]
113-
def req_get_result_url(result_class, url)
114-
@settings.check_api_key
115-
response = poll(url)
116-
result_class.new(process_response(response))
105+
# @return [void]
106+
def validate_https_url!(url)
107+
uri = URI.parse(url)
108+
raise Mindee::Error::MindeeError, "Invalid URL: #{url}" unless uri.scheme == 'https' && !uri.host.to_s.empty?
109+
rescue URI::BadURIError, URI::InvalidURIError
110+
raise Mindee::Error::MindeeError, "Invalid URL: #{url}"
117111
end
118112

119113
# Converts an HTTP response to a parsed response object.
@@ -156,15 +150,6 @@ def poll(url)
156150
raise Mindee::Error::MindeeError, 'Could not resolve server response.'
157151
end
158152

159-
# Polls the API for the result of an inference.
160-
#
161-
# @param queue_id [String] ID of the queue.
162-
# @param product [Class<Mindee::V2::Product::BaseProduct>] The return class.
163-
# @return [Net::HTTPResponse]
164-
def result_req_get(queue_id, product)
165-
poll("#{@settings.base_url}/v2/products/#{product.slug}/results/#{queue_id}")
166-
end
167-
168153
# Handle parameters for the enqueue form
169154
# @param form_data [Array] Array of form fields
170155
# @param params [V2::Product::Extraction::Params::ExtractionParameters] Inference options.

‎sig/mindee/v2/client.rbs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ module Mindee
1515

1616
def get_job: (String job_id) -> V2::Parsing::JobResponse
1717

18+
def get_result_by_url: [T] (HTTP::_ProductClass[T] product, String url) -> T
19+
20+
def get_job_by_url: (String url) -> V2::Parsing::JobResponse
21+
1822
def enqueue: [T] (HTTP::_ProductClass[T] product, Input::Source::LocalInputSource | Input::Source::URLInputSource, Hash[String | Symbol, untyped] | ClientOptions::BaseProductParameters params) -> V2::Parsing::JobResponse
1923

2024
def enqueue_and_get_result: [T] (HTTP::_ProductClass[T] product, Input::Source::LocalInputSource | Input::Source::URLInputSource, Hash[String | Symbol, untyped] | ClientOptions::BaseProductParameters params, ?Hash[String | Symbol, untyped] | Input::PollingOptions | nil) -> T

‎sig/mindee/v2/http/mindee_api_v2.rbs‎

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,20 @@ module Mindee
2727

2828
def initialize: (?api_key: String?) -> void
2929

30-
def req_get_result: [T] (_ProductClass[T] product, String resource) -> T
30+
def req_get_result_by_id: [T] (_ProductClass[T] product, String inference_id) -> T
3131

3232
def req_post_product_enqueue: (Input::Source::LocalInputSource | Input::Source::URLInputSource, ClientOptions::BaseProductParameters) -> V2::Parsing::JobResponse
3333

34-
def req_get_job: (String) -> V2::Parsing::JobResponse
34+
def req_get_job_by_id: (String job_id) -> V2::Parsing::JobResponse
35+
36+
def req_get_job_by_url: (String url) -> V2::Parsing::JobResponse
37+
38+
def req_get_result_by_url: [T] (_ProductClass[T] product, String url) -> T
3539

3640
def process_response: (Net::HTTPResponse?) -> Hash[String | Symbol, untyped]
3741

3842
def poll: (String) -> Net::HTTPResponse
3943

40-
def result_req_get: [T] (String, _ProductClass[T] product) -> Net::HTTPResponse
41-
4244
def enqueue: (Input::Source::LocalInputSource | Input::Source::URLInputSource, ClientOptions::BaseProductParameters) -> Net::HTTPResponse?
4345

4446
def req_get_search: [T] (_SearchParameters[T] params) -> T
@@ -47,11 +49,7 @@ module Mindee
4749

4850
def enqueue_form_options: (Array[Array[untyped]], V2::Product::Extraction::Params::ExtractionParameters) -> Array[Array[untyped]]
4951

50-
def req_get_job_url: (String) -> V2::Parsing::JobResponse
51-
52-
def req_get_result_url: [T] (_ResponseFactory[T] result_class, String url) -> T
53-
54-
def uri?: (String) -> bool
52+
def validate_https_url!: (String) -> void
5553
end
5654
end
5755
end

‎spec/v2/client_v2_spec.rb‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def stub_next_request_with(method, hash:, status_code: 0)
119119
resp.job.completed_at.strftime('%Y-%m-%dT%H:%M:%S.%6N')
120120
).to eq('2026-04-20T18:32:02.734312')
121121
end
122+
122123
it 'poll builds a real Net::HTTP::Get request without a Transfer-Encoding header' do
123124
job_json = File.read(File.join(V2_DATA_DIR, 'job', 'ok_processing.json'))
124125
captured_request = nil
@@ -161,7 +162,7 @@ def stub_next_request_with(method, hash:, status_code: 0)
161162
before do
162163
allow(client).to receive(:sleep)
163164
allow(client).to receive(:enqueue).and_return(mock_enqueue_res)
164-
allow(client).to receive(:get_job).and_return(mock_processing_res)
165+
allow(client).to receive(:get_job_by_url).and_return(mock_processing_res)
165166
end
166167

167168
it 'raises MindeeError when token is cancelled before first poll' do
@@ -178,7 +179,7 @@ def stub_next_request_with(method, hash:, status_code: 0)
178179
it 'raises MindeeError when token is cancelled during poll loop' do
179180
token = Mindee::HTTP::CancellationToken.new
180181
call_count = 0
181-
allow(client).to receive(:get_job) do
182+
allow(client).to receive(:get_job_by_url) do
182183
call_count += 1
183184
token.cancel if call_count == 1
184185
mock_processing_res

0 commit comments

Comments
 (0)