Run the API client
This example exposes an empty AuthenticationServer database through a local
APIServer and reads its status. It uses the standard-library Python client at
tunnels/APIServer/examples/api_client.py
in the WaterWall source checkout.
It shares tunnels/APIServer/client/ww_api.py and ww_api_cli.py with the
administration CLI. Keep the examples/ and client/
directories beside each other when copying this generic example. For everyday
account administration, the CLI supplies commands without handwritten JSON
request files. The generic example writes decoded result bytes unchanged to
stdout; transport and CLI support remain independent of account schemas.
The chain is TcpListener -> APIServer. The gateway invokes the separately
configured AuthenticationServer through its registered API; the database node
is not the next node in that chain. No AuthenticationClient or producer-protocol
listener is needed for this example.
Create a local configuration
Start in the WaterWall repository root. Use a new directory so the example does not replace an existing database:
export WATERWALL_REPO="$(pwd)"
umask 077
mkdir api-demo
cd api-demo
Generate the configuration and an independent random operator token:
python3 - <<'PY'
import json
from pathlib import Path
import secrets
token = secrets.token_hex(32)
Path("monitor-token").write_text(token + "\n", encoding="ascii")
Path("users.json").write_text('{"users":[]}\n', encoding="utf-8")
core = {"misc": {"workers": 1, "try-enabling-bbr": False}, "configs": ["config.json"]}
config = {
"name": "central",
"nodes": [
{"name": "auth-db", "type": "AuthenticationServer", "settings": {
"db-path": "users.json", "file-save-rate-ms": 60000,
"auth-clients": [{"name": "reserved-producer", "secret": secrets.token_hex(32)}]
}},
{"name": "api-listener", "type": "TcpListener", "settings": {
"address": "127.0.0.1", "port": 9080
}, "next": "management-api"},
{"name": "management-api", "type": "APIServer", "settings": {
"clients": [{"name": "monitor", "token": token, "allow": [{
"config": "central", "node": "auth-db",
"operations": ["status", "get-user", "list-users"]
}]}]
}}
]
}
for filename, value in (("core.json", core), ("config.json", config)):
Path(filename).write_text(json.dumps(value, indent=2) + "\n", encoding="utf-8")
PY
AuthenticationServer requires a nonempty auth-clients setting. The reserved
producer above has no permissions and no network listener. Its secret is separate
from the API operator token and cannot authenticate an API request.
Run WaterWall from this directory, using your installed executable or the existing Linux build:
"$WATERWALL_REPO/build/linux/Release/Waterwall" --config:core.json
Paths in core.json and db-path are relative to the process working directory.
See the startup configuration guide
for other executable and configuration locations. The listener is local only;
APIServer authenticates requests but does not encrypt the transport.
Read the server status
In another terminal, enter api-demo and set WATERWALL_REPO to your checkout's
absolute path. Run:
python3 "$WATERWALL_REPO/tunnels/APIServer/examples/api_client.py" \
--host 127.0.0.1 --port 9080 \
--client monitor --token-file monitor-token \
--config central --node auth-db --operation status
The client sends {} as the default node body, reads one complete framed reply,
and writes the decoded node-result body to stdout. An empty database reports
user_count: "0". The AuthenticationServer reference
defines the complete result; values such as counts and revisions are decimal
strings. Credentials are omitted from public results.
The selector uses the configuration's logical name central, not the filename
config.json. Omitting --config works only when the node name is unique across
all loaded configurations. Using the qualified selector keeps the target explicit.
Supply tokens and request bodies
Tokens may come from a file or an environment variable. For the latter:
export WATERWALL_API_TOKEN="$(cat monitor-token)"
python3 "$WATERWALL_REPO/tunnels/APIServer/examples/api_client.py" \
--client monitor --token-env WATERWALL_API_TOKEN \
--config central --node auth-db --operation status
The default host and port are 127.0.0.1:9080. Token contents are never supplied
as a command-line option. --body-file supplies the node's request bytes; with the
default --body-encoding utf8 they must be UTF-8 without NUL. Use
--body-encoding base64 for a registered operation that accepts arbitrary bytes.
The client reads the file and performs base64 encoding itself. Select the
operation's registered content type with --content-type; its default is
application/json.
The client validates response framing and correlation ID and makes exactly one attempt. It does not automatically retry reads or writes. Conditional edits and password changes print conflict or uncertain-outcome guidance when applicable. The outer request ID correlates replies and does not deduplicate operations.
Gateway busy and shutting_down mean the handler was not invoked, including for create, update and password
changes. They are definite refusals; the client still makes no automatic retry. A returned node error is a separate
operation result. Lost/malformed replies, timeout and response-size errors after sending retain unknown-outcome
guidance. Response reads request at most 64 KiB per socket call within the accepted frame cap, using one original
monotonic deadline across every chunk rather than extending the timeout after each short read.
Continue with the administration CLI, wire-level authentication account workflows, or HTTP and reliable UDP transport. The API protocol guide describes framing, envelopes and errors for developers writing another client; the APIServer reference owns gateway settings and resource limits.