The Quart app shown below demonstrates the use of an HTTPX AsyncClient within the /sample and /delay4 routes. The purpose of the client is to make JSON requests to some service and the returned data can be used within the Quart application. If the client was defined at the top level of the module/file then it would be initialized during import which could cause unwanted side effects. Therefore, an empty dictionary is used to store the client object and the client itself is created before the server starts in the startup function. When the server is shutdown, the client is closed and the dictionary is cleared.
# main.py
import httpx
from quart import Quart
app = Quart(__name__)
state: dict[str, httpx.AsyncClient] = {}
@app.before_serving
async def startup():
state["client"] = httpx.AsyncClient(base_url="https://httpbin.org", timeout=20)
@app.get("/")
async def root():
return {"message": "hello there", "routes": ["/sample", "/delay4"]}
@app.get("/sample")
async def sample():
client = state["client"]
response = await client.get("/json")
return response.json()
@app.get("/delay4")
async def delay4():
client = state["client"]
response = await client.get("/delay/4")
return response.json()
@app.after_serving
async def shutdown():
client = state["client"]
await client.aclose()
state.clear()
print("\nClosed client and shutdown server")
if __name__ == "__main__":
app.run(debug=True)
Tests are shown next. A client fixture provides Quart's test client to the test functions. The pytest-asyncio plugin provides async functionality to pytest via the @pytest.mark.asyncio function decorator. Notice the HTTPX client and response are mocked in the test_sample function to avoid making HTTP requests to the actual endpoint. The same approach is used to test the delay4 route.
# conftest.py
import pytest
from quart_httpx.main import app
@pytest.fixture
def client():
return app.test_client()
# test_root.py
import pytest
@pytest.mark.asyncio
async def test_root(client):
response = await client.get("/")
assert response.status_code == 200
data = await response.get_json()
assert data["message"] == "hello there"
assert data["routes"] == ["/sample", "/delay4"]
# test_sample.py
import pytest
from quart_httpx import main
@pytest.mark.asyncio
async def test_sample(client, monkeypatch):
mock_response_data = {"slideshow": {"title": "Sample Slideshow"}}
class MockResponse:
def json(self):
return mock_response_data
class MockAsyncClient:
async def get(self, url):
assert url == "/json"
return MockResponse()
async def aclose(self):
pass
monkeypatch.setitem(main.state, "client", MockAsyncClient())
response = await client.get("/sample")
assert response.status_code == 200
data = await response.get_json()
assert data == mock_response_data
See the Quart and HTTPX documentation for more information about these packages. See the pytest-asyncio documentation for more information about the pytest plugin. Code discussed in this article is available in the pythonic/projects/quart-httpx directory which is located in the GitHub pythonic repository.
Gavin Wiggins © 2025
Made on a Mac with Genja. Hosted on GitHub Pages.