Metadata-Version: 2.4
Name: function-api-builder
Version: 0.1.2
Summary: Generate complete FastAPI applications from decorated Python business functions.
Author: Sushruth Samson
License-Expression: MIT
Keywords: api-builder,api-generator,backend,code-generation,fastapi,pydantic
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Code Generators
Requires-Python: >=3.11
Requires-Dist: fastapi>=0.115
Requires-Dist: pydantic>=2.7
Requires-Dist: uvicorn>=0.30
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Requires-Dist: twine>=6; extra == 'dev'
Description-Content-Type: text/markdown

<h1 align="center">API Builder</h1>

<p align="center">
  Generate a complete FastAPI application from decorated Python business functions.
</p>

## Status

This project is alpha software. The intended PyPI distribution name is `api-builder`.
PyPI currently rejects that exact name as too similar to an existing project, so the
first published release is temporarily available as `function-api-builder` while the
name issue is resolved.

## Install

Intended install command:

```bash
pip install api-builder
```

Current published fallback:

```bash
pip install function-api-builder
```

Both distributions expose the same Python packages and the same `api-builder` command.

## What It Does

API Builder turns plain, typed business functions into a runnable FastAPI service.
You write the business logic once. The builder discovers those functions, validates
their metadata and Pydantic models, then generates an `app/` directory containing:

- public service routes
- optional local development routes for individual functions
- request validation through Pydantic
- service sequencing
- dependency and request-context containers
- standard error responses
- health checks
- OpenAPI documentation
- generated smoke tests

The generated application is ordinary Python code. After generation, run it with
Uvicorn or edit the generated app as part of your application workflow.

## End-to-End Flow

The complete flow is:

```text
functions/**/*.py
        |
        |  @function metadata + type annotations
        v
  discovery and import
        |
        |  signature, models, steps, routes, dependencies
        v
       validation
        |
        |  generated Python modules and manifest
        v
      app/ directory
        |
        |  FastAPI startup imports generated routers
        v
  HTTP API + OpenAPI
```

### 1. Write a business function

Business functions live under `functions/`. Every function exposed by the builder
uses the same three-argument contract:

```python
def business_function(payload, deps, context) -> OutputModel:
    ...
```

- `payload` is a Pydantic input model.
- `deps` is the generated dependency container.
- `context` contains request metadata and the current service execution context.
- The return annotation is a Pydantic output model.

The function may be synchronous or asynchronous.

### 2. Decorate it with service metadata

```python
from pydantic import BaseModel
from api_builder_runtime import function


class EchoInput(BaseModel):
    message: str


class EchoOutput(BaseModel):
    message: str


@function(service="echo", step=1)
def echo(payload: EchoInput, deps, context) -> EchoOutput:
    return EchoOutput(message=payload.message)
```

The decorator records the metadata needed by the builder:

- `service`: the public service name
- `step`: execution order inside the service
- `description`: optional function description
- `dependencies`: optional named dependencies
- `errors`: optional application error codes and HTTP statuses

The decorator does not execute the function. It marks the function for discovery.

### 3. Run the builder

From the root of the project containing `functions/`:

```bash
api-builder
```

Useful options:

```bash
api-builder --check                 # validate without writing app/
api-builder --force                 # overwrite generated files
api-builder --service echo          # generate one service
api-builder --no-dev-routes         # omit local function routes
api-builder --project-root ./demo   # build another project
```

### 4. Run the generated API

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

The public route for the `echo` service is:

```bash
curl -X POST http://127.0.0.1:8000/api/v1/echo \
  -H 'content-type: application/json' \
  -d '{"message":"hello"}'
```

The response uses the generated standard envelope:

```json
{
  "data": {
    "message": "hello"
  }
}
```

OpenAPI is available at `/docs` and `/openapi.json`. Health status is available at
`/healthz`.

## Multi-Step Services

A service can contain multiple functions. Steps run in ascending order, and the
output of each step becomes the input for the next step.

