0
# Asynchronous HTTP Client
1
2
The `AsyncClient` class provides an asynchronous HTTP client with the same features as the synchronous `Client` but using async/await syntax. It's designed for high-concurrency applications and integrates seamlessly with async frameworks.
3
4
## Overview
5
6
The async client uses the same API as the synchronous client but all methods are coroutines that must be awaited. It maintains async connection pools and supports concurrent requests efficiently.
7
8
## Capabilities
9
10
### AsyncClient Class
11
12
#### Constructor
13
14
```python { .api }
15
class AsyncClient:
16
def __init__(self, *, auth=None, params=None, headers=None, cookies=None, verify=True, cert=None, http1=True, http2=False, proxy=None, mounts=None, timeout=DEFAULT_TIMEOUT_CONFIG, follow_redirects=False, limits=DEFAULT_LIMITS, max_redirects=DEFAULT_MAX_REDIRECTS, event_hooks=None, base_url="", transport=None, trust_env=True, default_encoding="utf-8"):
17
"""
18
Initialize an asynchronous HTTP client.
19
20
Args:
21
auth (Auth, optional): Default authentication for all requests
22
params (dict, optional): Default query parameters for all requests
23
headers (dict, optional): Default headers for all requests
24
cookies (dict, optional): Default cookies for all requests
25
verify (bool | str | SSLContext): SSL certificate verification (default: True)
26
cert (str | tuple, optional): Client certificate file path or (cert, key) tuple
27
http1 (bool): Enable HTTP/1.1 (default: True)
28
http2 (bool): Enable HTTP/2 (default: False)
29
proxy (str | Proxy, optional): Proxy URL or configuration
30
mounts (dict, optional): Mapping of URL prefixes to custom transports
31
timeout (Timeout): Default timeout configuration (default: 5.0s)
32
follow_redirects (bool): Default redirect behavior (default: False)
33
limits (Limits): Connection pool limits (default: max_connections=100, max_keepalive_connections=20)
34
max_redirects (int): Maximum number of redirect hops (default: 20)
35
event_hooks (dict, optional): Request/response event hooks
36
base_url (str): Base URL to prepend to relative URLs
37
transport (AsyncBaseTransport, optional): Custom async transport implementation
38
trust_env (bool): Use environment variables for proxy/SSL config (default: True)
39
default_encoding (str | callable): Default text encoding for responses (default: "utf-8")
40
"""
41
```
42
43
#### Request Methods
44
45
```python { .api }
46
async def get(
47
self,
48
url: URL | str,
49
*,
50
params: QueryParamTypes | None = None,
51
headers: HeaderTypes | None = None,
52
cookies: CookieTypes | None = None,
53
auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
54
follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
55
timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
56
extensions: RequestExtensions | None = None,
57
) -> Response:
58
"""
59
Send a GET request asynchronously.
60
61
Args:
62
url (str): URL for the request (can be relative to base_url)
63
params (dict, optional): Query parameters to append to URL
64
headers (dict, optional): HTTP headers (merged with client defaults)
65
cookies (dict, optional): Cookies (merged with client defaults)
66
auth (Auth | USE_CLIENT_DEFAULT): Authentication (overrides client default)
67
follow_redirects (bool | USE_CLIENT_DEFAULT): Redirect behavior (overrides client default)
68
timeout (Timeout | USE_CLIENT_DEFAULT): Timeout configuration (overrides client default)
69
extensions (dict, optional): Protocol extensions
70
71
Returns:
72
Response: HTTP response object
73
74
Raises:
75
RequestError: If the request fails
76
"""
77
78
async def post(
79
self,
80
url: URL | str,
81
*,
82
content: RequestContent | None = None,
83
data: RequestData | None = None,
84
files: RequestFiles | None = None,
85
json: Any | None = None,
86
params: QueryParamTypes | None = None,
87
headers: HeaderTypes | None = None,
88
cookies: CookieTypes | None = None,
89
auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
90
follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
91
timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
92
extensions: RequestExtensions | None = None,
93
) -> Response:
94
"""
95
Send a POST request asynchronously.
96
97
Args:
98
url (str): URL for the request (can be relative to base_url)
99
content (bytes, optional): Raw bytes content for request body
100
data (dict, optional): Form data to send in request body
101
files (dict, optional): Files to upload
102
json (any, optional): JSON-serializable object for request body
103
params (dict, optional): Query parameters to append to URL
104
headers (dict, optional): HTTP headers (merged with client defaults)
105
cookies (dict, optional): Cookies (merged with client defaults)
106
auth (Auth | USE_CLIENT_DEFAULT): Authentication (overrides client default)
107
follow_redirects (bool | USE_CLIENT_DEFAULT): Redirect behavior (overrides client default)
108
timeout (Timeout | USE_CLIENT_DEFAULT): Timeout configuration (overrides client default)
109
extensions (dict, optional): Protocol extensions
110
111
Returns:
112
Response: HTTP response object
113
114
Raises:
115
RequestError: If the request fails
116
"""
117
118
async def put(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth=USE_CLIENT_DEFAULT, follow_redirects=USE_CLIENT_DEFAULT, timeout=USE_CLIENT_DEFAULT, extensions=None):
119
"""Send a PUT request asynchronously. Same arguments as post()."""
120
121
async def patch(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth=USE_CLIENT_DEFAULT, follow_redirects=USE_CLIENT_DEFAULT, timeout=USE_CLIENT_DEFAULT, extensions=None):
122
"""Send a PATCH request asynchronously. Same arguments as post()."""
123
124
async def delete(self, url, *, params=None, headers=None, cookies=None, auth=USE_CLIENT_DEFAULT, follow_redirects=USE_CLIENT_DEFAULT, timeout=USE_CLIENT_DEFAULT, extensions=None):
125
"""Send a DELETE request asynchronously. Same arguments as get()."""
126
127
async def head(self, url, *, params=None, headers=None, cookies=None, auth=USE_CLIENT_DEFAULT, follow_redirects=USE_CLIENT_DEFAULT, timeout=USE_CLIENT_DEFAULT, extensions=None):
128
"""Send a HEAD request asynchronously. Same arguments as get()."""
129
130
async def options(self, url, *, params=None, headers=None, cookies=None, auth=USE_CLIENT_DEFAULT, follow_redirects=USE_CLIENT_DEFAULT, timeout=USE_CLIENT_DEFAULT, extensions=None):
131
"""Send an OPTIONS request asynchronously. Same arguments as get()."""
132
133
async def request(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth=USE_CLIENT_DEFAULT, follow_redirects=USE_CLIENT_DEFAULT, timeout=USE_CLIENT_DEFAULT, extensions=None):
134
"""
135
Send an HTTP request with specified method asynchronously.
136
137
Args:
138
method (str): HTTP method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)
139
url (str): URL for the request (can be relative to base_url)
140
content (bytes, optional): Raw bytes content for request body
141
data (dict, optional): Form data to send in request body
142
files (dict, optional): Files to upload
143
json (any, optional): JSON-serializable object for request body
144
params (dict, optional): Query parameters to append to URL
145
headers (dict, optional): HTTP headers (merged with client defaults)
146
cookies (dict, optional): Cookies (merged with client defaults)
147
auth (Auth | USE_CLIENT_DEFAULT): Authentication (overrides client default)
148
follow_redirects (bool | USE_CLIENT_DEFAULT): Redirect behavior (overrides client default)
149
timeout (Timeout | USE_CLIENT_DEFAULT): Timeout configuration (overrides client default)
150
extensions (dict, optional): Protocol extensions
151
152
Returns:
153
Response: HTTP response object
154
155
Raises:
156
RequestError: If the request fails
157
"""
158
```
159
160
#### Advanced Methods
161
162
```python { .api }
163
async def send(self, request, *, stream=False, auth=USE_CLIENT_DEFAULT, follow_redirects=USE_CLIENT_DEFAULT, timeout=USE_CLIENT_DEFAULT):
164
"""
165
Send a pre-built Request object asynchronously.
166
167
Args:
168
request (Request): Request object to send
169
stream (bool): Whether to return a streaming response (default: False)
170
auth (Auth | USE_CLIENT_DEFAULT): Authentication (overrides client default)
171
follow_redirects (bool | USE_CLIENT_DEFAULT): Redirect behavior (overrides client default)
172
timeout (Timeout | USE_CLIENT_DEFAULT): Timeout configuration (overrides client default)
173
174
Returns:
175
Response: HTTP response object
176
177
Raises:
178
RequestError: If the request fails
179
"""
180
181
def build_request(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None):
182
"""
183
Build a Request object without sending it (synchronous).
184
185
Args:
186
method (str): HTTP method
187
url (str): URL for the request
188
content (bytes, optional): Raw bytes content for request body
189
data (dict, optional): Form data to send in request body
190
files (dict, optional): Files to upload
191
json (any, optional): JSON-serializable object for request body
192
params (dict, optional): Query parameters to append to URL
193
headers (dict, optional): HTTP headers (merged with client defaults)
194
cookies (dict, optional): Cookies (merged with client defaults)
195
196
Returns:
197
Request: Prepared request object
198
"""
199
200
def stream(self, method, url, **kwargs):
201
"""
202
Stream a request response asynchronously.
203
204
Args:
205
method (str): HTTP method
206
url (str): URL for the request
207
**kwargs: Same arguments as request() method
208
209
Returns:
210
AsyncGenerator yielding Response: Async context manager for streaming response
211
212
Usage:
213
async with client.stream('GET', '/large-file') as response:
214
async for chunk in response.aiter_bytes():
215
await process_chunk(chunk)
216
"""
217
218
async def aclose(self):
219
"""
220
Close the client and release all connections asynchronously.
221
222
Should be called when done with the client to ensure connections
223
are properly closed and resources are released.
224
"""
225
```
226
227
#### Context Manager Support
228
229
```python { .api }
230
async def __aenter__(self):
231
"""Enter async context manager."""
232
return self
233
234
async def __aexit__(self, exc_type=None, exc_value=None, traceback=None):
235
"""Exit async context manager and close client."""
236
await self.aclose()
237
```
238
239
## Usage Examples
240
241
### Basic Async Client Usage
242
243
```python
244
import httpx
245
import asyncio
246
247
async def main():
248
client = httpx.AsyncClient()
249
try:
250
response = await client.get('https://httpbin.org/get')
251
print(response.json())
252
finally:
253
await client.aclose()
254
255
asyncio.run(main())
256
```
257
258
### Async Context Manager (Recommended)
259
260
```python
261
import httpx
262
import asyncio
263
264
async def main():
265
async with httpx.AsyncClient() as client:
266
response = await client.get('https://httpbin.org/get')
267
print(response.json())
268
# Client automatically closed
269
270
asyncio.run(main())
271
```
272
273
### Concurrent Requests
274
275
```python
276
import httpx
277
import asyncio
278
279
async def fetch_url(client, url):
280
response = await client.get(url)
281
return response.json()
282
283
async def main():
284
urls = [
285
'https://httpbin.org/delay/1',
286
'https://httpbin.org/delay/2',
287
'https://httpbin.org/delay/3'
288
]
289
290
async with httpx.AsyncClient() as client:
291
# Make concurrent requests
292
tasks = [fetch_url(client, url) for url in urls]
293
results = await asyncio.gather(*tasks)
294
295
for result in results:
296
print(result)
297
298
asyncio.run(main())
299
```
300
301
### Async Client with Configuration
302
303
```python
304
import httpx
305
import asyncio
306
307
async def main():
308
timeout = httpx.Timeout(10.0, connect=5.0)
309
limits = httpx.Limits(max_connections=50)
310
311
async with httpx.AsyncClient(
312
base_url='https://api.example.com',
313
headers={'User-Agent': 'AsyncApp/1.0'},
314
timeout=timeout,
315
limits=limits
316
) as client:
317
response = await client.get('/users')
318
users = response.json()
319
320
asyncio.run(main())
321
```
322
323
### Async Streaming
324
325
```python
326
import httpx
327
import asyncio
328
329
async def main():
330
async with httpx.AsyncClient() as client:
331
async with client.stream('GET', 'https://example.com/large-file') as response:
332
async for chunk in response.aiter_bytes(chunk_size=1024):
333
# Process chunk asynchronously
334
await process_chunk(chunk)
335
336
async def process_chunk(chunk):
337
# Simulate async processing
338
await asyncio.sleep(0.01)
339
print(f"Processed {len(chunk)} bytes")
340
341
asyncio.run(main())
342
```
343
344
### FastAPI Integration
345
346
```python
347
import httpx
348
from fastapi import FastAPI
349
350
app = FastAPI()
351
352
# Create a shared client for the application
353
client = httpx.AsyncClient()
354
355
@app.on_event("shutdown")
356
async def shutdown_event():
357
await client.aclose()
358
359
@app.get("/proxy/{path:path}")
360
async def proxy_request(path: str):
361
response = await client.get(f"https://api.example.com/{path}")
362
return response.json()
363
```
364
365
### Async Authentication
366
367
```python
368
import httpx
369
import asyncio
370
371
async def main():
372
auth = httpx.BasicAuth('username', 'password')
373
374
async with httpx.AsyncClient(auth=auth) as client:
375
# All requests use authentication
376
response = await client.get('https://example.com/protected')
377
data = response.json()
378
379
asyncio.run(main())
380
```
381
382
### Error Handling
383
384
```python
385
import httpx
386
import asyncio
387
388
async def main():
389
async with httpx.AsyncClient() as client:
390
try:
391
response = await client.get('https://httpbin.org/status/404')
392
response.raise_for_status()
393
except httpx.HTTPStatusError as exc:
394
print(f"Error response {exc.response.status_code}: {exc.response.text}")
395
except httpx.RequestError as exc:
396
print(f"Request error: {exc}")
397
398
asyncio.run(main())
399
```
400
401
### ASGI Application Testing
402
403
```python
404
import httpx
405
from fastapi import FastAPI
406
407
app = FastAPI()
408
409
@app.get("/hello")
410
async def hello():
411
return {"message": "Hello World"}
412
413
async def test_app():
414
# Test ASGI app directly without network calls
415
async with httpx.AsyncClient(app=app, base_url="http://test") as client:
416
response = await client.get("/hello")
417
assert response.status_code == 200
418
assert response.json() == {"message": "Hello World"}
419
420
asyncio.run(test_app())
421
```