Agent skill
httpx
A synchronous and asynchronous HTTP client for making requests and working with responses.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/skills-skilldoai-skilldo-28
SKILL.md
Imports
import httpx
from httpx import AsyncClient, BasicAuth, Client, DigestAuth, NetRCAuth, Response
from httpx import ASGITransport, WSGITransport
Core Patterns
One-off request with top-level API ✅ Current
import httpx
def fetch_json(url: str) -> dict:
response = httpx.get(url)
response.raise_for_status()
return response.json()
if __name__ == "__main__":
data = fetch_json("https://httpbin.org/json")
print(sorted(data.keys()))
- Use
httpx.get()/httpx.request()for quick scripts or single calls. - Prefer a persistent
httpx.Clientonce you have multiple requests.
Persistent client with connection pooling (recommended) ✅ Current
import httpx
def fetch_many(urls: list[str]) -> list[int]:
status_codes: list[int] = []
with httpx.Client() as client:
for url in urls:
r = client.get(url)
status_codes.append(r.status_code)
return status_codes
if __name__ == "__main__":
codes = fetch_many(["https://httpbin.org/status/200", "https://httpbin.org/status/204"])
print(codes)
- Use
httpx.Client()for connection pooling, cookie persistence, shared headers, proxy support, and HTTP/2 support (when configured). - Use
with httpx.Client() as client:(or callclient.close()) to release resources.
Async requests with AsyncClient ✅ Current
import asyncio
import httpx
async def fetch_text(url: str) -> str:
async with httpx.AsyncClient() as client:
r = await client.get(url)
r.raise_for_status()
return r.text
async def main() -> None:
text = await fetch_text("https://httpbin.org/uuid")
print(text.strip())
if __name__ == "__main__":
asyncio.run(main())
- Use
httpx.AsyncClient()for async I/O; alwaysawaitrequest calls. - Use
async withto ensure the client is closed.
Authentication (built-in) ✅ Current
import httpx
def fetch_with_basic_auth(url: str, username: str, password: str) -> int:
auth = httpx.BasicAuth(username, password)
with httpx.Client(auth=auth) as client:
r = client.get(url)
return r.status_code
if __name__ == "__main__":
# httpbin requires user/pass to match in this endpoint.
code = fetch_with_basic_auth("https://httpbin.org/basic-auth/user/pass", "user", "pass")
print(code)
- Configure auth per request (
client.get(..., auth=...)) or on the client (Client(auth=...)) depending on scope. - Other built-ins include
DigestAuthandNetRCAuth.
Mounting an ASGI/WSGI app via explicit transports ✅ Current
import httpx
async def asgi_app(scope, receive, send) -> None:
assert scope["type"] == "http"
await send(
{
"type": "http.response.start",
"status": 200,
"headers": [(b"content-type", b"text/plain")],
}
)
await send({"type": "http.response.body", "body": b"ok"})
def wsgi_app(environ, start_response):
start_response("200 OK", [("Content-Type", "text/plain")])
return [b"ok"]
def call_wsgi() -> str:
transport = httpx.WSGITransport(app=wsgi_app)
with httpx.Client(transport=transport, base_url="http://testserver") as client:
return client.get("/").text
async def call_asgi() -> str:
transport = httpx.ASGITransport(app=asgi_app)
async with httpx.AsyncClient(transport=transport, base_url="http://testserver") as client:
return (await client.get("/")).text
if __name__ == "__main__":
print(call_wsgi())
import asyncio
print(asyncio.run(call_asgi()))
- Use
transport=httpx.WSGITransport(app=...)ortransport=httpx.ASGITransport(app=...). - The older
app=shortcut onClient/AsyncClientis removed in 0.28.0 (see Migration).
Configuration
- Client lifecycle
- Recommended:
with httpx.Client(...) as client:/async with httpx.AsyncClient(...) as client: - Manual cleanup:
client.close()when not using a context manager.
- Recommended:
- Auth
- Pass
auth=per request or setClient(auth=...). - Built-ins:
httpx.BasicAuth,httpx.DigestAuth,httpx.NetRCAuth. - Custom: implement
httpx.Authand itsauth_flow()/sync_auth_flow()/async_auth_flow().
- Pass
- Proxy configuration (0.26+;
proxies=removed in 0.28.0)- Use
Client(proxy="http://proxy.local:8080")for simple cases. - For complex routing, use
mounts=(preferred over the removedproxies=argument).
- Use
- Transports
- In-process apps:
WSGITransport,ASGITransport. - Network transports:
HTTPTransport,AsyncHTTPTransport(advanced usage).
- In-process apps:
- SSL notes (0.28.0 deprecations) ⚠️
- Passing
verifyas a string path and usingcert=are deprecated and may warn. verify=True,verify=False, orverify=<ssl.SSLContext>remain valid.
- Passing
- JSON request bodies (0.28 behavioral change)
- Default JSON encoding is now more compact; tests asserting exact JSON bytes may need updates.
- If you need stable formatting, pre-serialize and send via
content=with an explicitcontent-type.
Pitfalls
Wrong: Using top-level httpx.get() in a loop (no pooling)
import httpx
def download_many() -> None:
for _ in range(10):
httpx.get("https://httpbin.org/get").raise_for_status()
if __name__ == "__main__":
download_many()
Right: Reuse a httpx.Client() for pooling
import httpx
def download_many() -> None:
with httpx.Client() as client:
for _ in range(10):
client.get("https://httpbin.org/get").raise_for_status()
if __name__ == "__main__":
download_many()
Wrong: Forgetting to close a httpx.Client()
import httpx
def fetch_once() -> int:
client = httpx.Client()
r = client.get("https://httpbin.org/status/200")
r.raise_for_status()
return r.status_code # client.close() never called
if __name__ == "__main__":
print(fetch_once())
Right: Use a context manager (or call client.close())
import httpx
def fetch_once() -> int:
with httpx.Client() as client:
r = client.get("https://httpbin.org/status/200")
r.raise_for_status()
return r.status_code
if __name__ == "__main__":
print(fetch_once())
Wrong: Using removed proxies= argument (0.28+) ⚠️
import httpx
def build_client() -> httpx.Client:
return httpx.Client(proxies={"https": "http://proxy.local:8080"}) # removed in 0.28.0
if __name__ == "__main__":
build_client()
Right: Use proxy= (or mounts= for complex routing)
import httpx
def build_client() -> httpx.Client:
return httpx.Client(proxy="http://proxy.local:8080")
if __name__ == "__main__":
with build_client() as client:
print(client.get("https://httpbin.org/get").status_code)
Wrong: Custom httpx.Auth.auth_flow() doing async/non-HTTP I/O
import asyncio
import httpx
async def get_token() -> str:
await asyncio.sleep(0)
return "token"
class TokenAuth(httpx.Auth):
def auth_flow(self, request: httpx.Request):
# BAD: running async I/O inside a sync generator.
token = asyncio.get_event_loop().run_until_complete(get_token())
request.headers["Authorization"] = f"Bearer {token}"
yield request
def main() -> None:
with httpx.Client(auth=TokenAuth()) as client:
client.get("https://httpbin.org/get")
if __name__ == "__main__":
main()
Right: Provide sync_auth_flow() and async_auth_flow()
import asyncio
import threading
import httpx
class TokenAuth(httpx.Auth):
def __init__(self) -> None:
self._sync_lock = threading.RLock()
self._async_lock = asyncio.Lock()
def _sync_get_token(self) -> str:
with self._sync_lock:
return "token"
def sync_auth_flow(self, request: httpx.Request):
token = self._sync_get_token()
request.headers["Authorization"] = f"Bearer {token}"
yield request
async def _async_get_token(self) -> str:
async with self._async_lock:
await asyncio.sleep(0)
return "token"
async def async_auth_flow(self, request: httpx.Request):
token = await self._async_get_token()
request.headers["Authorization"] = f"Bearer {token}"
yield request
def main() -> None:
with httpx.Client(auth=TokenAuth()) as client:
client.get("https://httpbin.org/get").raise_for_status()
if __name__ == "__main__":
main()
References
Migration from v0.27.x
proxies= argument removed 🗑️ Removed
- Deprecated since: 0.26.0 (deprecated), removed in 0.28.0
- Still works: false
- Modern alternative:
proxy=for simple cases, ormounts=for complex routing - Migration guidance:
import httpx
# Before (0.27.x and earlier; removed in 0.28.0)
# client = httpx.Client(proxies={"https": "http://proxy.local:8080"})
# After (0.28.0+)
with httpx.Client(proxy="http://proxy.local:8080") as client:
r = client.get("https://httpbin.org/get")
print(r.status_code)
app= shortcut removed 🗑️ Removed
- Deprecated since: 0.27.0, removed in 0.28.0
- Still works: false
- Modern alternative:
transport=httpx.ASGITransport(app=...)ortransport=httpx.WSGITransport(app=...) - Migration guidance:
import httpx
async def asgi_app(scope, receive, send) -> None:
await send({"type": "http.response.start", "status": 204, "headers": []})
await send({"type": "http.response.body", "body": b""})
# Before (removed in 0.28.0)
# client = httpx.AsyncClient(app=asgi_app)
# After
transport = httpx.ASGITransport(app=asgi_app)
JSON request formatting changed ✅ Current (behavioral change in 0.28.0)
- Still works: true (but output bytes may differ)
- Modern alternative: if you require stable JSON bytes, pre-serialize and send via
content=...with a JSON content-type.
import json
import httpx
def post_stable_json(url: str, payload: dict) -> int:
body = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8")
headers = {"content-type": "application/json"}
r = httpx.request("POST", url, content=body, headers=headers)
return r.status_code
if __name__ == "__main__":
print(post_stable_json("https://httpbin.org/post", {"b": 1, "a": 2}))
SSL arguments deprecated ⚠️
- Deprecated since: 0.28.0
- Passing a string path to
verifyor using thecertargument is deprecated and will issue warnings. - Modern alternative: Use
verify=True,verify=False, orverify=<ssl.SSLContext>. See new SSL configuration docs for details.
API Reference
- httpx.get(url, **kwargs) - Convenience GET request; returns
httpx.Response. - httpx.request(method, url, **kwargs) - Generic request entry point for one-off calls.
- httpx.Client(**kwargs) - Sync client with connection pooling and shared config (auth, proxy, transport, etc.).
- Client.get(url, **kwargs) - Sync GET using the client’s configuration.
- Client.request(method, url, **kwargs) - Generic sync request method on a client.
- Client.close() - Close the client and release network resources (use context managers instead when possible).
- httpx.AsyncClient(**kwargs) - Async client; use with
async withandawait. - httpx.Response - Response object (status, headers, body accessors).
- Response.raise_for_status() - Raise an exception on 4xx/5xx; returns the response (can be chained).
- Response.json() - Parse response body as JSON.
- Response.iter_text() - Stream response body as decoded text chunks.
- httpx.BasicAuth(username, password) - HTTP Basic authentication.
- httpx.DigestAuth(username, password) - HTTP Digest authentication.
- httpx.NetRCAuth(file=None) - Auth from
.netrc(optionally specify file). - httpx.Auth - Base class for custom auth; implement
auth_flow()orsync_auth_flow()/async_auth_flow(). - httpx.FunctionAuth(callable) - Wrap a callable as an auth implementation.
- httpx.WSGITransport(app=...) - Transport for calling a WSGI app in-process.
- httpx.ASGITransport(app=...) - Transport for calling an ASGI app in-process.
- httpx.HTTPTransport(...) - Low-level sync transport configuration (advanced).
- httpx.AsyncHTTPTransport(...) - Low-level async transport configuration (advanced).
- httpx.InvalidURL - Exception raised for invalid URL inputs.
Security Note:
All examples are designed for use within your own project directory and for safe, local development or controlled network requests. Never use these patterns to transmit, modify, or access data outside your intended project or environment. Do not copy/paste code into environments where you lack permission or understanding of the security implications.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?