Metadata-Version: 2.1
Name: idemptx
Version: 0.2.1
Summary: Idempotency decorator for FastAPI
Home-page: https://github.com/pypy-riley/idemptx
License: MIT
Keywords: fastapi,idempotency,decorator,redis,cache
Author: pypy-riley
Author-email: pypy.riley@gmail.com
Requires-Python: >=3.9,<4.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Dist: fastapi
Requires-Dist: redis (>=4.2,<6.0)
Project-URL: Documentation, https://github.com/pypy-riley/idemptx#readme
Project-URL: Repository, https://github.com/pypy-riley/idemptx
Description-Content-Type: text/markdown

# 🧹 idemptx

[![PyPI - Version](https://img.shields.io/pypi/v/idemptx?color=blue)](https://pypi.org/project/idemptx/)
![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)

> A minimal, pluggable idempotency decorator for FastAPI, designed for payment and retry-safe APIs.

Supports Redis as backend for deduplication, distributed locking, and response caching.

---

## ✨ Features

- ✅ Supports `Idempotency-Key` header out of the box
- 🔒 Redis-backed lock to prevent double execution
- ⚡️ Sync & Async backends with auto-detection
- 🧠 Request signature validation (method + URL + headers + body)
- ⏳ Configurable `wait_timeout` behavior
- 🔁 Response replay from cache (with headers)
- 🔢 In-memory backend for testing/local use

---

## 📦 Installation

```bash
pip install idemptx
```

---

## 🚀 Quick Start

```python
import redis
from fastapi import FastAPI, Request
from idemptx import idempotent
from idemptx.backend import RedisBackend

app = FastAPI()
client = redis.Redis(host='localhost', port=6379, db=0)
redis_backend = RedisBackend(client)

@app.post('/orders')
@idempotent(storage_backend=redis_backend)
async def create_order(request: Request):
    return {'status': 'created'}
```

> ⚠️ You must include `request: Request` in your endpoint parameters!

---

## 🔧 Advanced Usage

```python
@idempotent(
    storage_backend=redis_backend,
    key_ttl=60,
    wait_timeout=3.0,
    validate_signature=True,
)
```

- `key_ttl`: How long to hold cache and lock (in seconds)
- `wait_timeout`: Wait for lock to be released (0 = immediate failure)
- `validate_signature`: Whether to compare request content on replays

---

## 🔀 Async Redis Backend

```python
import redis.asyncio as aioredis
from idemptx.backend import AsyncRedisBackend

async_client = aioredis.Redis(host='localhost', port=6379, db=0)
async_backend = AsyncRedisBackend(async_client)
```

---

## 🔖 In-memory Backend (for testing only)

```python
from idemptx.backend import InMemoryBackend

backend = InMemoryBackend()

@app.post('/example')
@idempotent(storage_backend=backend)
async def create_something(request: Request):
    return {'ok': True}
```

> Note: Not suitable for multi-process or production environments.

---

## 🔐 Response Headers

| Header                    | Description                            |
|---------------------------|----------------------------------------|
| `Idempotency-Key`         | Echoed back to client                  |
| `X-Idempotency-Signature` | Hash of request for conflict detection |
| `X-Idempotency-Status`    | `"hit"` or `"new"`                     |

---

## 📄 License

MIT License © 2025 [pypy-riley](https://github.com/pypy-riley)