```python
class ReadInput(BaseModel):
    file_reference: str


class ReadOutput(BaseModel):
    text: str


class SummarizeInput(BaseModel):
    text: str


class SummarizeOutput(BaseModel):
    summary: str


@function(service="document", step=1)
async def read_document(
    payload: ReadInput, deps, context
) -> ReadOutput:
    return ReadOutput(text="Document contents")


@function(service="document", step=2)
async def summarize_document(
    payload: SummarizeInput, deps, context
) -> SummarizeOutput:
    return SummarizeOutput(summary=payload.text)
```

The builder validates that:

- steps are unique
- steps are contiguous, starting at `1`
- required fields needed by the next step are produced by the previous step
- generated route paths and operation IDs are unique

The public route remains one service route:

```text
POST /api/v1/document
```

## Generated Project Layout

Running `api-builder` creates this shape:

```text
app/
├── config.py                 # environment-backed settings
├── context.py                # request execution context
├── dependencies.py           # named dependency container
├── errors.py                 # standard exception mapping
├── health.py                 # GET /healthz
├── main.py                   # FastAPI application factory
├── middleware.py             # request middleware
├── responses.py              # response envelopes
├── routers/
│   ├── public.py             # service routes
│   └── dev.py                # local function routes
├── services/                 # generated service orchestration
├── generated/
│   ├── function_registry.py  # discovered function registry
│   ├── service_registry.py   # service registry
│   ├── manifest.py           # runtime metadata
│   └── manifest.json         # inspectable metadata
└── tests/                    # generated health/OpenAPI tests
```

Generated files contain a header identifying them as generated. Treat the decorated
functions under `functions/` as the source of truth and regenerate after changing
their metadata or type models.

## Development Routes

When the environment is `local`, `development`, or `test`, API Builder exposes one
route per decorated function:

```text
POST /__dev/functions/{service}/{function}
```

These routes require the `X-Internal-Dev-Token` header. They are excluded from the
OpenAPI schema and application entirely in production environments.

Use them to exercise a single step while developing a service. The public service
route remains the normal integration boundary.

## Errors

Business functions can raise `FunctionError`:

```python
from api_builder_runtime import FunctionError


raise FunctionError("EMPTY_DOCUMENT", "The document contains no readable text.")
```

Declare an error status on the decorator when a custom HTTP status is needed:

```python
@function(
    service="document",
    step=2,
    errors={"EMPTY_DOCUMENT": 422},
)
async def summarize_document(payload, deps, context):
    ...
```

The generated error handler returns a stable API error shape and avoids exposing
internal tracebacks or implementation details to clients.

## Validation Rules

Build-time validation fails fast when the project contains an invalid function:

- missing `functions/` directory
- no decorated functions
- wrong function signature
- missing or invalid Pydantic input model
- missing or invalid Pydantic output model
- invalid service or dependency names
- duplicate or missing service steps
- incompatible adjacent step models
- duplicate routes or operation IDs

Use `api-builder --check` in CI to validate source functions without changing the
working tree.

## Example

The repository includes a two-step PDF summary example at:

```text
examples/basic/functions/pdf_summary.py
```

Build it with:

```bash
api-builder --project-root examples/basic --force
```

## Library API

The builder can also be called from Python:

```python
from pathlib import Path
from api_builder import build


result = build(Path("."), force=True)
for route in result.routes:
    print(route.method, route.path)
```

The runtime decorator is intentionally small and has no application-global registry.
Discovery happens when the builder scans the current project.

## Local Development

```bash
python -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
pytest
ruff check src tests examples/basic/functions
mypy src tests
python -m build
python -m twine check dist/*
```

## Scope

API Builder generates application structure and validates the contract between
decorated functions. It does not diagnose infrastructure failures, determine root
cause, repair runtime systems, or create external service clients automatically.
Dependencies are named in function metadata and represented in the generated app;
application owners decide how those dependencies are implemented.

## License

MIT. See the project metadata for the current author and package version.
