Core API

Essential HTTP methods and configuration for everyday use — every method is synchronous by default

HTTP Methods

AtomHTTP supports all standard HTTP methods with a plain, synchronous interface -- no await required. Each method returns a Response object containing the parsed response body, status code, headers, and original request configuration. The exact same methods exist on AsyncAtomHTTP, just awaited.

GET Request

Retrieve data from a server. GET requests should only retrieve data and should not have any other effect. Returns a Response directly -- no await needed.

Parameters

ParameterTypeDefaultDescription
urlstrRequiredThe endpoint URL
paramsdict{}Query parameters for filtering, pagination, sorting
headersdict{}Custom HTTP headers
responseTypestr"json"Response format: json, text, blob, arraybuffer, stream
timeoutint/float30Override client timeout

Returns

Response Response object containing data, status, headers, config

Example

1
2
3
4
5
6
7
8
9
# Basic GET request
response = client.get('https://api.example.com/users')

# GET with query parameters
response = client.get('/users', params={'page': 1, 'limit': 10, 'sort': 'desc'})
print(response.data)

# GET with custom headers
response = client.get('/protected', headers={'Authorization': 'Bearer token123'})

POST Request

Send data to create a new resource. Accepts JSON, FormData, URL-encoded data, or raw bytes. Large file uploads via FormData stream automatically -- the file is never fully loaded into memory.

Parameters

ParameterTypeDefaultDescription
urlstrRequiredThe endpoint URL
dataAnyNoneRequest body (dict, FormData, bytes, str)
headersdict{}Custom HTTP headers (Content-Type auto-detected)
responseTypestr"json"Response format
onUploadProgressCallableNoneProgress callback for uploads: fn(loaded, total)

Returns

Response Response object with created resource data

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# POST with JSON data
user_data = {'name': 'John Doe', 'email': 'john@example.com'}
response = client.post('/users', data=user_data)
print(f"Created ID: {response.data['id']}")

# POST with FormData (file upload -- large files stream automatically)
from atomhttp import FormData
form = FormData()
form.append('name', 'John Doe')
form.append('avatar', open('photo.jpg', 'rb'), filename='photo.jpg')
response = client.post('/users', data=form)

# POST with progress tracking
def on_progress(loaded, total):
    print(f"Uploaded: {loaded}/{total} bytes")
response = client.post('/upload', data=large_file, onUploadProgress=on_progress)

PUT Request

Completely replace an existing resource. Requires the complete resource data.

Parameters

ParameterTypeDefaultDescription
urlstrRequiredThe endpoint URL with resource ID
datadictRequiredComplete resource data
headersdict{}Custom HTTP headers

Returns

Response Response object with updated resource data

Example

1
2
3
4
5
6
7
# Full resource replacement
update_data = {'id': 1, 'name': 'Jane Doe', 'email': 'jane@example.com', 'role': 'admin'}
response = client.put('/users/1', data=update_data)

# Conditional update
response = client.put('/users/1', data=update_data,
    headers={'If-Unmodified-Since': 'Wed, 21 Oct 2024 07:28:00 GMT'})

PATCH Request

Partially update an existing resource. Only send the fields that need to be changed.

Parameters

ParameterTypeDefaultDescription
urlstrRequiredThe endpoint URL with resource ID
datadictRequiredFields to update (partial data)
headersdict{}Custom HTTP headers

Returns

Response Response object with updated resource data

Example

1
2
3
4
5
6
7
8
9
10
# Partial update
response = client.patch('/users/1', data={'email': 'newemail@example.com'})

# Update multiple fields
response = client.patch('/users/1', data={'email': 'newemail@example.com', 'role': 'editor'})

# JSON Patch operations
response = client.patch('/users/1', data=[
    {'op': 'replace', 'path': '/email', 'value': 'new@example.com'}
])

DELETE Request

Remove a resource from the server.

Parameters

ParameterTypeDefaultDescription
urlstrRequiredThe endpoint URL with resource ID
paramsdict{}Query parameters for batch delete
headersdict{}Custom HTTP headers

