Netizen is a minimalist HTTP client with a symmetrical interface between async and sync modes. It doesn't aim to be feature-complete like requests or httpx.
Netizen is just enough for poking API endpoints and performing basic HTTP operations or testing. It suits me, as I prefer working closely with sockets and don't need high-level abstraction.
- Symmetrical interface, e.g.
client.send()vsawait client.send() - ~500 lines of code
- No dependencies other than the Python Standard Library
pip install git+https://github.com/nggit/netizen.git
import asyncio
from netizen import HTTPClient
# sync
with HTTPClient('ip-api.com', 80) as client:
response = client.send(b'GET /json HTTP/1.1')
print(response.json())
# async
async def main():
async with HTTPClient('ip-api.com', 80) as client:
response = await client.send(b'GET /json HTTP/1.1')
print(await response.json())
asyncio.run(main())import asyncio
from netizen import HTTPClient
client = HTTPClient('example.com', 80)
# sync
with client:
response = client.send(b'GET / HTTP/1.1')
for data in response:
print('Received:', len(data), 'Bytes')
# async
async def main():
async with client:
response = await client.send(b'GET / HTTP/1.1')
async for data in response:
print('Received:', len(data), 'Bytes')
asyncio.run(main())with HTTPClient('example.com', 80) as client:
response = client.send(
b'POST / HTTP/1.1',
b'Content-Type: application/json',
b'Content-Length: 14',
body=b'{"foo": "bar"}'
)
print('Status code:', response.status) # 403
print('Reason phrase:', response.message) # b'Forbidden'
# out of context, close the connection without reading the entire response bodyIf you don't specify any headers, then Content-Length will be automatically
inserted along with Content-Type: application/x-www-form-urlencoded.
with HTTPClient('example.com', 80) as client:
response = client.send(b'POST / HTTP/1.1', body=b'foo=bar')with HTTPClient('ip-api.com', 80) as client:
# first request
response = client.send(b'GET /json HTTP/1.1')
# the first response body must be consumed before sending another one
print(response.json())
# second request
response = client.send(b'GET / HTTP/1.1')
for data in response:
print('Received:', len(data), 'Bytes')from urllib.parse import urlparse
with HTTPClient('google.com', 443, ssl=True) as client:
response = client.send(b'GET / HTTP/1.1')
print('1. Status code:', response.status) # 301
print('1. Reason phrase:', response.message) # b'Moved Permanently'
print('1. Location:', response.url) # b'http://www.google.com/'
for data in response:
pass
if response.url:
url = urlparse(response.url)
if url.netloc: # b'www.google.com' (different host)
with HTTPClient(url.netloc.decode(), 443, ssl=True) as client:
response = client.send(b'GET %s HTTP/1.1' % url.path)
print('2. Status code:', response.status) # 200
print('2. Reason phrase:', response.message) # b'OK'
for data in response:
pass
else:
passwith HTTPClient('localhost', 8000, timeout=10) as client:
response = client.send(
b'GET /chat HTTP/1.1',
b'Upgrade: WebSocket',
b'Connection: Upgrade',
b'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==',
b'Sec-WebSocket-Version: 13'
)
if response.status == 101:
client.sendall(b'\x81\x0dHello, World!\x88\x02\x03\xe8')
print('Received:', client.recv(4096))MIT License