11from __future__ import annotations
22
3+ import warnings
34from functools import cached_property
4- from typing import TYPE_CHECKING
5+ from typing import TYPE_CHECKING , ClassVar
56
67from apify_client ._client_registry import ClientRegistry , ClientRegistryAsync
78from apify_client ._consts import (
1112 DEFAULT_MIN_DELAY_BETWEEN_RETRIES ,
1213 DEFAULT_TIMEOUT ,
1314)
14- from apify_client ._http_clients import AsyncHttpClient , SyncHttpClient
15+ from apify_client ._http_clients import HttpClient , HttpClientAsync
1516from apify_client ._resource_clients import (
1617 ActorClient ,
1718 ActorClientAsync ,
8182class ApifyClient :
8283 """The Apify API client."""
8384
85+ _OVERRIDABLE_DEFAULT_HEADERS : ClassVar [set [str ]] = {'Accept' , 'Authorization' , 'Accept-Encoding' , 'User-Agent' }
86+
8487 def __init__ (
8588 self ,
8689 token : str | None = None ,
@@ -90,6 +93,7 @@ def __init__(
9093 max_retries : int = DEFAULT_MAX_RETRIES ,
9194 min_delay_between_retries : timedelta = DEFAULT_MIN_DELAY_BETWEEN_RETRIES ,
9295 timeout : timedelta = DEFAULT_TIMEOUT ,
96+ headers : dict [str , str ] | None = None ,
9397 ) -> None :
9498 """Initialize a new instance.
9599
@@ -103,11 +107,15 @@ def __init__(
103107 min_delay_between_retries: How long will the client wait between retrying requests
104108 (increases exponentially from this value).
105109 timeout: The socket timeout of the HTTP requests sent to the Apify API.
110+ headers: Additional HTTP headers to include in all API requests.
106111 """
107112 # We need to do this because of mocking in tests and default mutable arguments.
108113 api_url = DEFAULT_API_URL if api_url is None else api_url
109114 api_public_url = DEFAULT_API_URL if api_public_url is None else api_public_url
110115
116+ if headers :
117+ self ._check_custom_headers (headers )
118+
111119 self ._token = token
112120 """Apify API token for authentication."""
113121
@@ -120,12 +128,13 @@ def __init__(
120128 self ._statistics = ClientStatistics ()
121129 """Collector for client request statistics."""
122130
123- self ._http_client = SyncHttpClient (
131+ self ._http_client = HttpClient (
124132 token = token ,
125133 timeout = timeout or DEFAULT_TIMEOUT ,
126134 max_retries = max_retries or DEFAULT_MAX_RETRIES ,
127135 min_delay_between_retries = min_delay_between_retries or DEFAULT_MIN_DELAY_BETWEEN_RETRIES ,
128136 statistics = self ._statistics ,
137+ headers = headers ,
129138 )
130139 """HTTP client used to communicate with the Apify API."""
131140
@@ -172,6 +181,18 @@ def _base_kwargs(self) -> dict:
172181 'client_registry' : self ._client_registry ,
173182 }
174183
184+ def _check_custom_headers (self , headers : dict [str , str ]) -> None :
185+ """Warn if custom headers override important default headers."""
186+ overwrite_headers = [key for key in headers if key .title () in self ._OVERRIDABLE_DEFAULT_HEADERS ]
187+ if overwrite_headers :
188+ warnings .warn (
189+ f'{ ", " .join (overwrite_headers )} headers of { self .__class__ .__name__ } was overridden with an '
190+ 'explicit value. A wrong header value can lead to API errors, it is recommended to use the default '
191+ f'value for following headers: { ", " .join (self ._OVERRIDABLE_DEFAULT_HEADERS )} .' ,
192+ category = UserWarning ,
193+ stacklevel = 3 ,
194+ )
195+
175196 @property
176197 def token (self ) -> str | None :
177198 """The Apify API token used by the client."""
@@ -322,6 +343,8 @@ def store(self) -> StoreCollectionClient:
322343class ApifyClientAsync :
323344 """The asynchronous version of the Apify API client."""
324345
346+ _OVERRIDABLE_DEFAULT_HEADERS : ClassVar [set [str ]] = {'Accept' , 'Authorization' , 'Accept-Encoding' , 'User-Agent' }
347+
325348 def __init__ (
326349 self ,
327350 token : str | None = None ,
@@ -331,6 +354,7 @@ def __init__(
331354 max_retries : int = DEFAULT_MAX_RETRIES ,
332355 min_delay_between_retries : timedelta = DEFAULT_MIN_DELAY_BETWEEN_RETRIES ,
333356 timeout : timedelta = DEFAULT_TIMEOUT ,
357+ headers : dict [str , str ] | None = None ,
334358 ) -> None :
335359 """Initialize a new instance.
336360
@@ -344,11 +368,15 @@ def __init__(
344368 min_delay_between_retries: How long will the client wait between retrying requests
345369 (increases exponentially from this value).
346370 timeout: The socket timeout of the HTTP requests sent to the Apify API.
371+ headers: Additional HTTP headers to include in all API requests.
347372 """
348373 # We need to do this because of mocking in tests and default mutable arguments.
349374 api_url = DEFAULT_API_URL if api_url is None else api_url
350375 api_public_url = DEFAULT_API_URL if api_public_url is None else api_public_url
351376
377+ if headers :
378+ self ._check_custom_headers (headers )
379+
352380 self ._token = token
353381 """Apify API token for authentication."""
354382
@@ -361,12 +389,13 @@ def __init__(
361389 self ._statistics = ClientStatistics ()
362390 """Collector for client request statistics."""
363391
364- self ._http_client = AsyncHttpClient (
392+ self ._http_client = HttpClientAsync (
365393 token = token ,
366394 timeout = timeout or DEFAULT_TIMEOUT ,
367395 max_retries = max_retries or DEFAULT_MAX_RETRIES ,
368396 min_delay_between_retries = min_delay_between_retries or DEFAULT_MIN_DELAY_BETWEEN_RETRIES ,
369397 statistics = self ._statistics ,
398+ headers = headers ,
370399 )
371400 """HTTP client used to communicate with the Apify API."""
372401
@@ -413,6 +442,18 @@ def _base_kwargs(self) -> dict:
413442 'client_registry' : self ._client_registry ,
414443 }
415444
445+ def _check_custom_headers (self , headers : dict [str , str ]) -> None :
446+ """Warn if custom headers override important default headers."""
447+ overwrite_headers = [key for key in headers if key .title () in self ._OVERRIDABLE_DEFAULT_HEADERS ]
448+ if overwrite_headers :
449+ warnings .warn (
450+ f'{ ", " .join (overwrite_headers )} headers of { self .__class__ .__name__ } was overridden with an '
451+ 'explicit value. A wrong header value can lead to API errors, it is recommended to use the default '
452+ f'value for following headers: { ", " .join (self ._OVERRIDABLE_DEFAULT_HEADERS )} .' ,
453+ category = UserWarning ,
454+ stacklevel = 3 ,
455+ )
456+
416457 @property
417458 def token (self ) -> str | None :
418459 """The Apify API token used by the client."""
0 commit comments