Skip to main content

API Builder

Generate a complete FastAPI application from decorated Python business functions.

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:

pip install api-builder

Current published fallback:

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:

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:

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

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

api-builder

Useful options:

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

uvicorn app.main:app --reload

The public route for the echo service is:

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:

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

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:

POST /api/v1/document

Generated Project Layout

Running api-builder creates this shape:

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:

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:

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:

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

examples/basic/functions/pdf_summary.py

Build it with:

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

Library API

The builder can also be called from 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

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.

Metadata

Release files for function-api-builder 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for function-api-builder 0.1.2
File Size Uploaded Provenance
function_api_builder-0.1.2.tar.gz 13.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for function-api-builder 0.1.2
File Interpreter ABI Platform
function_api_builder-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 26.4 kB

Release files / function_api_builder-0.1.2.tar.gz

Download URL function_api_builder-0.1.2.tar.gz
Size 13.4 kB
Tags Source
SHA-256 checksum
How to use checksums
afd6292a6b16110edc01d400e5b177b19fe0b40fcdbbd0092c7283e122ae7e3e
BLAKE2b-256 checksum
How to use checksums
882f4ba1eb9a4ab68386448efe4f0c44d94d4da72f0c70a0f2cda4be79f60507
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / function_api_builder-0.1.2-py3-none-any.whl

Download URL function_api_builder-0.1.2-py3-none-any.whl
Size 13.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7026171b9acaef6a9a87164bc624f9273eb55ae84846c3e7eac8709f8be83f9a
BLAKE2b-256 checksum
How to use checksums
c22fe209568ce4c5339a8830f66a4dcb07f20648dc2c23a3cb31277856b260ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Security for function-api-builder 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page