superfastapi


Namesuperfastapi JSON
Version 0.1.3 PyPI version JSON
download
home_pageNone
SummaryBuild versioned APIs from single-block functions with inline tests, locks, and FastAPI serving.
upload_time2025-09-06 16:30:42
maintainerNone
docs_urlNone
authorChase Anderson
requires_python>=3.10
licenseMIT
keywords fastapi api versioning pydantic serverless superfast
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            SuperFastAPI

SuperFastAPI lets you define versioned API functions with a single, self‑contained code block: code, metadata, and inline tests live together in one decorated function. Mark functions as `external` to expose them as HTTP endpoints automatically. Generate lock files per API version to freeze exact function versions by hash, ensuring immutability across versions. Serve instantly with FastAPI, complete with routing, docs, auth, and robust error handling.

Key ideas
- Functions only: no classes required.
- Inline metadata: version, external/internal, description, path, methods, auth, roles, tests.
- Per-version lock files: one file per API version under `.superfastapi/locks/` pins each function to a specific version and code hash. No metadata in the lock.
- Dynamic dependency resolution: functions call each other by name; the correct version is chosen based on the requested API version.
- Inline tests: run automatically during `apikit lock` to ensure behavior before freezing a version.
- Error handling: clean JSON errors for versioning, auth, resolution, validation, and internal failures.

Quickstart
1) Install: `pip install superfastapi`
2) Define functions anywhere in your project:

```python
from superfastapi import api_function

@api_function(version=1, external=True, description="Sum two numbers", methods=["POST"],
              tests=[{"args": (1, 2), "kwargs": {}, "expected": 3}])
def add(a: int, b: int) -> int:
    return a + b

@api_function(version=1, external=True, description="Do math", methods=["POST"])
def domath(x: int, y: int) -> int:
    # Will call the correct version of add() for the requested API version
    return add(x, y)
```

3) Create a lock for v1: `apikit lock v1`
4) Serve: `apikit serve` then hit `/v1/add` or `/v1/domath`.

Versioning example
- To change `add` behavior for v2: copy the whole decorated block, set `version=2` and adjust code. Run `apikit lock v2`. `/v2/domath` still uses `domath` v1 but now resolves `add` v2 automatically.

Auth
- Use decorator flags: `requires_auth=True, roles=["user"]`. Tokens are validated via JWT (HS256), secret from env `SUPERFASTAPI_SECRET`.

HTTP Methods and Paths
- Default path is `/v{X}/{function_name}` for external functions.
- Override using `path="/custom/path"` (route becomes `/v{X}/custom/path`).
- Configure methods via `methods=["GET"]` or `methods=["POST", "GET"]`.

Lock files per API version (no metadata inside)
- Each API version has its own lock file under `.superfastapi/locks/` at your project root, e.g. `.superfastapi/locks/v1.lock.json`.
- Contents only include function versions and hashes:

```json
{
  "functions": {
    "add": {"version": 1, "hash": "..."},
    "domath": {"version": 1, "hash": "..."}
  }
}
```

CLI
- `apikit lock [vX] [--root .] [--lock-dir PATH]` — Verify immutability, run inline tests, and write `.superfastapi/locks/vX.lock.json`.
- `apikit serve [--root .] [--lock-dir PATH] [--host 0.0.0.0 --port 8000]` — Serve only API versions that have a lock file present.
- `apikit versions` — List versions that have lock files.
- `apikit list [vX] [--verify]` — Show functions pinned in a lock; `--verify` checks code hashes.
- `apikit prune [vX|--all] [--dry-run|--no-dry-run] [--force]` — Remove lock files for versions that fail verification.
- `apikit bump <function> [--to vX] [--dry-run]` — Clone a function block and bump its version.
- `apikit diff v1 v2 [--json]` — Show function and route changes between two versions.
- `apikit changelog v1 v2` — Human-readable summary of changes.
- `apikit preview vX` — Dev-only server for vX selection (no lock written).
- `apikit client ts vX --out client.ts` / `apikit client py vX --out client.py` — Generate tiny clients.