Returns

Response Response object (status 204 on success)

Example

1
2
3
4
5
6
7
8
9
10
# Delete a single resource
response = client.delete('/users/1')
if response.status == 204:
    print("User deleted successfully")

# Batch delete
response = client.delete('/users', params={'ids': '1,2,3'})

# Conditional delete
response = client.delete('/users/1', headers={'If-Match': 'etag123'})

HEAD Request

Retrieve headers only, without the response body.

Parameters

ParameterTypeDefaultDescription
urlstrRequiredThe endpoint URL
headersdict{}Custom HTTP headers

Returns

Response Response object with headers but empty body

Example

1
2
3
4
5
6
7
8
9
# Check if resource exists
response = client.head('/large-file.pdf')
print(f"Size: {response.headers.get('Content-Length')} bytes")
print(f"Type: {response.headers.get('Content-Type')}")
print(f"Modified: {response.headers.get('Last-Modified')}")

# Check API health
response = client.head('/health')
print(f"Status: {'healthy' if response.ok else 'unhealthy'}")

OPTIONS Request

Discover which HTTP methods are supported by a resource.

Parameters

ParameterTypeDefaultDescription
urlstrRequiredThe endpoint URL
headersdict{}Custom HTTP headers

Returns

Response Response with Allow header listing supported methods

Example

1
2
3
4
5
6
7
8
9
# Discover allowed methods
response = client.options('/users/1')
print(f"Allowed: {response.headers.get('Allow', '')}")

# CORS preflight
response = client.options('/api/data', headers={
    'Origin': 'https://myapp.com',
    'Access-Control-Request-Method': 'POST'
})

Generic Request Method

Unified request method for maximum flexibility.

Parameters

ParameterTypeDefaultDescription
methodstr"GET"HTTP method (GET, POST, etc.)
urlstrRequiredRequest URL
dataAnyNoneRequest body
paramsdict{}Query parameters
headersdict{}Custom headers
timeoutint30Request timeout

Returns

Response Response object

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Full control over request configuration
response = client.request(
    'POST',
    '/api/data',
    data={'key': 'value'},
    headers={'X-Custom': 'header'},
    params={'version': 'v2'},
    timeout=30,
    maxRedirects=0,
    responseType='text',
)

# Dynamic method selection
method = 'DELETE' if condition else 'PUT'
response = client.request(method, '/resource/1')

Response Object

Every request returns a Response object with the following properties:

PropertyDescriptionTypeExample
response.dataParsed response bodydict, list, str, bytesresponse.data['id']
response.statusHTTP status codeintresponse.status == 200
response.status_textHTTP status messagestrresponse.status_text
response.headersResponse headersdictresponse.headers['Content-Type']
response.configOriginal request configRequestConfigresponse.config.url
response.okSuccess indicator (200-299)boolif response.ok: ...
response.elapsedWall-clock request durationfloat | Noneresponse.elapsed
response.urlFinal URL after redirectsstr | Noneresponse.url
1
2
3
4
5
6
7
8
response = client.get('https://httpbin.org/get')
print(f"Status: {response.status} {response.status_text}")
print(f"Content-Type: {response.headers.get('Content-Type')}")
print(f"Body: {response.data}")
print(f"URL: {response.config.url}")

# Chainable status check
data = client.get('/users/1').raise_for_status().data

Response Types

json

Parses as dict/list (default)

text

Returns raw text → str

blob / arraybuffer

Returns binary → bytes

stream

Raw urllib3.HTTPResponse — prefer client.stream()

Client Configuration

Configure your client with defaults that apply to every request:

