Metadata-Version: 2.4
Name: autorestify
Version: 2.0.0
Summary: Dynamic API generator from JSON models with automatic schema inference.
Author: Mikael Aurio Martins
License-Expression: MIT
Project-URL: Homepage, https://github.com/MikaelMartins/autorestify
Project-URL: Repository, https://github.com/MikaelMartins/autorestify
Project-URL: Issues, https://github.com/MikaelMartins/autorestify/issues
Keywords: starlette,rest-api,dynamic-api,aiosqlite,schema,automation,multi-tenant,rbac
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: starlette>=0.27.0
Requires-Dist: aiosqlite>=0.17.0
Provides-Extra: server
Requires-Dist: uvicorn>=0.27.0; extra == "server"
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: httpx>=0.27.0; extra == "dev"
Requires-Dist: coverage>=7.0.0; extra == "dev"
Requires-Dist: black>=24.0.0; extra == "dev"
Requires-Dist: ruff>=0.3.0; extra == "dev"
Requires-Dist: mypy>=1.8.0; extra == "dev"
Dynamic: license-file

# AutoRESTify

**The High-Performance Runtime Engine for Persistent REST APIs.**

AutoRESTify transforms JSON collections into complete, persistent, and secure REST APIs at runtime — no code generation, no ORM, no boilerplate.

---

## 🆕 What's New in v2.0 — Zero-ORM Stack

The entire dependency tree was replaced with minimal, targeted libraries:

| Removed | Replaced by | Savings |
|---|---|---|
| FastAPI + pydantic + pydantic_core | Starlette | −10 MB |
| SQLAlchemy ORM | raw `aiosqlite` SQL | −22 MB |
| **Total install footprint** | **~3.5 MB** | **−30 MB (−90%)** |
| **Import time** | **~80 ms** | **−400 ms (−83%)** |

Additional gains:
- `table_exists()` is O(1) in-memory lookup — zero DB round-trips per request
- No ORM serialization overhead — raw `dict` from SQLite cursor
- Test suite runs in **0.30 s** (was 0.99 s)

> **Breaking change:** `create_router()` now returns a Starlette `Router` instead of a FastAPI `APIRouter`. For FastAPI projects, mount the Starlette app with `fastapi_app.mount("/api", create_app())`.

---

## 🚀 Features

- Dynamic route generation from JSON uploads
- Automatic schema inference (no schema definition required)
- Async SQLite persistence via `aiosqlite` (non-blocking I/O)
- Full CRUD support with paginated list responses
- Filtering, pagination, and ordering on list endpoints
- RBAC with Bearer-token authentication
- Multi-tenant isolation (row-level, pluggable resolver)
- Pluggable security architecture (custom auth/policy via ABCs)
- In-memory database for test isolation (`sqlite:///:memory:`)
- Lightweight: only `starlette` + `aiosqlite` dependencies

---

## 📦 Installation

```bash
pip install autorestify
```

With uvicorn included:

```bash
pip install autorestify[server]
```

Local development:

```bash
git clone https://github.com/MikaelMartins/autorestify.git
cd autorestify
pip install -e ".[server]"
```

---

## ⚡ Quick Start

```python
from autorestify import create_app
import uvicorn

app = create_app()  # Starlette ASGI app, SQLite at ./autorestify.db

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)
```

```bash
uvicorn main:app --reload
```

`create_app()` accepts optional `database`, `security`, and `tenant_resolver` arguments for full customization.

---

## 📤 Uploading a collection

Send a JSON payload to `/upload` to register a collection and its documents:

```http
POST /upload
Content-Type: application/json

{
  "collection": "clientes",
  "documents": [
    {"name": "Ana", "age": 30},
    {"name": "Carlos", "age": 25}
  ]
}
```

AutoRESTify infers the schema and creates the table. The following routes are immediately available:

```
GET    /clientes           → list (paginated)
GET    /clientes/{id}      → single item
POST   /clientes           → create
PUT    /clientes/{id}      → update
DELETE /clientes/{id}      → delete
```

---

## 🔍 Filtering, Pagination & Ordering

The `GET /{collection}` endpoint supports query parameters:

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `page` | int ≥ 1 | `1` | Page number |
| `page_size` | int 1–1000 | `20` | Items per page |
| `order_by` | string | — | Field name to sort by |
| `order` | `asc` \| `desc` | `asc` | Sort direction |
| `<field>=<value>` | any | — | Exact-match filter |

