@@ -44,6 +44,18 @@ Fields of `ExternalApiConfig`
4444 * - ``api_key ``
4545 - ``Optional[str] ``
4646 - API key for authorization, sent in the ``Authorization `` header.
47+ * - ``async_mode ``
48+ - ``bool ``
49+ - Enable async HTTP client (httpx) for parallel requests. Default: ``False ``.
50+ * - ``timeout ``
51+ - ``int ``
52+ - Timeout in seconds for HTTP requests. Default: ``30 ``.
53+ * - ``retry_count ``
54+ - ``int ``
55+ - Number of retry attempts on failure. Default: ``0 ``.
56+ * - ``retry_delay ``
57+ - ``float ``
58+ - Delay in seconds between retries. Default: ``1.0 ``.
4759
4860Examples
4961--------
@@ -106,6 +118,158 @@ Handling Fallback Values
106118 }
107119 )
108120
121+ Async Support
122+ -------------
123+
124+ Installation
125+ ^^^^^^^^^^^^
126+
127+ To use async external APIs, install the optional async dependencies:
128+
129+ .. code-block :: bash
130+
131+ pip install flask-inputfilter[async]
132+
133+ This installs ``httpx ``, which is required for async HTTP requests.
134+
135+ Basic Async Usage
136+ ^^^^^^^^^^^^^^^^^
137+
138+ Enable async mode by setting ``async_mode=True `` in the ``ExternalApiConfig ``.
139+ The ``@validate() `` decorator automatically detects async routes and enables
140+ parallel API execution.
141+
142+ .. code-block :: python
143+
144+ from flask_inputfilter import InputFilter
145+ from flask_inputfilter.declarative import field
146+ from flask_inputfilter.models import ExternalApiConfig
147+
148+ class UserFilter (InputFilter ):
149+ user_id: int = field(
150+ required = True ,
151+ external_api = ExternalApiConfig(
152+ url = " https://api.example.com/users/{{ user_id}} " ,
153+ method = " GET" ,
154+ async_mode = True # Enable async
155+ )
156+ )
157+
158+ @app.route (' /users' , methods = [' POST' ])
159+ @UserFilter.validate () # Auto-detects async route
160+ async def create_user (): # Note: async def
161+ data = g.validated_data
162+ return {" user" : data}
163+
164+ Parallel API Calls
165+ ^^^^^^^^^^^^^^^^^^
166+
167+ When multiple fields have async external APIs, all API calls execute in parallel,
168+ dramatically reducing total request time.
169+
170+ .. code-block :: python
171+
172+ class OrderFilter (InputFilter ):
173+ user_id: int = field(
174+ required = True ,
175+ external_api = ExternalApiConfig(
176+ url = " https://api.users.com/{{ user_id}} " ,
177+ method = " GET" ,
178+ async_mode = True
179+ )
180+ )
181+
182+ product_id: int = field(
183+ required = True ,
184+ external_api = ExternalApiConfig(
185+ url = " https://api.products.com/{{ product_id}} " ,
186+ method = " GET" ,
187+ async_mode = True
188+ )
189+ )
190+
191+ shipping_id: int = field(
192+ required = True ,
193+ external_api = ExternalApiConfig(
194+ url = " https://api.shipping.com/{{ shipping_id}} " ,
195+ method = " GET" ,
196+ async_mode = True
197+ )
198+ )
199+
200+ @app.route (' /orders' , methods = [' POST' ])
201+ @OrderFilter.validate ()
202+ async def create_order ():
203+ # All 3 API calls execute in parallel!
204+ # Total time = max(user_api, product_api, shipping_api)
205+ return g.validated_data
206+
207+ Retry Logic
208+ ^^^^^^^^^^^
209+
210+ Configure retry behavior for unreliable APIs:
211+
212+ .. code-block :: python
213+
214+ user_id: int = field(
215+ required = True ,
216+ external_api = ExternalApiConfig(
217+ url = " https://flaky-api.com/users/{{ user_id}} " ,
218+ method = " GET" ,
219+ async_mode = True ,
220+ retry_count = 3 , # Retry up to 3 times
221+ retry_delay = 0.5 # Wait 500ms between retries
222+ )
223+ )
224+
225+ Custom Timeout
226+ ^^^^^^^^^^^^^^
227+
228+ Override the default 30-second timeout:
229+
230+ .. code-block :: python
231+
232+ user_id: int = field(
233+ required = True ,
234+ external_api = ExternalApiConfig(
235+ url = " https://slow-api.com/users/{{ user_id}} " ,
236+ method = " GET" ,
237+ async_mode = True ,
238+ timeout = 60 # 60 seconds
239+ )
240+ )
241+
242+ Mixed Sync and Async
243+ ^^^^^^^^^^^^^^^^^^^^
244+
245+ You can mix sync and async external APIs in the same filter:
246+
247+ .. code-block :: python
248+
249+ class MixedFilter (InputFilter ):
250+ # Legacy sync API
251+ legacy_id: int = field(
252+ external_api = ExternalApiConfig(
253+ url = " https://legacy-api.com/{{ id}} " ,
254+ method = " GET" ,
255+ async_mode = False # Sync (default)
256+ )
257+ )
258+
259+ # Modern async API
260+ modern_id: int = field(
261+ external_api = ExternalApiConfig(
262+ url = " https://modern-api.com/{{ id}} " ,
263+ method = " GET" ,
264+ async_mode = True # Async
265+ )
266+ )
267+
268+ @app.route (' /data' , methods = [' POST' ])
269+ @UserFilter.validate ()
270+ async def get_data ():
271+ return g.validated_data
272+
109273 Error Handling
110274--------------
111275
0 commit comments