|
1 | | -# fastapi-google-workflows |
2 | | -Framework to create Google Cloud Workflows using FastAPI server |
| 1 | +[](https://qlty.sh/gh/flamingo-run/projects/fastapi-google-workflows) |
| 2 | +[](https://qlty.sh/gh/flamingo-run/projects/fastapi-google-workflows) |
| 3 | +[](https://github.com/flamingo-run/fastapi-cloud-workflows/actions/workflows/ci.yml) |
| 4 | + |
| 5 | + |
| 6 | +# FastAPI Cloudflow |
| 7 | + |
| 8 | +Typed, ergonomic Google Cloud Workflows backed by FastAPI apps. |
| 9 | + |
| 10 | +Write typed steps as normal async functions, compose them with `>>`, and generate/deploy Cloud Workflows while the framework exposes first-class FastAPI step endpoints for you. |
| 11 | + |
| 12 | +## Why it’s useful |
| 13 | +- Define workflows in pure, typed Python (Pydantic IO models) |
| 14 | +- Reuse your FastAPI app: framework attaches `/steps/<name>` endpoints automatically |
| 15 | +- Generate stable Cloud Workflows YAML from your Python composition |
| 16 | +- Works great with CI (codegen snapshots) and smoke tests against real GCP |
| 17 | + |
| 18 | +## Tiny example |
| 19 | +```python |
| 20 | +from pydantic import BaseModel |
| 21 | +from fastapi_cloudflow import Context, step, workflow |
| 22 | + |
| 23 | +class CreateOrder(BaseModel): |
| 24 | + account_id: int |
| 25 | + sku: str |
| 26 | + qty: int |
| 27 | + |
| 28 | +class OrderDraft(BaseModel): |
| 29 | + order_id: str |
| 30 | + status: str |
| 31 | + |
| 32 | +class OrderPlaced(BaseModel): |
| 33 | + order_id: str |
| 34 | + status: str |
| 35 | + |
| 36 | +@step(name="price-order") |
| 37 | +async def price_order(ctx: Context, data: CreateOrder) -> OrderDraft: |
| 38 | + return OrderDraft(order_id="o-123", status="priced") |
| 39 | + |
| 40 | +@step(name="confirm-order") |
| 41 | +async def confirm_order(ctx: Context, data: OrderDraft) -> OrderPlaced: |
| 42 | + return OrderPlaced(order_id=data.order_id, status="approved") |
| 43 | + |
| 44 | +ORDER_FLOW = (workflow("order-flow") >> price_order >> confirm_order).build() |
| 45 | +``` |
| 46 | +- Run `fastapi-cloudflow build` and you’ll get `order-flow.yaml` |
| 47 | +- Attach to your FastAPI app and the framework exposes `POST /steps/price-order` with typed IO |
| 48 | + |
| 49 | +## How it works (high-level) |
| 50 | +```mermaid |
| 51 | +graph TD |
| 52 | + %% GCP runtime |
| 53 | + subgraph GCP |
| 54 | + subgraph CloudRun |
| 55 | + subgraph "FastAPI Server" |
| 56 | + subgraph "steps endpoints" |
| 57 | + StepCode["steps code"] |
| 58 | + end |
| 59 | + Other["other endpoints"] |
| 60 | + end |
| 61 | + end |
| 62 | + subgraph CloudWorkflows |
| 63 | + subgraph Workflow |
| 64 | + WFStep["Step"] |
| 65 | + end |
| 66 | + end |
| 67 | + end |
| 68 | +
|
| 69 | + %% CD pipeline |
| 70 | + subgraph "Continuous Delivery" |
| 71 | + subgraph Codegen |
| 72 | + YAML["YAML"] |
| 73 | + end |
| 74 | + Deploy["Deployment"] |
| 75 | + end |
| 76 | +
|
| 77 | + Codebase["Codebase"] --> Codegen |
| 78 | + Codebase --> Deploy |
| 79 | + Codegen --> YAML |
| 80 | + YAML --> Workflow |
| 81 | + WFStep -->|http.post| StepCode |
| 82 | + StepCode -->|JSON| WFStep |
| 83 | + Deploy --> CloudRun |
| 84 | +``` |
| 85 | + |
| 86 | +- You write typed steps and compose with `workflow(...) >> step_a >> step_b` |
| 87 | +- The CLI emits Cloud Workflows YAML that uses `http.post` to call the attached FastAPI step endpoints |
| 88 | +- The framework injects a workflow context into each request (headers include name/run-id), and returns typed JSON bodies |
| 89 | + |
| 90 | +## Try the examples |
| 91 | +- See `examples/app/flows`: playful multi-step workflows |
| 92 | + - `echo_name.py` → echo-name-flow: echo → extract → shout |
| 93 | + - `post_story.py` → post-story-flow: build story → POST external → summarize |
| 94 | + - `jokes.py` → joke-flow: fetch → split → rate |
| 95 | + |
| 96 | +## Codegen & tests |
| 97 | +- Codegen snapshots: `uv run -q pytest -q tests/codegen` (full-file YAML equality) |
| 98 | +- Unit tests: `uv run -q pytest -q tests/unit` (hits `/steps/<name>` endpoints with TestClient) |
| 99 | +- Smoke tests: `uv run -q python tests/smoke/run_smoke.py --region us-central1` (requires GCP & deployed example) |
| 100 | + |
| 101 | +## Supported features (Cloud Workflows) |
| 102 | + |
| 103 | +| Feature | Status | Notes | |
| 104 | +| --- | --- | --- | |
| 105 | +| HTTP calls (http.get/post/…) | ✅ | `HttpStep`; custom headers, method | |
| 106 | +| Auth to Cloud Run (OIDC audience) | ✅ | Python steps bake OIDC with `audience=BASE_URL` | |
| 107 | +| Step timeouts | ✅ | `HttpStep(timeout=…)` emits seconds | |
| 108 | +| Variables / assignment | ✅ | payload propagation + adapters/typed steps | |
| 109 | +| Expressions (concat/env/params) | ✅ | `Arg.env/param/ctx`, string concat and path join | |
| 110 | +| Sequential composition | ✅ | `workflow(...) >> step_a >> step_b` | |
| 111 | +| Workflow input/output | ✅ | single `payload` param; final `return: ${payload}` | |
| 112 | +| Error surfacing | ✅ | HTTP errors propagate; FastAPI returns typed 4xx/5xx | |
| 113 | +| Retries | ⏳ | planned `RetryPolicy` emission | |
| 114 | +| Try/catch | ❌ | not yet | |
| 115 | +| Conditionals / switch | ❌ | not yet | |
| 116 | +| Loops | ❌ | not yet | |
| 117 | +| Parallel branches / join | ❌ | not yet | |
| 118 | +| Subworkflows / call other workflows | ❌ | not yet | |
| 119 | +| GCP connectors / direct service calls | ❌ | not yet | |
| 120 | + |
| 121 | +## Next steps |
| 122 | +- Open CONTRIBUTING.md for local setup, structure, and contribution checklist |
| 123 | +- Use descriptive names for workflows/steps and prefer multi-step workflows that show transformations |
| 124 | + |
0 commit comments