```http
GET /clientes?age=30&order_by=name&order=asc&page=1&page_size=10
```

Response envelope:

```json
{
  "data": [...],
  "total": 42,
  "page": 1,
  "page_size": 10,
  "pages": 5
}
```

---

## 🔐 RBAC (Role-Based Access Control)

Fine-grained access control via three building blocks:

| Class | Role |
|---|---|
| `RBACUser` | Carries the user's name and list of roles |
| `RBACPolicy` | Maps `(role, resource) → {read, write, delete}` |
| `TokenAuthProvider` | Resolves `Authorization: Bearer <token>` to an `RBACUser` |

```python
from autorestify import create_app, Database
from autorestify.core.rbac import RBACUser, RBACPolicy, TokenAuthProvider
from autorestify.core.security import SecurityManager

policy = RBACPolicy({
    "admin":  {"*":        {"read", "write", "delete"}},
    "reader": {"*":        {"read"}},
    "editor": {"products": {"read", "write"}},
})

auth = TokenAuthProvider({
    "tok-alice": RBACUser(name="alice", roles=["admin"]),
    "tok-bob":   RBACUser(name="bob",   roles=["reader"]),
})

security = SecurityManager(auth_provider=auth, access_policy=policy)
app = create_app(security=security)
```

Permissions can be updated at runtime via `policy.grant(role, resource, actions)` and `policy.revoke(role, resource)`.

---

## 🏢 Multi-tenant Architecture

Row-level tenancy is built into every collection. All requests are automatically scoped to a tenant — no manual filtering needed.

```python
from autorestify import create_app, Database, HeaderTenantResolver

app = create_app(
    database=Database(),
    tenant_resolver=HeaderTenantResolver(),  # reads X-Tenant-ID header
)
```

| Resolver | Behaviour |
|---|---|
| `HeaderTenantResolver(header="X-Tenant-ID")` | Reads header; defaults to `"default"` if absent |
| `SingleTenantResolver()` | Always `"default"` — zero-config (library default) |

- Every collection gains an indexed `tenant_id` column automatically.
- `GET`, `POST`, `PUT`, `DELETE` are all scoped — cross-tenant access returns 404.
- `tenant_id`, `id`, and `created_at` are write-protected and cannot be overwritten via `PUT`.
- Filtering, pagination, and ordering all operate within the caller's tenant scope.

---

## 🔗 FastAPI Integration

`create_app()` returns a standard Starlette ASGI app that can be mounted on any ASGI framework:

```python
from fastapi import FastAPI
from autorestify import create_app, Database

fastapi_app = FastAPI()
fastapi_app.mount("/api", create_app(database=Database()))
```

---

## 🧠 Architecture

AutoRESTify is built exclusively on:

- **Starlette** — HTTP routing and request/response layer
- **aiosqlite** — async SQLite persistence with raw SQL

Core modules:

```
autorestify/
  api/
    router_factory.py   # Starlette Router with all handlers
    app_factory.py      # Starlette app wrapper
  core/
    schema_inference.py # JSON → SQL type mapping
    security.py         # AuthProvider / AccessPolicy ABCs
    rbac.py             # RBACUser, RBACPolicy, TokenAuthProvider
    tenant.py           # TenantResolver, HeaderTenantResolver, SingleTenantResolver
  storage/
    base.py             # async Database (aiosqlite wrapper)
    repository.py       # raw SQL CRUD with tenant scoping
```

---

## 🧪 Running Tests

```bash
pytest -v
```

With coverage:

```bash
pytest --cov=autorestify --cov-report=term-missing
```

Tests use in-memory SQLite for full isolation:

```python
from autorestify import create_app, Database
from starlette.testclient import TestClient

client = TestClient(create_app(database=Database("sqlite:///:memory:")))
```

---

## 🛠 Development Setup

```bash
python -m venv .venv
source .venv/bin/activate
pip install -e ".[server]"
pytest -v
```

---

## 🗺 Roadmap

- ✅ Filtering, pagination, and ordering
- ✅ Async storage engine (aiosqlite)
- ✅ RBAC with Bearer-token authentication
- ✅ Multi-tenant architecture (row-level)
- ✅ Zero-ORM stack (Starlette + aiosqlite only)

---

## 📜 License

MIT License

---

## 👨‍💻 Author

Mikael Aurio Martins — Software Developer
