Skip to main content

Dynamic API generator from JSON models with automatic schema inference.

Project description

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

pip install autorestify

With uvicorn included:

pip install autorestify[server]

Local development:

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

⚡ Quick Start

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)
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:

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
GET /clientes?age=30&order_by=name&order=asc&page=1&page_size=10

Response envelope:

{
  "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
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.

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:

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

pytest -v

With coverage:

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

Tests use in-memory SQLite for full isolation:

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

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

🛠 Development Setup

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

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

autorestify-2.0.0.tar.gz (19.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

autorestify-2.0.0-py3-none-any.whl (16.7 kB view details)

Uploaded Python 3

File details

Details for the file autorestify-2.0.0.tar.gz.

File metadata

  • Download URL: autorestify-2.0.0.tar.gz
  • Upload date:
  • Size: 19.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.2

File hashes

Hashes for autorestify-2.0.0.tar.gz
Algorithm Hash digest
SHA256 c13cad20c044ec020c5fb5c3f1bc5c0e0780c7e7783a5850b06ee2ecf9f26467
MD5 ab374ba8e96ba9c9aebe853d661f5366
BLAKE2b-256 9853e32aaa7deee8f8f5862e7566d4e908a450325da578fa99d2be3920c66780

See more details on using hashes here.

File details

Details for the file autorestify-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: autorestify-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 16.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.2

File hashes

Hashes for autorestify-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a2228908659f7a086516a2541393bdbe350a7ef0720fe2af8a94af9f58b162f1
MD5 bd509ca7ec13af6ebad6364980663f2e
BLAKE2b-256 289ee841dbaddd21936972ec1bd53ce54a1515e91326f0c3ce324b73a7b07992

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page