1616)
1717from airbyte_cdk .sources .declarative .decoders import Decoder
1818from airbyte_cdk .sources .declarative .decoders .json_decoder import JsonDecoder
19- from airbyte_cdk .sources .declarative .interpolation .interpolated_string import InterpolatedString
19+ from airbyte_cdk .sources .declarative .interpolation .interpolated_string import (
20+ InterpolatedString ,
21+ )
2022from airbyte_cdk .sources .declarative .requesters .request_options .interpolated_request_options_provider import (
2123 InterpolatedRequestOptionsProvider ,
2224)
2628from airbyte_cdk .sources .streams .http import HttpClient
2729from airbyte_cdk .sources .streams .http .error_handlers import ErrorHandler
2830from airbyte_cdk .sources .types import Config , EmptyString , StreamSlice , StreamState
29- from airbyte_cdk .utils .mapping_helpers import combine_mappings , get_interpolation_context
31+ from airbyte_cdk .utils .mapping_helpers import (
32+ combine_mappings ,
33+ get_interpolation_context ,
34+ )
3035
3136
3237@dataclass
@@ -155,7 +160,9 @@ def get_request_params(
155160 next_page_token : Optional [Mapping [str , Any ]] = None ,
156161 ) -> MutableMapping [str , Any ]:
157162 return self ._request_options_provider .get_request_params (
158- stream_state = stream_state , stream_slice = stream_slice , next_page_token = next_page_token
163+ stream_state = stream_state ,
164+ stream_slice = stream_slice ,
165+ next_page_token = next_page_token ,
159166 )
160167
161168 def get_request_headers (
@@ -166,7 +173,9 @@ def get_request_headers(
166173 next_page_token : Optional [Mapping [str , Any ]] = None ,
167174 ) -> Mapping [str , Any ]:
168175 return self ._request_options_provider .get_request_headers (
169- stream_state = stream_state , stream_slice = stream_slice , next_page_token = next_page_token
176+ stream_state = stream_state ,
177+ stream_slice = stream_slice ,
178+ next_page_token = next_page_token ,
170179 )
171180
172181 # fixing request options provider types has a lot of dependencies
@@ -195,7 +204,9 @@ def get_request_body_json( # type: ignore
195204 next_page_token : Optional [Mapping [str , Any ]] = None ,
196205 ) -> Optional [Mapping [str , Any ]]:
197206 return self ._request_options_provider .get_request_body_json (
198- stream_state = stream_state , stream_slice = stream_slice , next_page_token = next_page_token
207+ stream_state = stream_state ,
208+ stream_slice = stream_slice ,
209+ next_page_token = next_page_token ,
199210 )
200211
201212 @property
@@ -350,9 +361,24 @@ def _join_url(cls, url_base: str, path: str) -> str:
350361 path (str): The path to join with the base URL.
351362
352363 Returns:
353- str: The concatenated URL with the trailing slash (if any) removed.
364+ str: The resulting joined URL.
365+
366+ Note:
367+ Related issue: https://github.com/airbytehq/airbyte-internal-issues/issues/11869
368+ - If the path is an empty string or None, the method returns the base URL with any trailing slash removed.
369+
370+ Example:
371+ 1) _join_url("https://example.com/api/", "endpoint") >> 'https://example.com/api/endpoint'
372+ 2) _join_url("https://example.com/api", "/endpoint") >> 'https://example.com/api/endpoint'
373+ 3) _join_url("https://example.com/api/", "") >> 'https://example.com/api'
374+ 4) _join_url("https://example.com/api", None) >> 'https://example.com/api'
354375 """
355- return urljoin (url_base , path ).rstrip ("/" )
376+
377+ # return a full-url if provided directly from interpolation context
378+ if path == EmptyString or path is None :
379+ return url_base .rstrip ("/" )
380+
381+ return urljoin (url_base , path )
356382
357383 def send_request (
358384 self ,
0 commit comments