Metadata-Version: 2.1
Name: wexample-api
Version: 6.8.3
Summary: Provides an AbstractGateway base class that handles HTTP requests with rate limiting, status-code validation, retry logic, and structured error reporting for building typed API client gateways
Author-Email: weeger <contact@wexample.com>
License: MIT
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Project-URL: homepage, https://github.com/wexample/python-api
Requires-Python: >=3.10
Requires-Dist: attrs>=23.1.0
Requires-Dist: cattrs>=23.1.0
Requires-Dist: requests
Requires-Dist: wexample-helpers>=19.1.0
Requires-Dist: wexample-prompt>=15.0.0
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Description-Content-Type: text/markdown

# api

Version: 6.8.3

`wexample-api` provides an `AbstractGateway` base class for building typed HTTP API client gateways in Python. It wraps `requests` with built-in rate limiting, configurable timeout, status-code validation, exponential-backoff retries, and structured error reporting via `wexample-prompt`, so a concrete gateway only needs to declare a `base_url` and call `make_request`. The package targets Python developers who integrate third-party REST APIs and want to centralise connection handling, logging, and error propagation without writing the same boilerplate for each service.

## Table of Contents

- [Installation](#installation)
- [Quickstart](#quickstart)
- [Tests](#tests)
- [Architecture](#architecture)
- [Integration in the Suite](#integration-in-the-suite)
- [Dependencies](#dependencies)
- [Versioning & Compatibility Policy](#versioning--compatibility-policy)
- [License](#license)
- [About us](#about-us)
- [Known Limitations & Roadmap](#known-limitations--roadmap)
- [Status & Compatibility](#status--compatibility)
- [Useful Links](#useful-links)
- [Migration Notes](#migration-notes)

## Installation

```bash
pip install wexample-api
```

Requires Python >=3.10.

## Quickstart

Install the package:

```bash
pip install wexample-api
```

Subclass `AbstractGateway`, pass `base_url` and an `IoManager`, then call `make_request`:

```python
from wexample_api.common.abstract_gateway import AbstractGateway
from wexample_api.enums.http import HttpMethod
from wexample_helpers.decorator.base_class import base_class
from wexample_prompt.common.io_manager import IoManager

@base_class
class JsonPlaceholderGateway(AbstractGateway):
    def get_post(self, post_id: int) -> dict | None:
        response = self.make_request(
            endpoint=f"/posts/{post_id}",
            method=HttpMethod.GET,
            expected_status_codes=200,
        )
        return response.json() if response else None

gateway = JsonPlaceholderGateway(
    base_url="https://jsonplaceholder.typicode.com",
    io=IoManager(),
)

post = gateway.get_post(1)
print(post["title"])
# sunt aut facere repellat provident occaecati excepturi optio reprehenderit
```

`make_request` returns the raw `requests.Response` when the actual status code is in `expected_status_codes`, or `None` when it is not. Omitting `expected_status_codes` accepts any response. The `@base_class` decorator is required: `AbstractGateway` uses `wexample_helpers` field initialisation that depends on it.

A runnable, annotated version of this example lives at examples/common/http_request_example.py.

## Tests

This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.

### Installation

First, install the required testing dependencies:
```bash
.venv/bin/python -m pip install pytest pytest-cov
```

### Basic Usage

Run all tests with coverage:
```bash
.venv/bin/python -m pytest --cov --cov-report=html
```

### Common Commands
```bash
# Run tests with coverage for a specific module
.venv/bin/python -m pytest --cov=your_module

# Show which lines are not covered
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing

# Generate an HTML coverage report
.venv/bin/python -m pytest --cov=your_module --cov-report=html

# Combine terminal and HTML reports
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html

# Run specific test file with coverage
.venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
```

### Viewing HTML Reports

After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.

### Coverage Threshold

To enforce a minimum coverage percentage:
```bash
.venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
```

This will cause the test suite to fail if coverage drops below 80%.

## Architecture

`wexample-api` ships one thing: `AbstractGateway`, a base class callers subclass to build typed HTTP clients. The rest of the package feeds that class — enums for the HTTP vocabulary, a payload dataclass that carries each request's parameters, two error types for the failure modes gateways commonly signal, and a demo subclass that shows the pattern in use.

### Modules

| File | Owns |
|------|------|
| src/wexample_api/common/abstract_gateway.py | `AbstractGateway` — the only class callers subclass |
| src/wexample_api/common/http_request_payload.py | `HttpRequestPayload` — value object assembled for each call |
| src/wexample_api/enums/http.py | `HttpMethod`, `ContentType`, `Header` enums |
| src/wexample_api/const/http.py | `HTTP_METHOD_MAP` — string-to-`HttpMethod` lookup |
| src/wexample_api/errors/gateway_connexion_error.py | `GatewayConnectionError` |
| src/wexample_api/errors/gateway_authentication_error.py | `GatewayAuthenticationError` |
| src/wexample_api/demo/demo_simple_gateway.py | `DemoSimpleGateway` — concrete subclass used in tests |

`src/wexample_api/middleware/` and `src/wexample_api/models/` are currently empty; they are stubs reserved for a planned rework documented in `.wex/journal/todo/abstract-gateway-rework.md`.

### AbstractGateway

`AbstractGateway` inherits three mixins from `wexample-helpers` and `wexample-prompt`:

- `WithIoManager` — exposes `self.io` for structured terminal output (`debug`, `error`, `properties`)
- `HasTwoStepInit` — two-phase initialisation; `setup()` is the second phase
- `HasSnakeShortClassNameClassMixin` — `get_class_name_suffix` strips `"GatewayService"` from derived class names

Its public fields control the request lifecycle:

- `base_url` — prepended to every endpoint
- `default_headers` — merged into every call's header dict
- `connected` / `rate_limit_delay` / `timeout` — connection and throttle configuration
- `quiet` — suppresses non-error log lines when `True`
- `last_exception` / `last_request_time` — per-instance mutable state written after each call

Concrete subclasses declare domain methods (e.g. `get_user`, `create_item`) and delegate to `self.make_request`.

### HttpRequestPayload

`HttpRequestPayload` is the internal transfer object for one HTTP call. `make_request` constructs it with `HttpRequestPayload.from_endpoint()`, which joins `base_url` and `endpoint` (stripping duplicate slashes) and coerces a bare `int` in `expected_status_codes` to a one-element list. The payload object then travels into `handle_api_response`, where it provides the URL, method, data, and `call_origin` for log lines and error details.

### Call path through make_request

1. **Retry wrapper.** If `retries > 0`, the call is handed to `RetryableCallbackManager` from `wexample-helpers`, which re-invokes `make_request` with `raise_exceptions=True` and exponential back-off (`backoff_base_seconds=3`), retrying only on `GatewayError`.

2. **Payload assembly.** `HttpRequestPayload.from_endpoint()` constructs the full URL and normalises the status-code argument.

3. **Connection.** If `self.connected` is `False`, `connect()` is called; the base implementation sets the flag and returns `True`. Subclasses override this to perform real handshakes.

4. **Rate limiting.** `_handle_rate_limiting()` sleeps as needed so that consecutive calls are at least `rate_limit_delay` seconds apart.

5. **Body dispatch.** The content type of the merged headers determines how the body travels: `files=` for multipart, `data=` for `application/x-www-form-urlencoded`, `application/octet-stream`, and `text/plain`, `json=` for everything else (including when no `Content-Type` is set).

6. **HTTP call.** `requests.request(**request_kwargs)` executes the call. On `RequestException`, a `GatewayError` is created, stored in `last_exception`, and passed to `handle_api_response` with `response=None`; if `raise_exceptions=True` the error is raised instead.

7. **Status validation.** If `expected_status_codes` was supplied and the response status is not in the set, a `GatewayError` is created (and raised immediately when `raise_exceptions=True`).

8. **Response handling.** `handle_api_response` logs the outcome via `self.io` and returns the `requests.Response` object, or `None` when the call failed and `fatal_on_error` is `False`. When `fatal_on_error` is `True`, it calls `self.io.error(..., fatal=True)`, which terminates the process.

### Errors

Both `GatewayConnectionError` and `GatewayAuthenticationError` subclass `GatewayError` from `wexample-helpers`. `AbstractGateway.make_request` itself raises only `GatewayError`; the two subclasses are available for concrete gateways that need callers to distinguish the failure mode.

### External dependencies

`AbstractGateway` calls `requests.request` directly — the `requests` library is the only HTTP transport. `wexample-prompt` supplies `IoManager` for all output. `wexample-helpers` supplies `RetryableCallbackManager`, `GatewayError`, and the class infrastructure (`base_class` decorator, `public_field`, `HasTwoStepInit`).

## Integration in the Suite

This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.

### Related Packages

The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.

Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.

## Dependencies

- attrs: >=23.1.0
- cattrs: >=23.1.0
- requests: 
- wexample-helpers: >=19.1.0
- wexample-prompt: >=15.0.0

## Versioning & Compatibility Policy

Wexample packages follow **Semantic Versioning** (SemVer):

- **MAJOR**: Breaking changes
- **MINOR**: New features, backward compatible
- **PATCH**: Bug fixes, backward compatible

We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

Free to use in both personal and commercial projects.

## About us

[Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.

This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.

Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.

## Known Limitations & Roadmap

Current limitations and planned features are tracked in the GitHub issues.

See the [project roadmap](https://github.com/wexample/python-api/issues) for upcoming features and improvements.

## Status & Compatibility

**Maturity**: Production-ready

**Python Support**: >=3.10

**OS Support**: Linux, macOS, Windows

**Status**: Actively maintained

## Useful Links

- **Homepage**: https://github.com/wexample/python-api
- **Documentation**: [docs.wexample.com](https://docs.wexample.com)
- **Issue Tracker**: https://github.com/wexample/python-api/issues
- **Discussions**: https://github.com/wexample/python-api/discussions
- **PyPI**: [pypi.org/project/wexample-api](https://pypi.org/project/wexample-api/)

## Migration Notes

When upgrading between major versions, refer to the migration guides in the documentation.

Breaking changes are clearly documented with upgrade paths and examples.