Notes
- Hashing uses the full decorated source (including the decorator line). Moving files is fine; editing old versions is blocked.
- Inline tests are simple dicts: `{"args": (...), "kwargs": {...}, "expected": value}`. Optional keys: `timeout`, `approx`, `rel_tol`, `abs_tol`. Set `SUPERFASTAPI_TEST_VERBOSE=1` for timing.
- Selection rule: for API version vX, each function is pinned to the highest version ≤ X.

Auth (simple)
- Modes via `SUPERFASTAPI_AUTH_MODE=jwt|apikey|none`.
  - JWT (default): HS256, secret `SUPERFASTAPI_SECRET`; roles enforced from decorator.
  - API key: `SUPERFASTAPI_API_KEY_HEADER` (default `X-API-Key`) + `SUPERFASTAPI_API_KEY`.

Validation & docs
- Pydantic validates inputs/outputs from function annotations. GET reads query params; POST/PUT/PATCH reads JSON.
- OpenAPI request examples are generated automatically from passing inline tests.

Quality-of-life envs
- `SUPERFASTAPI_CORS=open` (default) enables dev-friendly CORS.
- `SUPERFASTAPI_GZIP=1` enables gzip.
- `SUPERFASTAPI_RATE_LIMIT=60/min` (or `5/sec`, `100/3600`) enables simple in-memory rate limiting.
- `SUPERFASTAPI_INCLUDE` / `SUPERFASTAPI_EXCLUDE` (comma-separated globs) control which files are scanned.

**Decorator Reference**
- `@api_function(`
  - `version: int = 1`
  - `external: bool = False` — expose as an HTTP endpoint when True
  - `description: str = ""` — used in docs
  - `path: str | None = None` — route path segment (default `/{function_name}`)
  - `methods: list[str] = ["POST"]` — e.g., `["GET"]`, `["POST", "GET"]`
  - `requires_auth: bool = False` — enforce auth per global mode (JWT/API key)
  - `roles: list[str] = []` — JWT roles claim must overlap
  - `tests: list[dict] = []` — inline tests executed on `apikit lock`
`)`
- Inline tests keys:
  - `args`: tuple of positional args
  - `kwargs`: dict of keyword args
  - `expected`: expected return value
  - Optional: `timeout` (seconds), `approx: true`, `rel_tol`, `abs_tol`
- Request/response typing:
  - Pydantic infers input schema from function signature. `GET` uses query params; `POST/PUT/PATCH` expects JSON body matching the arguments.
  - The return annotation (if present) is used as the `response_model` for docs/validation.
- Async functions are supported. Regular functions run in a thread executor.

Example tests
```python
@api_function(
    version=1,
    external=True,
    methods=["POST"],
    tests=[
        {"args": (1, 2), "kwargs": {}, "expected": 3},
        {"args": (0.1, 0.2), "kwargs": {}, "expected": 0.3, "approx": True, "rel_tol": 1e-6},
        {"args": (1, 2), "expected": 3, "timeout": 0.05},
    ],
)
def add(a: float, b: float) -> float:
    return a + b
```

**CI Recipe**
- Goal: ensure all existing locks are valid (old versions unchanged) and all inline tests pass on every PR.
- GitHub Actions example:

```yaml
name: superfastapi-verify

on: [push, pull_request]

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - name: Install SuperFastAPI
        run: |
          python -m pip install --upgrade pip
          pip install superfastapi  # pin your version as needed
      - name: Verify locks and inline tests
        env:
          SUPERFASTAPI_TEST_VERBOSE: '1'
        shell: bash
        run: |
          set -euo pipefail
          if [ ! -d .superfastapi/locks ]; then
            echo "No locks directory; nothing to verify"; exit 0
          fi
          ok=0
          for v in $(apikit versions); do
            echo "Verifying $v"
            out=$(apikit list "$v" --verify)
            echo "$out"
            echo "$out" | grep -q 'ok=True' || ok=1
          done
          if [ "$ok" -ne 0 ]; then
            echo "Lock verification failed" >&2
            exit 1
          fi
```

