Turn a Python library into an API with YAML
If a library already exposes top-level functions with supported signatures, APIZIT Linking can connect them to HTTP routes by dotted module name. The package remains ordinary Python; YAML owns the method, path, and request-field mapping.
When a library is a good fit#
The simplest target is a top-level function that accepts ordinary keyword arguments and returns JSON-serializable data. The function can live in a dotted package, call sibling modules, and perform imports lazily during invocation.
This guide exposes a small catalogue package:
catalog-api/
├── apizit_linking.yaml
└── catalog/
├── __init__.py
├── pricing.py
└── service.pyNo module imports FastAPI, Starlette, or APIZIT Linking. The same package remains importable by Python tools that never start an HTTP server.
1. Create the Python package#
Add an empty catalog/__init__.py, then create catalog/pricing.py:
def base_price_for(product_id: int) -> float:
return round(10.0 + product_id * 1.5, 2)
def apply_discount(price: float, discount: float) -> float:
if not 0 <= discount <= 100:
raise ValueError("discount must be between 0 and 100")
return round(price * (1 - discount / 100), 2)Create catalog/service.py:
def quote(product_id: int, discount: float = 0.0) -> dict[str, float | int]:
from .pricing import apply_discount, base_price_for
base_price = base_price_for(product_id)
return {
"product_id": product_id,
"base_price": base_price,
"discount": discount,
"final_price": apply_discount(base_price, discount),
}The relative import occurs inside quote. APIZIT Linking keeps a project-private import namespace available during invocation, so this normal lazy package import resolves without placing the project root permanently on sys.path.
Before adding HTTP, check the library directly:
python -c "from catalog.service import quote; assert quote(7, 10)['final_price'] == 18.45"2. Declare the HTTP route in YAML#
Create apizit_linking.yaml at the project root. The function target uses canonical module:function syntax:
version: 1
runtime:
language: python
version: "3.12"
routes:
- path: /products/{product_id}/quote
method: GET
function: catalog.service:quote
parameters:
product_id:
source:
location: path
name: product_id
discount:
source:
location: query
name: discountThe path value is converted to int, and the query value is converted to float using the function annotations. Because discount defaults to 0.0, the query field can be omitted.
runtime.version validates the declared Python minor-version syntax; the local preview does not install or switch Python interpreters for you.
3. Validate and call the API#
Install the preview extra and run the static compiler:
python -m pip install "apizit-linking[preview,models]==1.0.1"
apizit-linking validate .Validation resolves catalog/service.py inside the project root and checks the top-level quote signature using the Python AST. It does not execute catalog.
Start the local server:
apizit-linking preview . --port 8080Request a ten-percent discount for product 7:
curl "http://127.0.0.1:8080/products/7/quote?discount=10"Expected response (200 OK):
{
"product_id": 7,
"base_price": 20.5,
"discount": 10.0,
"final_price": 18.45
}The complete public gallery includes this same pattern as a runnable multi-module example.
Library compatibility checklist#
A V1 target must satisfy these constraints:
- The target uses canonical
module:functionsyntax and resolves to a file or package inside the project root. - The linked function is defined at module scope and is callable at runtime.
- Parameters may be positional-or-keyword or keyword-only. Positional-only,
*args, and**kwargssignatures are rejected. - Request conversion is built in for strings, integers, finite floats, booleans, nullable unions, lists, and dictionaries.
- The optional HTTP adapter must be able to serialize the returned value. Ordinary dictionaries, lists, strings, numbers, booleans, and
Noneare the clearest portable choices. - Third-party dependencies used by the library must already be installed in the runtime environment. Linking does not install a project’s dependencies.
If an existing function has an incompatible signature or returns a domain-specific object, add a thin plain Python adapter function in your own package. That adapter can translate values without importing a web framework or modifying the underlying library.
V1 limits and the production boundary#
The example keeps legacy binding and a plain Python function. Its default successful response is 200; request conversion failures use 400 and unmapped domain exceptions use a generic JSON 500. The 1.0 release adds explicit response/errors policies, optional nested models, injected resources and guards. Add those policies deliberately and test their behavior. Preview imports trusted code and provides no production sandbox.
The persistent API exercises models, transactions and permissions. Current limits distinguish the supported contract from streaming, identity-provider and storage responsibilities.
Continue learning#
- YAML reference for route and parameter-source rules.
- CLI reference for validation and preview options.
- Example gallery for JSON body, errors, CRUD, and multi-module projects.
- Install APIZIT Linking from PyPI.
- Fork the public examples repository.
Use this boundary with an AI assistant#
Ask your assistant to work on the Python behavior first: inputs, return value and domain cases. Review or run those function tests before adding an HTTP route. Then provide the function signature and the intended method, path and parameter sources as a separate task. This keeps the business decision and the HTTP mapping explicit for both the assistant and the reviewer.
Validate the proposed manifest with JSON diagnostics, inspect the affected module:function targets and preview the request cases. Static validation checks supported contracts; it does not prove business correctness or execute the function. Preview imports the project and must only run code you trust. The architecture makes these boundaries inspectable, but lower token usage, faster work and fewer mistakes would need measurement for your own workflow.
Follow the AI-assisted development guide for the complete sequence. For debugging, trace a route back to Python. Compare Flask and FastAPI when you need a different HTTP contract.