Metadata-Version: 2.4
Name: apizit-linking
Version: 0.4.0
Summary: Declarative HTTP binding for plain Python functions without decorators
Author: APIZIT
License-Expression: Apache-2.0
Project-URL: Homepage, https://chipsi44.github.io/apizit-linking-examples/
Project-URL: Documentation, https://chipsi44.github.io/apizit-linking-examples/quickstart/
Project-URL: Examples, https://github.com/chipsi44/apizit-linking-examples
Project-URL: Issues, https://github.com/chipsi44/apizit-linking-examples/issues
Keywords: api,apizit,apizit-linking,declarative,fastapi,http,python,routing,yaml
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyYAML>=6.0.3
Provides-Extra: fastapi
Requires-Dist: fastapi<1,>=0.115.0; extra == "fastapi"
Requires-Dist: python-multipart<1,>=0.0.18; extra == "fastapi"
Provides-Extra: preview
Requires-Dist: fastapi<1,>=0.115.0; extra == "preview"
Requires-Dist: python-multipart<1,>=0.0.18; extra == "preview"
Requires-Dist: uvicorn<1,>=0.30.0; extra == "preview"
Dynamic: license-file

# APIZIT Linking

**Keep the code. Add the API.**

`apizit-linking` is a standalone declarative Python-to-HTTP binding engine. It
turns a versioned configuration file into validated HTTP routes while keeping
customer Python code unchanged. APIZIT is one platform that consumes it, not a
dependency of the package.