- Optional: release workflow step to create a new lock (manual or on tag):

```yaml
  create-lock:
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: pip install superfastapi
      - name: Write vNEXT lock (example)
        run: |
          apikit lock v2
          git config user.name "ci"; git config user.email "ci@example"
          git add .superfastapi/locks/v2.lock.json
          git commit -m "Add lock v2" || echo "No changes"
          git push || true
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "superfastapi",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "fastapi, api, versioning, pydantic, serverless, superfast",
    "author": "Chase Anderson",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/4b/27/73c886e961eb85694e5d6fe89086bfa770c729c0fea8124f0858ae5a279e/superfastapi-0.1.3.tar.gz",
    "platform": null,
    "description": "SuperFastAPI\n\nSuperFastAPI lets you define versioned API functions with a single, self\u2011contained code block: code, metadata, and inline tests live together in one decorated function. Mark functions as `external` to expose them as HTTP endpoints automatically. Generate lock files per API version to freeze exact function versions by hash, ensuring immutability across versions. Serve instantly with FastAPI, complete with routing, docs, auth, and robust error handling.\n\nKey ideas\n- Functions only: no classes required.\n- Inline metadata: version, external/internal, description, path, methods, auth, roles, tests.\n- Per-version lock files: one file per API version under `.superfastapi/locks/` pins each function to a specific version and code hash. No metadata in the lock.\n- Dynamic dependency resolution: functions call each other by name; the correct version is chosen based on the requested API version.\n- Inline tests: run automatically during `apikit lock` to ensure behavior before freezing a version.\n- Error handling: clean JSON errors for versioning, auth, resolution, validation, and internal failures.\n\nQuickstart\n1) Install: `pip install superfastapi`\n2) Define functions anywhere in your project:\n\n```python\nfrom superfastapi import api_function\n\n@api_function(version=1, external=True, description=\"Sum two numbers\", methods=[\"POST\"],\n              tests=[{\"args\": (1, 2), \"kwargs\": {}, \"expected\": 3}])\ndef add(a: int, b: int) -> int:\n    return a + b\n\n@api_function(version=1, external=True, description=\"Do math\", methods=[\"POST\"])\ndef domath(x: int, y: int) -> int:\n    # Will call the correct version of add() for the requested API version\n    return add(x, y)\n```\n\n3) Create a lock for v1: `apikit lock v1`\n4) Serve: `apikit serve` then hit `/v1/add` or `/v1/domath`.\n\nVersioning example\n- To change `add` behavior for v2: copy the whole decorated block, set `version=2` and adjust code. Run `apikit lock v2`. `/v2/domath` still uses `domath` v1 but now resolves `add` v2 automatically.\n\nAuth\n- Use decorator flags: `requires_auth=True, roles=[\"user\"]`. Tokens are validated via JWT (HS256), secret from env `SUPERFASTAPI_SECRET`.\n\nHTTP Methods and Paths\n- Default path is `/v{X}/{function_name}` for external functions.\n- Override using `path=\"/custom/path\"` (route becomes `/v{X}/custom/path`).\n- Configure methods via `methods=[\"GET\"]` or `methods=[\"POST\", \"GET\"]`.\n\nLock files per API version (no metadata inside)\n- Each API version has its own lock file under `.superfastapi/locks/` at your project root, e.g. `.superfastapi/locks/v1.lock.json`.\n- Contents only include function versions and hashes:\n\n```json\n{\n  \"functions\": {\n    \"add\": {\"version\": 1, \"hash\": \"...\"},\n    \"domath\": {\"version\": 1, \"hash\": \"...\"}\n  }\n}\n```\n\nCLI\n- `apikit lock [vX] [--root .] [--lock-dir PATH]` \u2014 Verify immutability, run inline tests, and write `.superfastapi/locks/vX.lock.json`.\n- `apikit serve [--root .] [--lock-dir PATH] [--host 0.0.0.0 --port 8000]` \u2014 Serve only API versions that have a lock file present.\n- `apikit versions` \u2014 List versions that have lock files.\n- `apikit list [vX] [--verify]` \u2014 Show functions pinned in a lock; `--verify` checks code hashes.\n- `apikit prune [vX|--all] [--dry-run|--no-dry-run] [--force]` \u2014 Remove lock files for versions that fail verification.\n- `apikit bump <function> [--to vX] [--dry-run]` \u2014 Clone a function block and bump its version.\n- `apikit diff v1 v2 [--json]` \u2014 Show function and route changes between two versions.\n- `apikit changelog v1 v2` \u2014 Human-readable summary of changes.\n- `apikit preview vX` \u2014 Dev-only server for vX selection (no lock written).\n- `apikit client ts vX --out client.ts` / `apikit client py vX --out client.py` \u2014 Generate tiny clients.\n\nNotes\n- Hashing uses the full decorated source (including the decorator line). Moving files is fine; editing old versions is blocked.\n- Inline tests are simple dicts: `{\"args\": (...), \"kwargs\": {...}, \"expected\": value}`. Optional keys: `timeout`, `approx`, `rel_tol`, `abs_tol`. Set `SUPERFASTAPI_TEST_VERBOSE=1` for timing.\n- Selection rule: for API version vX, each function is pinned to the highest version \u2264 X.\n\nAuth (simple)\n- Modes via `SUPERFASTAPI_AUTH_MODE=jwt|apikey|none`.\n  - JWT (default): HS256, secret `SUPERFASTAPI_SECRET`; roles enforced from decorator.\n  - API key: `SUPERFASTAPI_API_KEY_HEADER` (default `X-API-Key`) + `SUPERFASTAPI_API_KEY`.\n\nValidation & docs\n- Pydantic validates inputs/outputs from function annotations. GET reads query params; POST/PUT/PATCH reads JSON.\n- OpenAPI request examples are generated automatically from passing inline tests.\n\nQuality-of-life envs\n- `SUPERFASTAPI_CORS=open` (default) enables dev-friendly CORS.\n- `SUPERFASTAPI_GZIP=1` enables gzip.\n- `SUPERFASTAPI_RATE_LIMIT=60/min` (or `5/sec`, `100/3600`) enables simple in-memory rate limiting.\n- `SUPERFASTAPI_INCLUDE` / `SUPERFASTAPI_EXCLUDE` (comma-separated globs) control which files are scanned.\n\n**Decorator Reference**\n- `@api_function(`\n  - `version: int = 1`\n  - `external: bool = False` \u2014 expose as an HTTP endpoint when True\n  - `description: str = \"\"` \u2014 used in docs\n  - `path: str | None = None` \u2014 route path segment (default `/{function_name}`)\n  - `methods: list[str] = [\"POST\"]` \u2014 e.g., `[\"GET\"]`, `[\"POST\", \"GET\"]`\n  - `requires_auth: bool = False` \u2014 enforce auth per global mode (JWT/API key)\n  - `roles: list[str] = []` \u2014 JWT roles claim must overlap\n  - `tests: list[dict] = []` \u2014 inline tests executed on `apikit lock`\n`)`\n- Inline tests keys:\n  - `args`: tuple of positional args\n  - `kwargs`: dict of keyword args\n  - `expected`: expected return value\n  - Optional: `timeout` (seconds), `approx: true`, `rel_tol`, `abs_tol`\n- Request/response typing:\n  - Pydantic infers input schema from function signature. `GET` uses query params; `POST/PUT/PATCH` expects JSON body matching the arguments.\n  - The return annotation (if present) is used as the `response_model` for docs/validation.\n- Async functions are supported. Regular functions run in a thread executor.\n\nExample tests\n```python\n@api_function(\n    version=1,\n    external=True,\n    methods=[\"POST\"],\n    tests=[\n        {\"args\": (1, 2), \"kwargs\": {}, \"expected\": 3},\n        {\"args\": (0.1, 0.2), \"kwargs\": {}, \"expected\": 0.3, \"approx\": True, \"rel_tol\": 1e-6},\n        {\"args\": (1, 2), \"expected\": 3, \"timeout\": 0.05},\n    ],\n)\ndef add(a: float, b: float) -> float:\n    return a + b\n```\n\n**CI Recipe**\n- Goal: ensure all existing locks are valid (old versions unchanged) and all inline tests pass on every PR.\n- GitHub Actions example:\n\n```yaml\nname: superfastapi-verify\n\non: [push, pull_request]\n\njobs:\n  verify:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n        with:\n          python-version: '3.11'\n      - name: Install SuperFastAPI\n        run: |\n          python -m pip install --upgrade pip\n          pip install superfastapi  # pin your version as needed\n      - name: Verify locks and inline tests\n        env:\n          SUPERFASTAPI_TEST_VERBOSE: '1'\n        shell: bash\n        run: |\n          set -euo pipefail\n          if [ ! -d .superfastapi/locks ]; then\n            echo \"No locks directory; nothing to verify\"; exit 0\n          fi\n          ok=0\n          for v in $(apikit versions); do\n            echo \"Verifying $v\"\n            out=$(apikit list \"$v\" --verify)\n            echo \"$out\"\n            echo \"$out\" | grep -q 'ok=True' || ok=1\n          done\n          if [ \"$ok\" -ne 0 ]; then\n            echo \"Lock verification failed\" >&2\n            exit 1\n          fi\n```\n\n- Optional: release workflow step to create a new lock (manual or on tag):\n\n```yaml\n  create-lock:\n    runs-on: ubuntu-latest\n    if: startsWith(github.ref, 'refs/tags/v')\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n        with:\n          python-version: '3.11'\n      - run: pip install superfastapi\n      - name: Write vNEXT lock (example)\n        run: |\n          apikit lock v2\n          git config user.name \"ci\"; git config user.email \"ci@example\"\n          git add .superfastapi/locks/v2.lock.json\n          git commit -m \"Add lock v2\" || echo \"No changes\"\n          git push || true\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Build versioned APIs from single-block functions with inline tests, locks, and FastAPI serving.",
    "version": "0.1.3",
    "project_urls": {
        "Homepage": "https://pypi.org/project/superfastapi/"
    },
    "split_keywords": [
        "fastapi",
        " api",
        " versioning",
        " pydantic",
        " serverless",
        " superfast"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "ad5f83f18b2ce02b90c5cb1774faf5abd1c8cdd181c82ae8b362f6ad345ecc5a",
                "md5": "aa78a8e905a4ec6cd4c050650276dc68",
                "sha256": "b2840a7fb50f23e60d6d197e48401dc4296a97d016a55b539dce1207ff4c1921"
            },
            "downloads": -1,
            "filename": "superfastapi-0.1.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "aa78a8e905a4ec6cd4c050650276dc68",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 22832,
            "upload_time": "2025-09-06T16:30:40",
            "upload_time_iso_8601": "2025-09-06T16:30:40.820337Z",
            "url": "https://files.pythonhosted.org/packages/ad/5f/83f18b2ce02b90c5cb1774faf5abd1c8cdd181c82ae8b362f6ad345ecc5a/superfastapi-0.1.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "4b2773c886e961eb85694e5d6fe89086bfa770c729c0fea8124f0858ae5a279e",
                "md5": "527aec4ebd9a8286b90feae2ba405044",
                "sha256": "43f10841aad3d03bf8d65609d686186ef9ec7191e1e2d8699be503834c1b02de"
            },
            "downloads": -1,
            "filename": "superfastapi-0.1.3.tar.gz",
            "has_sig": false,
            "md5_digest": "527aec4ebd9a8286b90feae2ba405044",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 23081,
            "upload_time": "2025-09-06T16:30:42",
            "upload_time_iso_8601": "2025-09-06T16:30:42.382883Z",
            "url": "https://files.pythonhosted.org/packages/4b/27/73c886e961eb85694e5d6fe89086bfa770c729c0fea8124f0858ae5a279e/superfastapi-0.1.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-06 16:30:42",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "superfastapi"
}
        
Elapsed time: 0.56502s