[ AxiomCore · Documentation ]
FastAPI
Keep a FastAPI service, extract its contract, and call it from a browser client generated for atmx-web.
Keep FastAPI as your executable backend and ordinary TypeScript as your frontend. AxiomCore extracts a contract from the FastAPI app and generates a typed web client from it. This guide runs a real Python service and a real browser request, with no mock responses.
| Path | Status |
|---|---|
| FastAPI extraction | Available (the published extractor binary is for macOS arm64) |
Vanilla web client (atmx-web) | Available |
Requirements
| Tool | Version used by the example |
|---|---|
| Axiom CLI | 0.149.1 |
| FastAPI extractor | 0.1.4, macOS arm64 |
| Python | 3.12, to run the service (FastAPI 0.123.5, Pydantic 2.13.4, Uvicorn 0.38.0) |
| Node.js and npm | Node.js 22.12 or later |
| Web packages | atmx-cli 0.146.7, atmx-web 0.147.5, Vite 7.3.7, TypeScript 5.9.3 |
You also need two terminals and free ports 8083 and 5175.
1. Get the example
git clone --depth 1 https://github.com/AxiomCore/AxiomCore.git
cd AxiomCore/examples/documentation/fastapi-webThe example has backend/ (the FastAPI app, its Acore source and manifest) and
frontend/ (a Vite page that calls the API).
2. Install the FastAPI extractor
Install FastAPI extractor 0.1.4 with the checksummed steps in
backend extractors. The CLI
runs ~/.acore/bin/axiom-fastapi-extractor, or the binary at the path in
AXIOM_FASTAPI_EXTRACTOR. In CLI 0.149.1, axiom install <extractor> --module
does not find the published build, so install it directly.
3. Build the contract and start the API
The backend source is two lines. amends tells the CLI to extract the FastAPI
app app from main.py, then apply anything else declared in this file:
amends "axiom-fastapi:main.py:app"
project(id: "docs.fastapi.greeting", version: "1.0.0")Create a virtual environment for the service, build the contract, and start the API:
python3 -m venv .venv
.venv/bin/python -m pip install -r backend/requirements.txt
cd backend
axiom build axiom.acore --out backend.axiom
../.venv/bin/python -m uvicorn main:app --host 127.0.0.1 --port 8083Built backend contract: backend.axiomExtraction imports main.py, so keep its import path free of migrations,
worker startup, production connections and destructive setup. See
how extraction works for what runs.
4. Review the extracted contract
Before anything consumes the contract, review method and path, required inputs, response models, validation, authentication and errors. Two ways to look:
axiom inspect backend.axiomopens an interactive endpoint and model browser (it needs a terminal).axiom explain axiom.acoreprints the extracted contract as JSON.
For this example the contract holds one endpoint, greet: GET /greet/{name}
with a required string path parameter and a Greeting response with one
message string. The 40-character limit on name is not in the extracted
contract; FastAPI enforces it and returns 422. Extraction cannot infer every
rule a handler applies, so add the facts that matter in Acore or test them
directly.
To start your own app without an Acore file, run this from its backend
directory, replacing main.py:app with your module and app variable:
axiom init main.py:app --module axiom-fastapiaxiom init writes axiom.acore and a backend AxiomDeps.toml. It refuses to
overwrite an existing axiom.acore. Without both arguments it opens an
interactive wizard.
5. Generate the web client and run it
Open a second terminal in the example root:
cd frontend
npm ci
axiom pull ../backend/backend.axiom --framework atmx-web --name greetings --out generated
npm run devaxiom pull records the contract in frontend/AxiomDeps.toml, copies it to
public/greetings.axiom, and runs the generator into generated/. The
predev script copies the atmx-web runtime Wasm into public/, so both
assets are served from the frontend origin.
Install the generator before you pull
axiom pull runs the project's local atmx-cli when node_modules has one.
Otherwise it runs npx atmx-cli@<CLI version>, and no atmx-cli 0.149.x is
published, so npm fails with ETARGET. The example pins atmx-cli 0.146.7
as a dev dependency; npm ci installs it. Pin and test the combination for
your own contract.
Open http://127.0.0.1:5175 and select Say hello. The page shows
Hello, Ada! from the running Python service.
6. Initialize before querying
frontend/main.ts overrides the generated config with the API base URL and
the Wasm location, awaits atmx.init, and enables the button only when
ready.ok is true. A query returns a handle that you subscribe to, not a
value you await:
const query = atmx.query('greetings.greet', { name: 'Ada' });
const unsubscribe = query.subscribe((state) => {
if (state.error) output.textContent = state.error.message;
else if (state.data) output.textContent = state.data.message;
});
// When you replace the query or the page goes away:
unsubscribe();
query.dispose();The operation name is the --name alias plus the endpoint name. Use your own
generated names and types. The web SDK guide covers caching and
authentication.
Verify
Call the API directly from any terminal:
curl -fsS http://127.0.0.1:8083/greet/Ada{"message":"Hello, Ada!"}Then check:
- a name longer than 40 characters returns 422, both directly and in the page;
- missing or invalid input shows a browser-visible error;
- base URL, CORS allowlist, credentials where used, loading and empty states, and cache privacy behave as intended;
- a fresh browser session still starts correctly (a stored cache must not hide a startup failure).
Use contract tests and mocks for declared behavior during frontend work. They complement the real request; a mock does not prove the FastAPI handler's behavior.
Security and deployment
- The example API is public and stateless, with no login or database. Add your application's identity and data policies separately.
- Local CORS allows only
http://127.0.0.1:5175andhttp://localhost:5175, methodGET, and the headerscontent-type,traceparentandx-axiom-cache-mode, which the web runtime sends. - Extraction and contract builds do not deploy the API or enforce the contract around each handler. Use a server adapter when you need that boundary.
- For release review, keep the source, contract, dependency lock, test output and semantic diff together.
Clean up
Stop both servers with Ctrl-C. Delete the example directory to remove its
virtual environment, node_modules, generated SDK and built contract.