Clients
HTTP requests are sent by using a Client
instance. Client instances are thread safe interfaces that maintain a pool of HTTP connections.
>>> cli = httpx.Client()
>>> cli
<Client [0 active]>
The client representation provides an indication of how many connections are currently in the pool.
>>> r = cli.get("https://www.example.com")
>>> r = cli.get("https://www.wikipedia.com")
>>> r = cli.get("https://www.theguardian.com/uk")
>>> cli
<Client [0 active, 3 idle]>
The connections in the pool can be explicitly closed, using the close()
method...
>>> cli.close()
>>> cli
<Client [0 active]>
Client instances support being used in a context managed scope. You can use this style to enforce properly scoped resources, ensuring that the connection pool is cleanly closed when no longer required.
>>> with httpx.Client() as cli:
... r = cli.get("https://www.example.com")
It is important to scope the use of client instances as widely as possible.
Typically you should have a single client instance that is used throughout the lifespan of your application. This ensures that connection pooling is maximised, and minmises unneccessary reloading of SSL certificate stores.
The recommened usage is to either a have single global instance created at import time, or a single context scoped instance that is passed around wherever it is required.
Setting a base URL
Client instances can be configured with a base URL that is used when constructing requests...
>>> with httpx.Client(url="https://www.httpbin.org") as cli:
>>> r = cli.get("/json")
>>> print(r)
<Response [200 OK]>
Setting client headers
Client instances include a set of headers that are used on every outgoing request.
The default headers are:
Accept: */*
- Indicates to servers that any media type may be returned.Accept-Encoding: gzip
- Indicates to servers that gzip compression may be used on responses.Connection: keep-alive
- Indicates that HTTP/1.1 connections should be reused over multiple requests.User-Agent: python-httpx/1.0
- Identify the client ashttpx
.
You can override this behavior by explicitly specifying the default headers...
>>> headers = {"User-Agent": "dev", "Accept-Encoding": "gzip"}
>>> with httpx.Client(headers=headers) as cli:
>>> r = cli.get("https://www.example.com/")
Configuring the connection pool
The connection pool used by the client can be configured in order to customise the SSL context, the maximum number of concurrent connections, or the network backend.
>>> # Setup an SSL context to allow connecting to improperly configured SSL.
>>> no_verify = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
>>> no_verify.check_hostname = False
>>> no_verify.verify_mode = ssl.CERT_NONE
>>> # Instantiate a client with our custom SSL context.
>>> pool = httpx.ConnectionPool(ssl_context=no_verify)
>>> with httpx.Client(transport=pool) as cli:
>>> ...
Sending requests
.request()
- Send an HTTP request, reading the response to completion..stream()
- Send an HTTP request, streaming the response.
Shortcut methods...
.get()
- Send an HTTPGET
request..post()
- Send an HTTPPOST
request..put()
- Send an HTTPPUT
request..delete()
- Send an HTTPDELETE
request.
Transports
By default requests are sent using the ConnectionPool
class. Alternative implementations for sending requests can be created by subclassing the Transport
interface.
For example, a mock transport class that doesn't make any network requests and instead always returns a fixed response.
class MockTransport(httpx.Transport):
def __init__(self, response):
self._response = response
@contextlib.contextmanager
def send(self, request):
yield response
def close(self):
pass
response = httpx.Response(200, content=httpx.Text('Hello, world'))
transport = MockTransport(response=response)
with httpx.Client(transport=transport) as cli:
r = cli.get('https://www.example.com')
print(r)
Middleware
In addition to maintaining an HTTP connection pool, client instances are responsible for two other pieces of functionality...
- Dealing with HTTP redirects.
- Maintaining an HTTP cookie store.
RedirectMiddleware
Wraps a transport class, adding support for HTTP redirect handling.
CookieMiddleware
Wraps a transport class, adding support for HTTP cookie persistence.
Custom client implementations
The Client
implementation in httpx
is intentionally lightweight.
If you're working with a large codebase you might want to create a custom client implementation in order to constrain the types of request that are sent.
The following example demonstrates a custom API client that only exposes GET
and POST
requests, and always uses JSON payloads.
class APIClient:
def __init__(self):
self.url = httpx.URL('https://www.example.com')
self.headers = httpx.Headers({
'Accept-Encoding': 'gzip',
'Connection': 'keep-alive',
'User-Agent': 'dev'
})
self.via = httpx.RedirectMiddleware(httpx.ConnectionPool())
def get(self, path: str) -> Response:
request = httpx.Request(
method="GET",
url=self.url.join(path),
headers=self.headers,
)
with self.via.send(request) as response:
response.read()
return response
def post(self, path: str, payload: Any) -> httpx.Response:
request = httpx.Request(
method="POST",
url=self.url.join(path),
headers=self.headers,
content=httpx.JSON(payload),
)
with self.via.send(request) as response:
response.read()
return response
You can expand on this pattern to provide behavior such as request or response schema validation, consistent timeouts, or standardised logging and exception handling.
← Quickstart Servers →