A modern Python framework for building clean, typed, and extensible API clients.
Project description
๐ HakiAPI
Build production-grade Python API SDKs โ not boilerplate.
Authentication ยท Retries ยท Pagination ยท Typed Exceptions ยท Session Management
Stop rewriting authentication, retries, and pagination for every API client you build.
Installation โข Quick Start โข Features โข Architecture โข Create Your Own Client โข Roadmap
Why HakiAPI?
Every API client grows the same infrastructure, in the same order. You start with a simple HTTP call. Then you add authentication. Then retries. Then pagination. Then timeout and exception handling. Then session management. A month later, you've rebuilt the same plumbing you already wrote for the last five projects.
HakiAPI extracts all of that into one reusable core, so every client you build on top of it inherits production-ready behavior automatically. Instead of writing infrastructure, you write business logic.
Without HakiAPI vs. with HakiAPI
Raw requests |
HakiAPI | |
|---|---|---|
| Retry on 429/500/502/503/504 | Write your own urllib3.Retry + HTTPAdapter wiring |
Built into BaseAPIClient automatically |
| Auth (Bearer / API Key / HMAC) | Reimplement per project | 4 reusable AuthBase strategies, drop-in |
| Rate limits, timeouts, 4xx/5xx | Manually check response.status_code everywhere |
Raised as typed, catchable exceptions |
| Pagination | Write a while loop per API's pagination style |
Auto-detects Link-header and cursor/token pagination, iterated lazily |
| New service client | Copy-paste session + error-handling code | Subclass BaseAPIClient, define endpoints, done |
โจ Features
| Feature | Details |
|---|---|
| ๐ Multiple auth strategies | BearerTokenAuth, HeaderApiKeyAuth, QueryApiKeyAuth, HmacAuth |
| ๐ Automatic retries | Exponential backoff on 429/500/502/503/504, mounted transparently on every session |
| ๐ Automatic pagination | Auto-detects Link-header (GitHub-style) and cursor/token (meta.next_token) pagination, lazily iterated with an optional max_pages safety valve |
| โ ๏ธ Typed exception hierarchy | RateLimitError, AuthenticationError, ClientError, ServerError, RequestTimeoutError, all rooted in HakiAPIError |
| ๐ Persistent HTTP sessions | Connection pooling via requests.Session, closed automatically with with |
| ๐งฉ Extensible base client | Subclass BaseAPIClient, inherit everything above for free |
| ๐ฆ Ready-to-use clients | GitHub, Gmail |
| ๐งช Fully tested | 214 tests, full coverage of core + clients |
| ๐ Python 3.10+ | Fully type-hinted |
Installation
pip install hakiapi
Requires Python 3.10+.
Quick Start
GitHub
from hakiapi.clients.github import GitHubClient
with GitHubClient() as github:
user = github.get_user("torvalds")
print(f"{user['name']} โ {user['public_repos']} public repos")
No authentication plumbing. No retry logic. No session handling. Just Python.
Automatic pagination
Forget page numbers, while loops, and manually checking for a next page โ HakiAPI follows Link headers, cursor pagination, and token pagination automatically, lazily:
with GitHubClient() as github:
for repo in github.get_all_user_repos("torvalds"):
print(repo["name"])
A full example
Aggregate every programming language used across a user's public repositories, entirely through the paginator:
from hakiapi.clients.github import GitHubClient
with GitHubClient() as github:
target_user = "Gugilla-Aakash"
user_data = github.get_user(target_user)
print(f"User: {user_data.get('name')}")
print(f"Public Repos: {user_data.get('public_repos')}")
lang_stats = github.get_aggregate_user_languages(target_user, params={"per_page": 5})
total_bytes = sum(lang_stats.values())
print("\nLanguage Breakdown (by byte allocation):")
for lang, byte_count in sorted(lang_stats.items(), key=lambda i: i[1], reverse=True):
percentage = (byte_count / total_bytes) * 100 if total_bytes else 0
print(f"- {lang}: {byte_count} bytes ({percentage:.2f}%)")
Output shape is illustrative โ real numbers depend on the account queried.
Gmail
from hakiapi.clients.gmail import GmailClient
with GmailClient(token="your-oauth-token") as gmail:
for message in gmail.get_all_messages():
print(message["id"])
Authentication, pagination, and retries โ already handled.
Exception Handling
Never check HTTP status codes manually again:
from hakiapi.core.exceptions import AuthenticationError, RateLimitError, ServerError
try:
github.get_user("torvalds")
except RateLimitError as e:
print(f"Rate limited โ retry after {e.retry_after}s")
except AuthenticationError:
print("Invalid credentials.")
except ServerError:
print("GitHub is currently unavailable.")
Every exception inherits from HakiAPIError, so you can catch broadly or narrowly โ each carries status_code and the original response object.
HakiAPIError
โโโ ClientError (4xx)
โ โโโ RateLimitError (429, carries retry_after)
โ โโโ AuthenticationError (401 / 403, carries auth_method)
โโโ ServerError (5xx)
โโโ RequestTimeoutError (network-level timeout, no status code)
Supported Authentication
| Strategy | Use case |
|---|---|
BearerTokenAuth |
Standard Authorization: Bearer <token> (GitHub, Gmail, most OAuth2 APIs) |
HeaderApiKeyAuth |
Custom header-based API keys (e.g. X-API-Key: <key>) |
QueryApiKeyAuth |
Query-string API keys, appended without dropping existing params |
HmacAuth |
HMAC-SHA256 request signing โ signs method, path, timestamp, and body; sets the key, timestamp, and signature headers |
Every strategy is a reusable AuthBase instance โ pass it once into BaseAPIClient.__init__, and every request is signed automatically.
Automatic Retry
Retries happen transparently on 429, 500, 502, 503, and 504, via urllib3's Retry mounted on the session's HTTPAdapter:
- Exponential backoff
- Connection reuse across retries
- Timeout handling surfaced as
RequestTimeoutError - No configuration required for standard usage โ override
total_retries,backoff_factor, orstatus_forcelistif you need to
Architecture
GitHubClient, GmailClient, ...
โ
โผ
BaseAPIClient
โโโโโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโโ
โ โ โ โ
Authentication Retry Pagination Exceptions
(auth.py) (retry.py) (paginator.py) (exceptions.py)
โ
โผ
requests
Every service client inherits production-ready infrastructure automatically โ nothing to wire up per client.
Create Your Own Client
Creating a new SDK is intentionally simple: subclass BaseAPIClient, point it at a base URL, and define your endpoints as plain methods.
from hakiapi import BaseAPIClient
class WeatherClient(BaseAPIClient):
def __init__(self, **kwargs):
super().__init__(base_url="https://api.open-meteo.com/v1", **kwargs)
def get_weather(self, latitude: float, longitude: float):
return self.get(
"forecast",
params={
"latitude": latitude,
"longitude": longitude,
"current_weather": True,
},
)
if __name__ == "__main__":
# Hyderabad, Telangana, India
with WeatherClient() as client:
weather = client.get_weather(latitude=17.385, longitude=78.4867)
print(weather["current_weather"])
Output
{
'time': '2026-07-19T10:00',
'interval': 900,
'temperature': 30.6,
'windspeed': 13.9,
'winddirection': 271,
'is_day': 1,
'weathercode': 51
}
Authentication, retries, pagination, sessions, and exceptions are already included โ you only write the endpoint logic.
Project Structure
hakiapi/
โโโ core/
โ โโโ auth.py # BearerTokenAuth, HeaderApiKeyAuth, QueryApiKeyAuth, HmacAuth
โ โโโ retry.py # Exponential-backoff HTTPAdapter factory
โ โโโ paginator.py # Link-header + cursor/token pagination, lazily iterated
โ โโโ base_client.py # Session management, request lifecycle, error mapping
โ โโโ exceptions.py # Typed exception hierarchy
โ
โโโ clients/
โโโ github.py # GitHubClient
โโโ gmail.py # GmailClient
Design Principles
- Infrastructure should be written once.
- API clients should remain lightweight.
- Explicit is better than magical.
- Strong typing improves maintainability.
- Production readiness should be the default, not an afterthought.
- Developer experience matters as much as correctness.
Testing
pip install hakiapi[dev]
pytest
- โ 214 tests passing
- โ Core framework covered (auth, retry, paginator, base client, exceptions)
- โ GitHub client covered
- โ Gmail client covered
Roadmap
Completed
- Base API framework (
BaseAPIClient) - Authentication system (Bearer, Header, Query, HMAC)
- Retry engine with exponential backoff
- Automatic pagination (Link header + cursor/token)
- Typed exception hierarchy
- GitHub client
- Gmail client
Planned
- Google Calendar client
- Stripe client
- Twitter/X client
- Async client (
httpx-based) - OAuth2 helpers
- Plugin system
- More service clients
Contributing
Contributions are welcome โ bug fixes, documentation, tests, or new clients. Please open an issue before proposing major changes so we can discuss the approach first.
License
MIT License โ see LICENSE for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hakiapi-1.2.0.tar.gz.
File metadata
- Download URL: hakiapi-1.2.0.tar.gz
- Upload date:
- Size: 28.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1f61227c88d0f98a01dec9f67fdc90e67bc039d9d09502b344ca9e53fe9446a
|
|
| MD5 |
1a5d0a038649358ece993cd3a5d8479d
|
|
| BLAKE2b-256 |
ccba42fc8c86fc6c7d5f58363dfde3db9656ffc4c617cf315425f6919c4f651a
|
Provenance
The following attestation bundles were made for hakiapi-1.2.0.tar.gz:
Publisher:
release.yml on Gugilla-Aakash/hakiapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hakiapi-1.2.0.tar.gz -
Subject digest:
b1f61227c88d0f98a01dec9f67fdc90e67bc039d9d09502b344ca9e53fe9446a - Sigstore transparency entry: 2202310390
- Sigstore integration time:
-
Permalink:
Gugilla-Aakash/hakiapi@5f60b48f9bf2af4689966229c4e5ee06f8edde4d -
Branch / Tag:
refs/tags/v1.2.0 - Owner: https://github.com/Gugilla-Aakash
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5f60b48f9bf2af4689966229c4e5ee06f8edde4d -
Trigger Event:
release
-
Statement type:
File details
Details for the file hakiapi-1.2.0-py3-none-any.whl.
File metadata
- Download URL: hakiapi-1.2.0-py3-none-any.whl
- Upload date:
- Size: 14.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
adeaa4d45eda4b286846f28f51ee1d80797172cd048d16ed5f77d52ba9967448
|
|
| MD5 |
73c678627661c26d4e40ab55a60c19b9
|
|
| BLAKE2b-256 |
84f5806d9af049d54b560087640fda3561334297f42f2c3cde96c123b95a3d1a
|
Provenance
The following attestation bundles were made for hakiapi-1.2.0-py3-none-any.whl:
Publisher:
release.yml on Gugilla-Aakash/hakiapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hakiapi-1.2.0-py3-none-any.whl -
Subject digest:
adeaa4d45eda4b286846f28f51ee1d80797172cd048d16ed5f77d52ba9967448 - Sigstore transparency entry: 2202310419
- Sigstore integration time:
-
Permalink:
Gugilla-Aakash/hakiapi@5f60b48f9bf2af4689966229c4e5ee06f8edde4d -
Branch / Tag:
refs/tags/v1.2.0 - Owner: https://github.com/Gugilla-Aakash
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5f60b48f9bf2af4689966229c4e5ee06f8edde4d -
Trigger Event:
release
-
Statement type: