Getting Started

Everything you need to start making HTTP requests with AtomHTTP

Why AtomHTTP?

AtomHTTP is a synchronous-first HTTP client for Python with fully optional async support — designed to be simple for everyday requests while remaining powerful enough for production applications.

Most HTTP client code doesn't need async/await. AtomHTTP doesn't force it on you — every method on AtomHTTP returns a response directly, no event loop required. When you do want async, AsyncAtomHTTP offers the exact same API, backed by the exact same transport.

With cancellation (axios/fetch-style AbortController), a persistent thread pool for real concurrency without async, true streaming for large uploads/downloads, pagination helpers, HTTP caching, interceptors, retries with backoff, and full type hints — AtomHTTP provides everything you need for production-grade HTTP communication, sync or async.

Installation

Install AtomHTTP using pip. The library has exactly one runtime dependency and works with Python 3.8 and above.

Basic installation:Minimal setup — small runtime footprint

1
pip install atomhttp

With SOCKS proxy support:Adds PySocks for socks4/socks5 proxies

1
pip install atomhttp[socks]

With Brotli support:Transparent decoding of Content-Encoding: br responses

1
pip install atomhttp[brotli]

With development dependencies:Includes pytest, black, mypy, ruff for development

1
pip install atomhttp[dev]

Requires Python 3.8 or higher

Minimal runtime dependencies and a small, stable surface area make AtomHTTP easy to adopt in existing projects.

Quick Start

Create a client instance and start making requests in just a few lines of code — no asyncio.run() required.

Basic GET request:Simple, synchronous — no event loop needed

1
2
3
4
5
6
7
8
from atomhttp import AtomHTTP

client = AtomHTTP()
response = client.get('https://jsonplaceholder.typicode.com/posts/1')

print(f"Status: {response.status}")
print(f"Title: {response.data['title']}")
print(f"User ID: {response.data['userId']}")

With configuration:Using base_url, timeout, and default headers

1
2
3
4
5
6
7
8
9
10
11
12
from atomhttp import AtomHTTP

client = AtomHTTP(
    base_url='https://jsonplaceholder.typicode.com',
    timeout=10,
    headers={'Accept': 'application/json'},
)

response = client.get('/posts', params={'_limit': 5})

for post in response.data:
    print(f"Post {post['id']}: {post['title'][:50]}...")

POST request with JSON:Creating a new resource

1
2
3
4
5
6
7
8
9
10
11
12
from atomhttp import AtomHTTP

client = AtomHTTP(base_url='https://jsonplaceholder.typicode.com')

new_post = client.post('/posts', data={
    'title': 'My Awesome Post',
    'body': 'This is the content of my post',
    'userId': 1,
})

print(f"Created with ID: {new_post.data['id']}")
print(f"Status: {new_post.status}")

Async, if you need it:Same API, same transport — just await it

1
2
3
4
5
6
7
8
9
import asyncio
from atomhttp import AsyncAtomHTTP

async def main():
    async with AsyncAtomHTTP(base_url='https://jsonplaceholder.typicode.com') as client:
        response = await client.get('/posts/1')
        print(response.data['title'])

asyncio.run(main())

Sync vs Async

AtomHTTP (sync) and AsyncAtomHTTP (async) expose an identical method surface and share the same urllib3-based transport. AsyncAtomHTTP doesn't reimplement anything — it runs the same blocking call in a worker thread via loop.run_in_executor(), so the event loop stays responsive.

1
2
3
4
5
6
7
8
9
10
11
12
13
from atomhttp import AtomHTTP, AsyncAtomHTTP

# Sync -- the default, no event loop required
client = AtomHTTP(base_url="https://api.example.com")
response = client.get("/users/1")

# Async -- fully optional, identical behavior
async with AsyncAtomHTTP(base_url="https://api.example.com") as client:
    response = await client.get("/users/1")

# Convert between them without losing state (cookies, interceptors, pools):
async_client = client.as_async()
sync_client = async_client.as_sync()

System Requirements

AtomHTTP works on all major operating systems and has minimal requirements. Tested on Python 3.8–3.13 across Linux, macOS, and Windows in CI.

Python Version

  • 3.8
  • 3.9
  • 3.10
  • 3.11
  • 3.12
  • 3.13

Operating Systems

  • Windows 10/11
  • macOS (Intel + Apple Silicon)
  • Linux (Ubuntu, Debian, CentOS, etc.)
  • WSL (Windows Subsystem for Linux)

Your First Request

Let's make a complete example that demonstrates the most common features — still without a single await.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from atomhttp import AtomHTTP

# 1. Create client with configuration
client = AtomHTTP(
    base_url='https://jsonplaceholder.typicode.com',
    timeout=10,
    headers={
        'Accept': 'application/json',
        'User-Agent': 'AtomHTTP-Demo/1.0',
    },
)

# 2. GET request with query parameters
print("Fetching posts...")
response = client.get('/posts', params={'_limit': 3})

print(f"Status: {response.status}")
print(f"Headers: {dict(list(response.headers.items())[:3])}")

for post in response.data:
    print(f"  Post {post['id']}: {post['title'][:40]}...")

# 3. POST request
print("\nCreating a new post...")
new_post = client.post('/posts', data={
    'title': 'Hello AtomHTTP!',
    'body': 'This is my first request with AtomHTTP',
    'userId': 1,
})

print(f"Created with ID: {new_post.data['id']}")
print(f"Response status: {new_post.status}")

# 4. Clean up (releases pooled connections + the thread pool)
client.close()
print("\nDone!")

Next Steps

Now that you've mastered the basics, explore more advanced features.