OptionTypeDefaultDescription
base_urlstr""Base URL prepended to relative paths
timeoutint/float30Request timeout in seconds
headersdict{}Default headers sent with every request
cookiesboolTrueEnable the client's persistent cookie jar
max_workersint10Size of the persistent thread pool backing .all()/.submit()/.map()
maxRedirectsint5Maximum number of redirects to follow
responseTypestr"json"Response format: json, text, blob, arraybuffer, stream
keepAliveboolTrueEnable HTTP keep-alive connections
verifybool | strTrueSSL verification: True/False, or a path to a custom CA bundle
certstr | tupleNoneClient cert for mTLS: a path, or (cert_path, key_path)
retryConfigdictNoneRetry settings for transient failures: max_retries, backoff_factor, status_forcelist. Retry-After is honored automatically.
decompressboolTrueAutomatically decompress gzip/deflate/brotli responses
adapterBaseAdapterHTTPAdapter()Custom transport adapter, e.g. MockAdapter for tests
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
client = AtomHTTP(
    base_url='https://api.example.com',
    timeout=15,
    headers={'X-API-Key': 'your-api-key', 'Accept': 'application/json'},
    maxRedirects=3,
    responseType='json',
    keepAlive=True,
    verify=True,
    max_workers=20,
    retryConfig={
        'max_retries': 3,
        'backoff_factor': 0.3,
        'status_forcelist': [408, 429, 500, 502, 503, 504],
    },
)

# All requests use these defaults
response = client.get('/users')

# Override for specific request
response = client.get('/slow', timeout=60)

Configuration Inheritance

Client-level defaults are merged with request-level options. Headers are deeply merged (request headers override client headers), while other options are replaced entirely.

Headers & Query Parameters

Add custom headers for authentication and metadata. Use query parameters for filtering and pagination.

1
2
3
4
response = client.get('https://httpbin.org/get',
    params={'search': 'python', 'page': 2, 'limit': 20},
    headers={'Authorization': 'Bearer token123', 'X-Custom-Header': 'value'}
)

Common Headers

Authorization

Bearer token or Basic auth

Content-Type

Media type of request body

Accept

Expected response media type

User-Agent

Client identifier

Query Parameter Best Practices

  • Use params for GET, DELETE requests
  • Avoid sensitive data in query parameters (they appear in logs)
  • Use lists for multi-value parameters
  • Auto URL-encoded — no manual encoding needed

Response Types In Depth

responseType controls how the body is parsed. For JSON, if the server claims JSON but the body isn't valid, the raw text is returned instead of raising — the same leniency axios/requests offer.

1
2
3
4
5
6
7
client.get('/data')                          # responseType='json' (default)
client.get('/page', responseType='text')      # -> str
client.get('/image.png', responseType='arraybuffer')  # -> bytes
client.get('/report.pdf', responseType='blob')        # -> bytes

# For truly large responses, prefer client.stream() over responseType='stream'
# -- see Advanced Features > Streaming, Download & Pagination

Error Types

AtomHTTP provides comprehensive error types with standardized error codes. By default, no exception is raised for 4xx/5xx -- use validateStatus or raise_for_status() to opt in.

Error TypeDescriptionError Code
AtomHTTPRequestErrorBad request (4xx) or malformed request, or rejected by validateStatusERR_BAD_{status}
AtomHTTPNetworkErrorNetwork connectivity issues, DNS errors, connection refusedERR_NETWORK
AtomHTTPTimeoutErrorRequest exceeded timeout limitECONNABORTED
AtomHTTPCancelErrorRequest was aborted via AbortControllerERR_CANCELED
1
2
3
4
5
6
7
8
9
10
from atomhttp.errors import AtomHTTPTimeoutError, AtomHTTPNetworkError, AtomHTTPRequestError

try:
    response = client.get('https://api.example.com/data', timeout=5, validateStatus=lambda s: s < 400)
except AtomHTTPTimeoutError as e:
    print(f"Timeout: {e.code}")  # ECONNABORTED
except AtomHTTPNetworkError as e:
    print(f"Network error: {e.code}")  # ERR_NETWORK
except AtomHTTPRequestError as e:
    print(f"Request failed: {e.code} - Status {e.response.status}")  # ERR_BAD_404

Error Handling Best Practices

  • Catch specific error types before generic Exception
  • Use error.code for programmatic handling
  • Check error.response.data for server error details
  • Use retryConfig for automatic retry on timeout/network errors instead of manual retry loops