[Documentation](https://chipsi44.github.io/apizit-linking-examples/) ·
[Forkable examples](https://github.com/chipsi44/apizit-linking-examples) ·
[Public support and issues](https://github.com/chipsi44/apizit-linking-examples/issues)

```python
def create_customer(customer_name: str, age: int):
    return {"name": customer_name, "age": age}
```

```yaml
version: 1

routes:
  - path: /customers
    method: POST
    function: customer_service:create_customer
    parameters:
      customer_name:
        source:
          location: body
          name: name
      age:
        source:
          location: body
          name: age
```

There are no APIZIT decorators, imports, handlers, or web routes in customer
code.

## Install the public beta

The core validation and runtime engine requires only PyYAML:

```text
pip install "apizit-linking==0.4.0"
```

Install the local FastAPI preview as an optional extra:

```text
pip install "apizit-linking[preview]==0.4.0"
apizit-linking validate .
apizit-linking preview . --port 8080
```

Version 0.4.0 is a public beta. Pin the exact version in projects and deployment
artifacts until the compatibility policy is declared stable. The public
[compatibility policy](https://chipsi44.github.io/apizit-linking-examples/reference/compatibility/)
separates package, Python API, manifest schema, diagnostics, and runtime-artifact
guarantees.

## Validate locally

The command searches the target directory for `apizit_linking.yaml`,
`apizit_linking.yml`, then `apizit_linking.json`:

```text
apizit-linking validate .
apizit-linking validate . --json
apizit-linking validate path/to/apizit_linking.yaml --project-root .
```

Validation is static. It parses the customer module with the Python AST and does
not import or execute customer code.

## Preview locally

```text
apizit-linking preview . --port 8080
```

Preview binds to `127.0.0.1` by default. It validates before importing customer
modules, then executes them in the server process. Binding to a non-loopback
interface requires `--allow-network`.

The preview server is a development tool, not an authentication layer, a
production deployment boundary, or a sandbox. Linked customer modules are
ordinary trusted Python code and may execute arbitrary code when imported or
called.

## Forkable example projects

The independent public
[APIZIT Linking examples repository](https://github.com/chipsi44/apizit-linking-examples)
contains a runnable Hello World starter and five additional projects covering
path/query parameters, JSON bodies, errors, packages, and a CRUD-style Task
API. It is the single source of truth for user-facing examples.

```text
git clone https://github.com/chipsi44/apizit-linking-examples.git
cd apizit-linking-examples
python -m pip install -r requirements.txt
apizit-linking validate .
apizit-linking preview . --port 8080
```

Every business module in that repository imports neither APIZIT Linking nor a
web framework. Fork it as a starter or pin one of its commits as an APIZIT
integration fixture.

## V1 configuration reference

The root document is a closed, versioned object:

```yaml
version: 1
runtime:
  language: python
  version: "3.12"
routes:
  - path: /customers/{customer_id}
    method: PATCH
    function: customer_service:update_customer
```

Editor completion and structural validation use the
[canonical JSON Schema](https://chipsi44.github.io/apizit-linking-examples/schema/apizit-linking-v1.schema.json).

`function` uses the canonical dotted `module:function` form. `path` must be an
absolute HTTP path and route placeholders use `{parameter_name}`. Canonical
methods are uppercase and must be one of `GET`, `POST`, `PUT`, `PATCH`,
`DELETE`, `OPTIONS`, or `HEAD`; the compiler normalizes case-insensitive
migration input.

The compiler verifies module and function existence, top-level callability,
supported signatures, parameter bindings, request-source compatibility, and
route collisions. A static sibling such as `/customers/search` is registered
before `/customers/{customer_id}` regardless of declaration order. Cross-shaped
patterns that overlap without a safe specificity order are rejected as
`ROUTE_AMBIGUITY`.

### Explicit parameter sources

The canonical source syntax is a structured object:

```yaml
parameters:
  customer_name:
    source:
      location: body
      name: name
```

This binds HTTP body field `name` to Python parameter `customer_name`. When a
source is explicit, only that source is inspected. There is no fallback to
another source.

V1 supports:

- `path`
- `query`
- `header`
- `body`
- `form`
- `file`

Header names are case-insensitive; other external names are exact. A route
cannot require both a JSON `body` value and a `form` or `file` value because
those request encodings are incompatible.

### Automatic parameter resolution

If a parameter has no explicit source, V1 searches its Python name in this
stable order:

```text
path > query > header > body > form > file
```

The first present source wins. A required absent parameter produces
`PARAMETER_NOT_FOUND`; explicit mode produces
`PARAMETER_NOT_FOUND_IN_SOURCE`. Parameters with Python defaults are omitted
from the generated keyword arguments so Python applies their defaults.

Missing values, JSON `null`, and empty strings are distinct. `null` is accepted
only by a nullable annotation. V1 converts primitive `str`, `int`, `float`,
`bool`, nullable unions, lists, and dictionaries. If one annotation contains an
unknown forward reference, other resolvable annotations are still converted.

### Stable error shape

Request errors use a JSON object:

```json
{
  "error": {
    "code": "PARAMETER_NOT_FOUND_IN_SOURCE",
    "message": "Required field 'name' was not found in request source 'body'.",
    "parameter": "customer_name",
    "external_name": "name",
    "source": "body"
  }
}
```

Configuration diagnostics include a stable code, severity, field, route index,
parameter, and relevant source metadata. The beta does not yet guarantee that
new minor releases will never add diagnostic codes or metadata fields.

## Python API

Platform adapters compile with `compile_linking_file`, serialize the complete
validated `CompilationResult` with `to_runtime_dict()`, then consume that
closed, versioned artifact through
`create_app_from_runtime_artifact`. Compilation is the static boundary;
customer imports happen only through the runtime loader, which verifies that
the packaged function signatures, sync/async callable kind, and return
annotation still match the compiled contract.

The optional ASGI adapter is available without changing customer code:

```python
from apizit_linking.fastapi import create_app

app = create_app(".")
```

Platforms may wrap that app with their own server, authentication, metering, or
deployment layer. FastAPI documentation routes are disabled by default because
V1 does not yet generate a complete request/response OpenAPI contract; pass
`docs=True` only when that limitation is acceptable.

## Package scope

The package owns discovery, YAML/YML/JSON parsing, closed V1 validation, safe
static `module:function` resolution, AST signature inspection, compilation,
structured diagnostics, request-context resolution, primitive conversion,
sync/async invocation, and the optional FastAPI preview.

It intentionally does not own Mangum, API Gateway, Lambda, deployment, metering,
or APIZIT scan UI/reporting. The core installation remains independent of
FastAPI.

## Development

Maintainers working from an authorized source checkout can run:

```text
uv sync --all-extras --all-groups
uv run python -m unittest discover -s tests -p "test_*.py"
uv run ruff check src tests
uv run black --check src tests
uv build
```

The complete V1 reference, release procedure, remaining work, and test support
are included in the source distribution. The public example gallery is
maintained separately. APIZIT Linking is licensed under Apache-2.0.
