function-api-builder 0.1.0__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- function_api_builder-0.1.2/PKG-INFO +387 -0
- function_api_builder-0.1.2/README.md +356 -0
- function_api_builder-0.1.2/assets/api-builder.svg +9 -0
- {function_api_builder-0.1.0 → function_api_builder-0.1.2}/pyproject.toml +2 -2
- function_api_builder-0.1.0/PKG-INFO +0 -72
- function_api_builder-0.1.0/README.md +0 -41
- {function_api_builder-0.1.0 → function_api_builder-0.1.2}/examples/basic/functions/__init__.py +0 -0
- {function_api_builder-0.1.0 → function_api_builder-0.1.2}/examples/basic/functions/pdf_summary.py +0 -0
- {function_api_builder-0.1.0 → function_api_builder-0.1.2}/src/api_builder/__init__.py +0 -0
- {function_api_builder-0.1.0 → function_api_builder-0.1.2}/src/api_builder/__main__.py +0 -0
- {function_api_builder-0.1.0 → function_api_builder-0.1.2}/src/api_builder/cli.py +0 -0
- {function_api_builder-0.1.0 → function_api_builder-0.1.2}/src/api_builder/generator.py +0 -0
- {function_api_builder-0.1.0 → function_api_builder-0.1.2}/src/api_builder_runtime/__init__.py +0 -0
- {function_api_builder-0.1.0 → function_api_builder-0.1.2}/tests/test_builder.py +0 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: function-api-builder
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Generate complete FastAPI applications from decorated Python business functions.
|
|
5
|
+
Author: Sushruth Samson
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: api-builder,api-generator,backend,code-generation,fastapi,pydantic
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Framework :: FastAPI
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: fastapi>=0.115
|
|
21
|
+
Requires-Dist: pydantic>=2.7
|
|
22
|
+
Requires-Dist: uvicorn>=0.30
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
25
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
26
|
+
Requires-Dist: mypy>=1.13; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
28
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
29
|
+
Requires-Dist: twine>=6; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
<h1 align="center">API Builder</h1>
|
|
33
|
+
|
|
34
|
+
<p align="center">
|
|
35
|
+
Generate a complete FastAPI application from decorated Python business functions.
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
## Status
|
|
39
|
+
|
|
40
|
+
This project is alpha software. The intended PyPI distribution name is `api-builder`.
|
|
41
|
+
PyPI currently rejects that exact name as too similar to an existing project, so the
|
|
42
|
+
first published release is temporarily available as `function-api-builder` while the
|
|
43
|
+
name issue is resolved.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
Intended install command:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install api-builder
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Current published fallback:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install function-api-builder
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Both distributions expose the same Python packages and the same `api-builder` command.
|
|
60
|
+
|
|
61
|
+
## What It Does
|
|
62
|
+
|
|
63
|
+
API Builder turns plain, typed business functions into a runnable FastAPI service.
|
|
64
|
+
You write the business logic once. The builder discovers those functions, validates
|
|
65
|
+
their metadata and Pydantic models, then generates an `app/` directory containing:
|
|
66
|
+
|
|
67
|
+
- public service routes
|
|
68
|
+
- optional local development routes for individual functions
|
|
69
|
+
- request validation through Pydantic
|
|
70
|
+
- service sequencing
|
|
71
|
+
- dependency and request-context containers
|
|
72
|
+
- standard error responses
|
|
73
|
+
- health checks
|
|
74
|
+
- OpenAPI documentation
|
|
75
|
+
- generated smoke tests
|
|
76
|
+
|
|
77
|
+
The generated application is ordinary Python code. After generation, run it with
|
|
78
|
+
Uvicorn or edit the generated app as part of your application workflow.
|
|
79
|
+
|
|
80
|
+
## End-to-End Flow
|
|
81
|
+
|
|
82
|
+
The complete flow is:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
functions/**/*.py
|
|
86
|
+
|
|
|
87
|
+
| @function metadata + type annotations
|
|
88
|
+
v
|
|
89
|
+
discovery and import
|
|
90
|
+
|
|
|
91
|
+
| signature, models, steps, routes, dependencies
|
|
92
|
+
v
|
|
93
|
+
validation
|
|
94
|
+
|
|
|
95
|
+
| generated Python modules and manifest
|
|
96
|
+
v
|
|
97
|
+
app/ directory
|
|
98
|
+
|
|
|
99
|
+
| FastAPI startup imports generated routers
|
|
100
|
+
v
|
|
101
|
+
HTTP API + OpenAPI
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 1. Write a business function
|
|
105
|
+
|
|
106
|
+
Business functions live under `functions/`. Every function exposed by the builder
|
|
107
|
+
uses the same three-argument contract:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
def business_function(payload, deps, context) -> OutputModel:
|
|
111
|
+
...
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- `payload` is a Pydantic input model.
|
|
115
|
+
- `deps` is the generated dependency container.
|
|
116
|
+
- `context` contains request metadata and the current service execution context.
|
|
117
|
+
- The return annotation is a Pydantic output model.
|
|
118
|
+
|
|
119
|
+
The function may be synchronous or asynchronous.
|
|
120
|
+
|
|
121
|
+
### 2. Decorate it with service metadata
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from pydantic import BaseModel
|
|
125
|
+
from api_builder_runtime import function
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class EchoInput(BaseModel):
|
|
129
|
+
message: str
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class EchoOutput(BaseModel):
|
|
133
|
+
message: str
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@function(service="echo", step=1)
|
|
137
|
+
def echo(payload: EchoInput, deps, context) -> EchoOutput:
|
|
138
|
+
return EchoOutput(message=payload.message)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The decorator records the metadata needed by the builder:
|
|
142
|
+
|
|
143
|
+
- `service`: the public service name
|
|
144
|
+
- `step`: execution order inside the service
|
|
145
|
+
- `description`: optional function description
|
|
146
|
+
- `dependencies`: optional named dependencies
|
|
147
|
+
- `errors`: optional application error codes and HTTP statuses
|
|
148
|
+
|
|
149
|
+
The decorator does not execute the function. It marks the function for discovery.
|
|
150
|
+
|
|
151
|
+
### 3. Run the builder
|
|
152
|
+
|
|
153
|
+
From the root of the project containing `functions/`:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
api-builder
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Useful options:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
api-builder --check # validate without writing app/
|
|
163
|
+
api-builder --force # overwrite generated files
|
|
164
|
+
api-builder --service echo # generate one service
|
|
165
|
+
api-builder --no-dev-routes # omit local function routes
|
|
166
|
+
api-builder --project-root ./demo # build another project
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 4. Run the generated API
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
uvicorn app.main:app --reload
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The public route for the `echo` service is:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
curl -X POST http://127.0.0.1:8000/api/v1/echo \
|
|
179
|
+
-H 'content-type: application/json' \
|
|
180
|
+
-d '{"message":"hello"}'
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The response uses the generated standard envelope:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"data": {
|
|
188
|
+
"message": "hello"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
OpenAPI is available at `/docs` and `/openapi.json`. Health status is available at
|
|
194
|
+
`/healthz`.
|
|
195
|
+
|
|
196
|
+
## Multi-Step Services
|
|
197
|
+
|
|
198
|
+
A service can contain multiple functions. Steps run in ascending order, and the
|
|
199
|
+
output of each step becomes the input for the next step.
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
class ReadInput(BaseModel):
|
|
203
|
+
file_reference: str
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class ReadOutput(BaseModel):
|
|
207
|
+
text: str
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class SummarizeInput(BaseModel):
|
|
211
|
+
text: str
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class SummarizeOutput(BaseModel):
|
|
215
|
+
summary: str
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@function(service="document", step=1)
|
|
219
|
+
async def read_document(
|
|
220
|
+
payload: ReadInput, deps, context
|
|
221
|
+
) -> ReadOutput:
|
|
222
|
+
return ReadOutput(text="Document contents")
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
@function(service="document", step=2)
|
|
226
|
+
async def summarize_document(
|
|
227
|
+
payload: SummarizeInput, deps, context
|
|
228
|
+
) -> SummarizeOutput:
|
|
229
|
+
return SummarizeOutput(summary=payload.text)
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
The builder validates that:
|
|
233
|
+
|
|
234
|
+
- steps are unique
|
|
235
|
+
- steps are contiguous, starting at `1`
|
|
236
|
+
- required fields needed by the next step are produced by the previous step
|
|
237
|
+
- generated route paths and operation IDs are unique
|
|
238
|
+
|
|
239
|
+
The public route remains one service route:
|
|
240
|
+
|
|
241
|
+
```text
|
|
242
|
+
POST /api/v1/document
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Generated Project Layout
|
|
246
|
+
|
|
247
|
+
Running `api-builder` creates this shape:
|
|
248
|
+
|
|
249
|
+
```text
|
|
250
|
+
app/
|
|
251
|
+
├── config.py # environment-backed settings
|
|
252
|
+
├── context.py # request execution context
|
|
253
|
+
├── dependencies.py # named dependency container
|
|
254
|
+
├── errors.py # standard exception mapping
|
|
255
|
+
├── health.py # GET /healthz
|
|
256
|
+
├── main.py # FastAPI application factory
|
|
257
|
+
├── middleware.py # request middleware
|
|
258
|
+
├── responses.py # response envelopes
|
|
259
|
+
├── routers/
|
|
260
|
+
│ ├── public.py # service routes
|
|
261
|
+
│ └── dev.py # local function routes
|
|
262
|
+
├── services/ # generated service orchestration
|
|
263
|
+
├── generated/
|
|
264
|
+
│ ├── function_registry.py # discovered function registry
|
|
265
|
+
│ ├── service_registry.py # service registry
|
|
266
|
+
│ ├── manifest.py # runtime metadata
|
|
267
|
+
│ └── manifest.json # inspectable metadata
|
|
268
|
+
└── tests/ # generated health/OpenAPI tests
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Generated files contain a header identifying them as generated. Treat the decorated
|
|
272
|
+
functions under `functions/` as the source of truth and regenerate after changing
|
|
273
|
+
their metadata or type models.
|
|
274
|
+
|
|
275
|
+
## Development Routes
|
|
276
|
+
|
|
277
|
+
When the environment is `local`, `development`, or `test`, API Builder exposes one
|
|
278
|
+
route per decorated function:
|
|
279
|
+
|
|
280
|
+
```text
|
|
281
|
+
POST /__dev/functions/{service}/{function}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
These routes require the `X-Internal-Dev-Token` header. They are excluded from the
|
|
285
|
+
OpenAPI schema and application entirely in production environments.
|
|
286
|
+
|
|
287
|
+
Use them to exercise a single step while developing a service. The public service
|
|
288
|
+
route remains the normal integration boundary.
|
|
289
|
+
|
|
290
|
+
## Errors
|
|
291
|
+
|
|
292
|
+
Business functions can raise `FunctionError`:
|
|
293
|
+
|
|
294
|
+
```python
|
|
295
|
+
from api_builder_runtime import FunctionError
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
raise FunctionError("EMPTY_DOCUMENT", "The document contains no readable text.")
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Declare an error status on the decorator when a custom HTTP status is needed:
|
|
302
|
+
|
|
303
|
+
```python
|
|
304
|
+
@function(
|
|
305
|
+
service="document",
|
|
306
|
+
step=2,
|
|
307
|
+
errors={"EMPTY_DOCUMENT": 422},
|
|
308
|
+
)
|
|
309
|
+
async def summarize_document(payload, deps, context):
|
|
310
|
+
...
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
The generated error handler returns a stable API error shape and avoids exposing
|
|
314
|
+
internal tracebacks or implementation details to clients.
|
|
315
|
+
|
|
316
|
+
## Validation Rules
|
|
317
|
+
|
|
318
|
+
Build-time validation fails fast when the project contains an invalid function:
|
|
319
|
+
|
|
320
|
+
- missing `functions/` directory
|
|
321
|
+
- no decorated functions
|
|
322
|
+
- wrong function signature
|
|
323
|
+
- missing or invalid Pydantic input model
|
|
324
|
+
- missing or invalid Pydantic output model
|
|
325
|
+
- invalid service or dependency names
|
|
326
|
+
- duplicate or missing service steps
|
|
327
|
+
- incompatible adjacent step models
|
|
328
|
+
- duplicate routes or operation IDs
|
|
329
|
+
|
|
330
|
+
Use `api-builder --check` in CI to validate source functions without changing the
|
|
331
|
+
working tree.
|
|
332
|
+
|
|
333
|
+
## Example
|
|
334
|
+
|
|
335
|
+
The repository includes a two-step PDF summary example at:
|
|
336
|
+
|
|
337
|
+
```text
|
|
338
|
+
examples/basic/functions/pdf_summary.py
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Build it with:
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
api-builder --project-root examples/basic --force
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Library API
|
|
348
|
+
|
|
349
|
+
The builder can also be called from Python:
|
|
350
|
+
|
|
351
|
+
```python
|
|
352
|
+
from pathlib import Path
|
|
353
|
+
from api_builder import build
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
result = build(Path("."), force=True)
|
|
357
|
+
for route in result.routes:
|
|
358
|
+
print(route.method, route.path)
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The runtime decorator is intentionally small and has no application-global registry.
|
|
362
|
+
Discovery happens when the builder scans the current project.
|
|
363
|
+
|
|
364
|
+
## Local Development
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
python -m venv .venv
|
|
368
|
+
source .venv/bin/activate
|
|
369
|
+
pip install -e '.[dev]'
|
|
370
|
+
pytest
|
|
371
|
+
ruff check src tests examples/basic/functions
|
|
372
|
+
mypy src tests
|
|
373
|
+
python -m build
|
|
374
|
+
python -m twine check dist/*
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Scope
|
|
378
|
+
|
|
379
|
+
API Builder generates application structure and validates the contract between
|
|
380
|
+
decorated functions. It does not diagnose infrastructure failures, determine root
|
|
381
|
+
cause, repair runtime systems, or create external service clients automatically.
|
|
382
|
+
Dependencies are named in function metadata and represented in the generated app;
|
|
383
|
+
application owners decide how those dependencies are implemented.
|
|
384
|
+
|
|
385
|
+
## License
|
|
386
|
+
|
|
387
|
+
MIT. See the project metadata for the current author and package version.
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
<h1 align="center">API Builder</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
Generate a complete FastAPI application from decorated Python business functions.
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
## Status
|
|
8
|
+
|
|
9
|
+
This project is alpha software. The intended PyPI distribution name is `api-builder`.
|
|
10
|
+
PyPI currently rejects that exact name as too similar to an existing project, so the
|
|
11
|
+
first published release is temporarily available as `function-api-builder` while the
|
|
12
|
+
name issue is resolved.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
Intended install command:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install api-builder
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Current published fallback:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install function-api-builder
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Both distributions expose the same Python packages and the same `api-builder` command.
|
|
29
|
+
|
|
30
|
+
## What It Does
|
|
31
|
+
|
|
32
|
+
API Builder turns plain, typed business functions into a runnable FastAPI service.
|
|
33
|
+
You write the business logic once. The builder discovers those functions, validates
|
|
34
|
+
their metadata and Pydantic models, then generates an `app/` directory containing:
|
|
35
|
+
|
|
36
|
+
- public service routes
|
|
37
|
+
- optional local development routes for individual functions
|
|
38
|
+
- request validation through Pydantic
|
|
39
|
+
- service sequencing
|
|
40
|
+
- dependency and request-context containers
|
|
41
|
+
- standard error responses
|
|
42
|
+
- health checks
|
|
43
|
+
- OpenAPI documentation
|
|
44
|
+
- generated smoke tests
|
|
45
|
+
|
|
46
|
+
The generated application is ordinary Python code. After generation, run it with
|
|
47
|
+
Uvicorn or edit the generated app as part of your application workflow.
|
|
48
|
+
|
|
49
|
+
## End-to-End Flow
|
|
50
|
+
|
|
51
|
+
The complete flow is:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
functions/**/*.py
|
|
55
|
+
|
|
|
56
|
+
| @function metadata + type annotations
|
|
57
|
+
v
|
|
58
|
+
discovery and import
|
|
59
|
+
|
|
|
60
|
+
| signature, models, steps, routes, dependencies
|
|
61
|
+
v
|
|
62
|
+
validation
|
|
63
|
+
|
|
|
64
|
+
| generated Python modules and manifest
|
|
65
|
+
v
|
|
66
|
+
app/ directory
|
|
67
|
+
|
|
|
68
|
+
| FastAPI startup imports generated routers
|
|
69
|
+
v
|
|
70
|
+
HTTP API + OpenAPI
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 1. Write a business function
|
|
74
|
+
|
|
75
|
+
Business functions live under `functions/`. Every function exposed by the builder
|
|
76
|
+
uses the same three-argument contract:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
def business_function(payload, deps, context) -> OutputModel:
|
|
80
|
+
...
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- `payload` is a Pydantic input model.
|
|
84
|
+
- `deps` is the generated dependency container.
|
|
85
|
+
- `context` contains request metadata and the current service execution context.
|
|
86
|
+
- The return annotation is a Pydantic output model.
|
|
87
|
+
|
|
88
|
+
The function may be synchronous or asynchronous.
|
|
89
|
+
|
|
90
|
+
### 2. Decorate it with service metadata
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from pydantic import BaseModel
|
|
94
|
+
from api_builder_runtime import function
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class EchoInput(BaseModel):
|
|
98
|
+
message: str
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class EchoOutput(BaseModel):
|
|
102
|
+
message: str
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@function(service="echo", step=1)
|
|
106
|
+
def echo(payload: EchoInput, deps, context) -> EchoOutput:
|
|
107
|
+
return EchoOutput(message=payload.message)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The decorator records the metadata needed by the builder:
|
|
111
|
+
|
|
112
|
+
- `service`: the public service name
|
|
113
|
+
- `step`: execution order inside the service
|
|
114
|
+
- `description`: optional function description
|
|
115
|
+
- `dependencies`: optional named dependencies
|
|
116
|
+
- `errors`: optional application error codes and HTTP statuses
|
|
117
|
+
|
|
118
|
+
The decorator does not execute the function. It marks the function for discovery.
|
|
119
|
+
|
|
120
|
+
### 3. Run the builder
|
|
121
|
+
|
|
122
|
+
From the root of the project containing `functions/`:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
api-builder
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Useful options:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
api-builder --check # validate without writing app/
|
|
132
|
+
api-builder --force # overwrite generated files
|
|
133
|
+
api-builder --service echo # generate one service
|
|
134
|
+
api-builder --no-dev-routes # omit local function routes
|
|
135
|
+
api-builder --project-root ./demo # build another project
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 4. Run the generated API
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
uvicorn app.main:app --reload
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The public route for the `echo` service is:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
curl -X POST http://127.0.0.1:8000/api/v1/echo \
|
|
148
|
+
-H 'content-type: application/json' \
|
|
149
|
+
-d '{"message":"hello"}'
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The response uses the generated standard envelope:
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"data": {
|
|
157
|
+
"message": "hello"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
OpenAPI is available at `/docs` and `/openapi.json`. Health status is available at
|
|
163
|
+
`/healthz`.
|
|
164
|
+
|
|
165
|
+
## Multi-Step Services
|
|
166
|
+
|
|
167
|
+
A service can contain multiple functions. Steps run in ascending order, and the
|
|
168
|
+
output of each step becomes the input for the next step.
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
class ReadInput(BaseModel):
|
|
172
|
+
file_reference: str
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class ReadOutput(BaseModel):
|
|
176
|
+
text: str
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class SummarizeInput(BaseModel):
|
|
180
|
+
text: str
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class SummarizeOutput(BaseModel):
|
|
184
|
+
summary: str
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@function(service="document", step=1)
|
|
188
|
+
async def read_document(
|
|
189
|
+
payload: ReadInput, deps, context
|
|
190
|
+
) -> ReadOutput:
|
|
191
|
+
return ReadOutput(text="Document contents")
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@function(service="document", step=2)
|
|
195
|
+
async def summarize_document(
|
|
196
|
+
payload: SummarizeInput, deps, context
|
|
197
|
+
) -> SummarizeOutput:
|
|
198
|
+
return SummarizeOutput(summary=payload.text)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The builder validates that:
|
|
202
|
+
|
|
203
|
+
- steps are unique
|
|
204
|
+
- steps are contiguous, starting at `1`
|
|
205
|
+
- required fields needed by the next step are produced by the previous step
|
|
206
|
+
- generated route paths and operation IDs are unique
|
|
207
|
+
|
|
208
|
+
The public route remains one service route:
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
POST /api/v1/document
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Generated Project Layout
|
|
215
|
+
|
|
216
|
+
Running `api-builder` creates this shape:
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
app/
|
|
220
|
+
├── config.py # environment-backed settings
|
|
221
|
+
├── context.py # request execution context
|
|
222
|
+
├── dependencies.py # named dependency container
|
|
223
|
+
├── errors.py # standard exception mapping
|
|
224
|
+
├── health.py # GET /healthz
|
|
225
|
+
├── main.py # FastAPI application factory
|
|
226
|
+
├── middleware.py # request middleware
|
|
227
|
+
├── responses.py # response envelopes
|
|
228
|
+
├── routers/
|
|
229
|
+
│ ├── public.py # service routes
|
|
230
|
+
│ └── dev.py # local function routes
|
|
231
|
+
├── services/ # generated service orchestration
|
|
232
|
+
├── generated/
|
|
233
|
+
│ ├── function_registry.py # discovered function registry
|
|
234
|
+
│ ├── service_registry.py # service registry
|
|
235
|
+
│ ├── manifest.py # runtime metadata
|
|
236
|
+
│ └── manifest.json # inspectable metadata
|
|
237
|
+
└── tests/ # generated health/OpenAPI tests
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Generated files contain a header identifying them as generated. Treat the decorated
|
|
241
|
+
functions under `functions/` as the source of truth and regenerate after changing
|
|
242
|
+
their metadata or type models.
|
|
243
|
+
|
|
244
|
+
## Development Routes
|
|
245
|
+
|
|
246
|
+
When the environment is `local`, `development`, or `test`, API Builder exposes one
|
|
247
|
+
route per decorated function:
|
|
248
|
+
|
|
249
|
+
```text
|
|
250
|
+
POST /__dev/functions/{service}/{function}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
These routes require the `X-Internal-Dev-Token` header. They are excluded from the
|
|
254
|
+
OpenAPI schema and application entirely in production environments.
|
|
255
|
+
|
|
256
|
+
Use them to exercise a single step while developing a service. The public service
|
|
257
|
+
route remains the normal integration boundary.
|
|
258
|
+
|
|
259
|
+
## Errors
|
|
260
|
+
|
|
261
|
+
Business functions can raise `FunctionError`:
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
from api_builder_runtime import FunctionError
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
raise FunctionError("EMPTY_DOCUMENT", "The document contains no readable text.")
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Declare an error status on the decorator when a custom HTTP status is needed:
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
@function(
|
|
274
|
+
service="document",
|
|
275
|
+
step=2,
|
|
276
|
+
errors={"EMPTY_DOCUMENT": 422},
|
|
277
|
+
)
|
|
278
|
+
async def summarize_document(payload, deps, context):
|
|
279
|
+
...
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
The generated error handler returns a stable API error shape and avoids exposing
|
|
283
|
+
internal tracebacks or implementation details to clients.
|
|
284
|
+
|
|
285
|
+
## Validation Rules
|
|
286
|
+
|
|
287
|
+
Build-time validation fails fast when the project contains an invalid function:
|
|
288
|
+
|
|
289
|
+
- missing `functions/` directory
|
|
290
|
+
- no decorated functions
|
|
291
|
+
- wrong function signature
|
|
292
|
+
- missing or invalid Pydantic input model
|
|
293
|
+
- missing or invalid Pydantic output model
|
|
294
|
+
- invalid service or dependency names
|
|
295
|
+
- duplicate or missing service steps
|
|
296
|
+
- incompatible adjacent step models
|
|
297
|
+
- duplicate routes or operation IDs
|
|
298
|
+
|
|
299
|
+
Use `api-builder --check` in CI to validate source functions without changing the
|
|
300
|
+
working tree.
|
|
301
|
+
|
|
302
|
+
## Example
|
|
303
|
+
|
|
304
|
+
The repository includes a two-step PDF summary example at:
|
|
305
|
+
|
|
306
|
+
```text
|
|
307
|
+
examples/basic/functions/pdf_summary.py
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Build it with:
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
api-builder --project-root examples/basic --force
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Library API
|
|
317
|
+
|
|
318
|
+
The builder can also be called from Python:
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
from pathlib import Path
|
|
322
|
+
from api_builder import build
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
result = build(Path("."), force=True)
|
|
326
|
+
for route in result.routes:
|
|
327
|
+
print(route.method, route.path)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
The runtime decorator is intentionally small and has no application-global registry.
|
|
331
|
+
Discovery happens when the builder scans the current project.
|
|
332
|
+
|
|
333
|
+
## Local Development
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
python -m venv .venv
|
|
337
|
+
source .venv/bin/activate
|
|
338
|
+
pip install -e '.[dev]'
|
|
339
|
+
pytest
|
|
340
|
+
ruff check src tests examples/basic/functions
|
|
341
|
+
mypy src tests
|
|
342
|
+
python -m build
|
|
343
|
+
python -m twine check dist/*
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Scope
|
|
347
|
+
|
|
348
|
+
API Builder generates application structure and validates the contract between
|
|
349
|
+
decorated functions. It does not diagnose infrastructure failures, determine root
|
|
350
|
+
cause, repair runtime systems, or create external service clients automatically.
|
|
351
|
+
Dependencies are named in function metadata and represented in the generated app;
|
|
352
|
+
application owners decide how those dependencies are implemented.
|
|
353
|
+
|
|
354
|
+
## License
|
|
355
|
+
|
|
356
|
+
MIT. See the project metadata for the current author and package version.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">API Builder logo</title>
|
|
3
|
+
<desc id="desc">A teal hexagonal API node mark with a white code chevron.</desc>
|
|
4
|
+
<rect width="512" height="512" rx="96" fill="#102A43"/>
|
|
5
|
+
<path d="M256 58 420 153v190l-164 95-164-95V153L256 58Z" fill="#16B8A6"/>
|
|
6
|
+
<path d="m222 181-76 75 76 75" fill="none" stroke="#102A43" stroke-linecap="round" stroke-linejoin="round" stroke-width="30"/>
|
|
7
|
+
<path d="m290 181 76 75-76 75" fill="none" stroke="#102A43" stroke-linecap="round" stroke-linejoin="round" stroke-width="30"/>
|
|
8
|
+
<path d="M271 158 241 354" fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-width="22"/>
|
|
9
|
+
</svg>
|
|
@@ -4,9 +4,9 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "function-api-builder"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
description = "Generate complete FastAPI applications from decorated Python business functions."
|
|
9
|
-
readme = "README.md"
|
|
9
|
+
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
requires-python = ">=3.11"
|
|
11
11
|
license = "MIT"
|
|
12
12
|
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: function-api-builder
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Generate complete FastAPI applications from decorated Python business functions.
|
|
5
|
-
Author: Sushruth Samson
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Keywords: api-builder,api-generator,backend,code-generation,fastapi,pydantic
|
|
8
|
-
Classifier: Development Status :: 3 - Alpha
|
|
9
|
-
Classifier: Environment :: Console
|
|
10
|
-
Classifier: Framework :: FastAPI
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
-
Classifier: Operating System :: OS Independent
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
-
Classifier: Topic :: Software Development :: Code Generators
|
|
19
|
-
Requires-Python: >=3.11
|
|
20
|
-
Requires-Dist: fastapi>=0.115
|
|
21
|
-
Requires-Dist: pydantic>=2.7
|
|
22
|
-
Requires-Dist: uvicorn>=0.30
|
|
23
|
-
Provides-Extra: dev
|
|
24
|
-
Requires-Dist: build>=1.2; extra == 'dev'
|
|
25
|
-
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
26
|
-
Requires-Dist: mypy>=1.13; extra == 'dev'
|
|
27
|
-
Requires-Dist: pytest>=8; extra == 'dev'
|
|
28
|
-
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
29
|
-
Requires-Dist: twine>=6; extra == 'dev'
|
|
30
|
-
Description-Content-Type: text/markdown
|
|
31
|
-
|
|
32
|
-
# API Builder
|
|
33
|
-
|
|
34
|
-
Generate a FastAPI application from decorated Python business functions.
|
|
35
|
-
|
|
36
|
-
## Install
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
pip install function-api-builder
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Use
|
|
43
|
-
|
|
44
|
-
Create `functions/example.py` in your project:
|
|
45
|
-
|
|
46
|
-
```python
|
|
47
|
-
from pydantic import BaseModel
|
|
48
|
-
from api_builder_runtime import function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class Input(BaseModel):
|
|
52
|
-
value: str
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
class Output(BaseModel):
|
|
56
|
-
result: str
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
@function(service="example", step=1)
|
|
60
|
-
def run(payload: Input, deps, context) -> Output:
|
|
61
|
-
return Output(result=payload.value)
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Then run:
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
api-builder
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
The builder writes a complete `app/` FastAPI application with a public service route, optional local development routes, health checks, OpenAPI, and generated tests.
|
|
71
|
-
|
|
72
|
-
The function signature must be `(payload, deps, context)`, with Pydantic models for the payload and return value. See `examples/basic/functions/pdf_summary.py` for a multi-step service.
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# API Builder
|
|
2
|
-
|
|
3
|
-
Generate a FastAPI application from decorated Python business functions.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
pip install function-api-builder
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Use
|
|
12
|
-
|
|
13
|
-
Create `functions/example.py` in your project:
|
|
14
|
-
|
|
15
|
-
```python
|
|
16
|
-
from pydantic import BaseModel
|
|
17
|
-
from api_builder_runtime import function
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class Input(BaseModel):
|
|
21
|
-
value: str
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class Output(BaseModel):
|
|
25
|
-
result: str
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@function(service="example", step=1)
|
|
29
|
-
def run(payload: Input, deps, context) -> Output:
|
|
30
|
-
return Output(result=payload.value)
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Then run:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
api-builder
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
The builder writes a complete `app/` FastAPI application with a public service route, optional local development routes, health checks, OpenAPI, and generated tests.
|
|
40
|
-
|
|
41
|
-
The function signature must be `(payload, deps, context)`, with Pydantic models for the payload and return value. See `examples/basic/functions/pdf_summary.py` for a multi-step service.
|
{function_api_builder-0.1.0 → function_api_builder-0.1.2}/examples/basic/functions/__init__.py
RENAMED
|
File without changes
|
{function_api_builder-0.1.0 → function_api_builder-0.1.2}/examples/basic/functions/pdf_summary.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{function_api_builder-0.1.0 → function_api_builder-0.1.2}/src/api_builder_runtime/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|