{"id":40510282,"url":"https://github.com/sequenzia/rest-client","last_synced_at":"2026-01-20T20:03:23.822Z","repository":{"id":326020025,"uuid":"1103469737","full_name":"sequenzia/rest-client","owner":"sequenzia","description":null,"archived":false,"fork":false,"pushed_at":"2025-11-26T00:02:12.000Z","size":54,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-28T10:30:33.835Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sequenzia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-24T23:09:28.000Z","updated_at":"2025-11-26T00:02:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sequenzia/rest-client","commit_stats":null,"previous_names":["sequenzia/rest-client"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/sequenzia/rest-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sequenzia%2Frest-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sequenzia%2Frest-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sequenzia%2Frest-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sequenzia%2Frest-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sequenzia","download_url":"https://codeload.github.com/sequenzia/rest-client/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sequenzia%2Frest-client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28612157,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T18:56:40.769Z","status":"ssl_error","status_checked_at":"2026-01-20T18:54:26.653Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-20T20:03:23.018Z","updated_at":"2026-01-20T20:03:23.808Z","avatar_url":"https://github.com/sequenzia.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Python REST Client\n\nA comprehensive, production-ready Python library for interacting with REST APIs. Built on top of `httpx`, it provides both synchronous and asynchronous clients with support for authentication, retry logic, streaming, and more.\n\n## Features\n\n### Core Capabilities\n- ✅ **Dual Interface**: Both synchronous and asynchronous clients\n- ✅ **All HTTP Methods**: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS\n- ✅ **Authentication**: API Key, Bearer Token, Basic Auth, and custom handlers\n- ✅ **Automatic Retries**: Exponential backoff with jitter for transient failures\n- ✅ **Response Streaming**: Memory-efficient handling of large responses\n- ✅ **Comprehensive Error Handling**: Granular exception hierarchy\n- ✅ **Type Hints**: Full type annotations for excellent IDE support\n- ✅ **Configurable Timeouts**: Connection, read, write, and pool timeouts\n- ✅ **SSL/TLS Support**: Certificate verification and client certificates\n- ✅ **Connection Pooling**: Efficient connection reuse\n- ✅ **Context Managers**: Automatic resource cleanup\n\n## Installation\n\n```bash\npip install rest-client\n```\n\nFor development dependencies:\n\n```bash\npip install rest-client[dev]\n```\n\nFor optional performance improvements:\n\n```bash\npip install rest-client[fast]\n```\n\n## Quick Start\n\n### Synchronous Client\n\n```python\nfrom rest_client import Client\n\n# Create a client\nclient = Client(\n    base_url=\"https://api.example.com\",\n    api_key=\"your-api-key\"\n)\n\n# Make requests\nresponse = client.get(\"/users/123\")\nuser = response.json()\n\n# POST request\nnew_user = client.post(\"/users\", json={\"name\": \"John Doe\", \"email\": \"john@example.com\"})\n\n# With context manager (recommended)\nwith Client(base_url=\"https://api.example.com\", api_key=\"your-key\") as client:\n    users = client.get(\"/users\").json()\n    print(users)\n```\n\n### Asynchronous Client\n\n```python\nfrom rest_client import AsyncClient\n\nasync def main():\n    async with AsyncClient(base_url=\"https://api.example.com\", api_key=\"your-key\") as client:\n        response = await client.get(\"/users/123\")\n        user = response.json()\n\n        # POST request\n        new_user = await client.post(\"/users\", json={\"name\": \"Jane Doe\"})\n```\n\n## Authentication\n\n### API Key Authentication\n\n```python\n# In header (default)\nclient = Client(\n    base_url=\"https://api.example.com\",\n    api_key=\"your-api-key\"\n)\n\n# In query parameter\nclient = Client(\n    base_url=\"https://api.example.com\",\n    api_key=\"your-api-key\",\n    api_key_location=\"query\",\n    api_key_name=\"apikey\"\n)\n```\n\n### Bearer Token Authentication\n\n```python\nclient = Client(\n    base_url=\"https://api.example.com\",\n    bearer_token=\"your-bearer-token\"\n)\n```\n\n### Basic Authentication\n\n```python\nclient = Client(\n    base_url=\"https://api.example.com\",\n    username=\"user\",\n    password=\"pass\"\n)\n```\n\n### Custom Authentication\n\n```python\nfrom rest_client import CustomAuth\n\ndef my_auth_handler(request):\n    request.headers[\"X-Custom-Auth\"] = \"my-token\"\n    return request\n\nclient = Client(\n    base_url=\"https://api.example.com\",\n    auth=CustomAuth(my_auth_handler)\n)\n```\n\n## Making Requests\n\n### GET Requests\n\n```python\n# Simple GET\nresponse = client.get(\"/users\")\n\n# With query parameters\nresponse = client.get(\"/search\", params={\"q\": \"python\", \"limit\": 10})\n\n# With custom headers\nresponse = client.get(\"/users\", headers={\"X-Custom-Header\": \"value\"})\n```\n\n### POST Requests\n\n```python\n# JSON body\nresponse = client.post(\"/users\", json={\"name\": \"John\", \"email\": \"john@example.com\"})\n\n# Form data\nresponse = client.post(\"/login\", data={\"username\": \"user\", \"password\": \"pass\"})\n\n# File upload\nwith open(\"file.txt\", \"rb\") as f:\n    response = client.post(\"/upload\", files={\"file\": f})\n```\n\n### Other HTTP Methods\n\n```python\n# PUT\nresponse = client.put(\"/users/123\", json={\"name\": \"Updated Name\"})\n\n# PATCH\nresponse = client.patch(\"/users/123\", json={\"email\": \"new@example.com\"})\n\n# DELETE\nresponse = client.delete(\"/users/123\")\n\n# HEAD\nresponse = client.head(\"/users/123\")\n\n# OPTIONS\nresponse = client.options(\"/users\")\n```\n\n## Response Streaming\n\nFor large responses, use streaming to avoid loading everything into memory:\n\n```python\n# Synchronous streaming\nwith client.stream(\"GET\", \"/large-file\") as response:\n    for chunk in response.iter_bytes(chunk_size=8192):\n        process_chunk(chunk)\n\n# Asynchronous streaming\nasync with client.stream(\"GET\", \"/large-file\") as response:\n    async for chunk in response.aiter_bytes(chunk_size=8192):\n        await process_chunk(chunk)\n```\n\n## Retry Configuration\n\nConfigure automatic retries for transient failures:\n\n```python\nfrom rest_client import Client, RetryConfig\n\nretry_config = RetryConfig(\n    max_retries=3,\n    retry_status_codes={408, 429, 500, 502, 503, 504},\n    backoff_factor=0.5,\n    max_backoff=60.0,\n    jitter=True\n)\n\nclient = Client(\n    base_url=\"https://api.example.com\",\n    retry=retry_config\n)\n```\n\nTo disable retries:\n\n```python\nclient = Client(\n    base_url=\"https://api.example.com\",\n    retry=None\n)\n```\n\n## Timeout Configuration\n\nConfigure timeouts to prevent hanging requests:\n\n```python\nfrom rest_client import Client, TimeoutConfig\n\n# Simple timeout (applies to all timeout types)\nclient = Client(base_url=\"https://api.example.com\", timeout=30.0)\n\n# Granular timeout configuration\ntimeout_config = TimeoutConfig(\n    connect=5.0,   # Connection timeout\n    read=30.0,     # Read timeout\n    write=30.0,    # Write timeout\n    pool=5.0       # Pool timeout\n)\n\nclient = Client(base_url=\"https://api.example.com\", timeout=timeout_config)\n\n# Per-request timeout override\nresponse = client.get(\"/slow-endpoint\", timeout=60.0)\n```\n\n## Error Handling\n\nThe library provides a comprehensive exception hierarchy:\n\n```python\nfrom rest_client import (\n    ClientError,           # Base exception\n    HTTPError,             # HTTP errors (4xx, 5xx)\n    AuthenticationError,   # 401, 403 errors\n    RateLimitError,        # 429 errors\n    ConnectionError,       # Network errors\n    TimeoutError,          # Timeout errors\n    ValidationError        # Validation errors\n)\n\ntry:\n    response = client.get(\"/users/123\")\nexcept AuthenticationError as e:\n    print(f\"Authentication failed: {e}\")\n    print(f\"Status code: {e.status_code}\")\nexcept RateLimitError as e:\n    print(f\"Rate limited. Retry after: {e.retry_after} seconds\")\nexcept HTTPError as e:\n    print(f\"HTTP error {e.status_code}: {e.message}\")\nexcept ConnectionError as e:\n    print(f\"Connection failed: {e}\")\nexcept TimeoutError as e:\n    print(f\"Request timed out: {e}\")\n```\n\nTo handle errors manually without exceptions:\n\n```python\nclient = Client(\n    base_url=\"https://api.example.com\",\n    raise_for_status_enabled=False\n)\n\nresponse = client.get(\"/users/123\")\nif response.status_code == 200:\n    user = response.json()\nelse:\n    print(f\"Error: {response.status_code}\")\n```\n\n## Advanced Configuration\n\n### SSL/TLS Configuration\n\n```python\n# Disable SSL verification (not recommended for production)\nclient = Client(base_url=\"https://api.example.com\", verify_ssl=False)\n\n# Use custom CA bundle\nclient = Client(base_url=\"https://api.example.com\", cert=\"/path/to/ca-bundle.crt\")\n\n# Client certificate authentication\nclient = Client(\n    base_url=\"https://api.example.com\",\n    cert=(\"/path/to/client.crt\", \"/path/to/client.key\")\n)\n```\n\n### Connection Pool Configuration\n\n```python\nclient = Client(\n    base_url=\"https://api.example.com\",\n    pool_limits={\n        \"max_keepalive_connections\": 20,\n        \"max_connections\": 100\n    }\n)\n```\n\n### Custom Headers\n\n```python\n# Default headers for all requests\nclient = Client(\n    base_url=\"https://api.example.com\",\n    headers={\n        \"User-Agent\": \"MyApp/1.0\",\n        \"Accept\": \"application/json\"\n    }\n)\n\n# Override per request\nresponse = client.get(\"/users\", headers={\"Accept\": \"application/xml\"})\n```\n\n## Complete Example\n\n```python\nfrom rest_client import Client, RetryConfig, TimeoutConfig, HTTPError\n\n# Configure retry and timeout\nretry_config = RetryConfig(max_retries=3, backoff_factor=0.5)\ntimeout_config = TimeoutConfig(connect=5.0, read=30.0)\n\n# Create client with all options\nwith Client(\n    base_url=\"https://api.example.com\",\n    bearer_token=\"your-token\",\n    headers={\"User-Agent\": \"MyApp/1.0\"},\n    timeout=timeout_config,\n    retry=retry_config,\n    verify_ssl=True\n) as client:\n    try:\n        # Get all users\n        users = client.get(\"/users\", params={\"limit\": 100}).json()\n\n        # Create a new user\n        new_user = client.post(\"/users\", json={\n            \"name\": \"John Doe\",\n            \"email\": \"john@example.com\"\n        }).json()\n\n        print(f\"Created user: {new_user['id']}\")\n\n        # Update the user\n        updated = client.patch(f\"/users/{new_user['id']}\", json={\n            \"name\": \"Jane Doe\"\n        }).json()\n\n        print(f\"Updated user: {updated}\")\n\n    except HTTPError as e:\n        print(f\"API error: {e.status_code} - {e.message}\")\n```\n\n## Async Example\n\n```python\nimport asyncio\nfrom rest_client import AsyncClient, HTTPError\n\nasync def main():\n    async with AsyncClient(\n        base_url=\"https://api.example.com\",\n        api_key=\"your-key\"\n    ) as client:\n        try:\n            # Concurrent requests\n            tasks = [\n                client.get(f\"/users/{i}\")\n                for i in range(1, 11)\n            ]\n            responses = await asyncio.gather(*tasks)\n            users = [r.json() for r in responses]\n\n            print(f\"Fetched {len(users)} users concurrently\")\n\n        except HTTPError as e:\n            print(f\"Error: {e}\")\n\nasyncio.run(main())\n```\n\n## Development\n\n### Running Tests\n\n```bash\n# Install dev dependencies\npip install -e \".[dev]\"\n\n# Run tests\npytest\n\n# Run with coverage\npytest --cov=rest_client --cov-report=html\n```\n\n### Code Quality\n\n```bash\n# Format code\nblack rest_client tests\n\n# Lint\nruff check rest_client tests\n\n# Type checking\nmypy rest_client\n```\n\n## Requirements\n\n- Python 3.8+\n- httpx \u003e= 0.24.0\n- certifi \u003e= 2023.0.0\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## Support\n\nFor issues and questions, please use the [GitHub issue tracker](https://github.com/yourusername/rest-client/issues)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsequenzia%2Frest-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsequenzia%2Frest-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsequenzia%2Frest-client/lists"}