Aster Web Data / Reference
Configuration
Every configuration key, its type, default and effect.
Keys
The server reads one YAML file. Unknown keys are an error, so a misspelt key stops the start-up rather than being ignored. Relative paths resolve against the directory of the configuration file. Secrets never go in the file: a database names the environment variable or file that holds its connection URL or password.
Types: string, int, bool, list (YAML list), map, and file (a path, relative to the configuration file). A duration is a whole number with a unit: ms, s, m or h (for example 5s).
Top level
| Key |
Type |
Default |
Effect |
listen |
string |
127.0.0.1:8080 |
Address to bind. Port 0 picks a free port, and the server prints the one it bound. |
services |
map |
required |
One entry per service. At least one. See Services. |
databases |
map |
required |
One entry per database. At least one. See Databases. |
startup |
section |
see below |
What start-up does when a database cannot be opened. |
limits |
section |
see Limits |
Request limits for every service, unless a service sets the key itself. |
auth |
section |
see Authentication |
How a request becomes a caller. |
cors |
section |
absent |
Cross-origin access for browser clients. Absent: no CORS headers, so browsers allow same-origin pages only. |
request_facts |
section |
see below |
What rules may read about a request besides its caller. |
i18n |
section |
see below |
Message files $metadata is translated with. |
log |
section |
see below |
Log format and level. |
shutdown |
section |
see below |
How a stop drains requests in flight. |
updates |
section |
see below |
Whether a preview build looks for a newer build. |
scripts |
section |
see below |
Ceilings that a script's own limits: cannot exceed. |
http |
map |
none |
Named connections that scripts make HTTP calls on. See HTTP connections. |
explain |
section |
see below |
The explain response header. See Explain. |
observability |
section |
see below |
Traces, metrics and logs export. |
observe |
section |
see below |
Per-plan-shape request metrics. |
health |
section |
see below |
The health listener and its endpoints. |
Startup
| Key |
Type |
Default |
Effect |
startup.require_databases |
bool |
false |
Every database must open and pass its check at start-up, or the process stops. Overridden by ASTER_WEBDATA_REQUIRE_DATABASES. |
startup.require_tls |
bool |
false |
Every PostgreSQL and MariaDB database refuses a plaintext or unverified connection. Overridden by ASTER_WEBDATA_REQUIRE_TLS. Independent of require_databases. |
Services
Each key below sits under services.<name>. The name uses letters, digits, _ and -. It appears in logs and in the aster_webdata.service metric label, and it gives the default root.
| Key |
Type |
Default |
Effect |
root |
string |
/<name> |
The path the service is mounted at. Roots are unique, and no root is a path prefix of another (/a and /a/b cannot both be roots). |
public_url |
string |
http://<listen><root> |
The absolute service root clients see, in context URLs and next links. Set it behind a proxy. |
openapi |
bool |
true |
Publishes <root>/openapi.json (OpenAPI 3.1) from the same model as $metadata. |
namespace |
string |
Aster |
The CSDL schema namespace. |
datasources |
list |
required |
DataSource files (.ds.xml, .ds.yaml, .ds.yml), or directories that hold them. |
database |
string |
the only database |
The database the sources are on, unless a DataSource names its own with database:. With several databases, a source with neither is refused at load. |
seed |
file |
none |
A JSON object of entity set name to an array of entities, for this service's sets. Loaded once per database: into memory, or into the tables with setup: recreate. |
max_page_size |
int |
1000 |
Server-driven paging: the largest page before a next link. A larger $top arrives in pages of this size, not as a refusal. Clients can ask for less with Prefer: odata.maxpagesize. |
select_without_keys |
bool |
false |
When false, a $select adds the key properties to the response. When true, it returns only what was selected. |
etag_opt_out |
list |
[] |
Entity sets without an ETag (the same as etag: none in the DataSource). Writes to them are last write wins. |
updates_without_read |
list |
[] |
Entity sets that accept an update of a row the caller may write but not read, with If-Match: *. Published as AsterData.UpdatesWithoutRead. |
deletes_without_read |
list |
[] |
Entity sets that accept a delete of a row the caller may delete but not read, with If-Match: *. Published as AsterData.DeletesWithoutRead. Separate from the update option. |
rules |
file |
none |
A rules file of server rules over claims, request facts and data. A rule that does not compile fails the load, and the error names it. |
security.<Set>.read, .insert, .update, .delete |
map |
none |
Access rule for the operation: authenticated (bool), roles (list, any one), never (bool). An absent operation allows anyone. |
security.<Set>.owner |
string |
none |
The property holding the owner's user ID. A caller sees and changes only their own rows. |
context.values.<name>.type |
string |
required |
String, Int64, Decimal, Boolean, Guid or Date. Name: lower case letters, digits and _. |
context.values.<name>.required |
bool |
false |
A request without the value gets 400. |
context.values.<name>.authorise.set |
string |
none |
The set a value is checked against. |
context.values.<name>.authorise.filter |
string |
none |
A $filter over that set, which may read context.<name>, user.<property> and $user. Fails with 403 when no row matches. |
context.user_source.set |
string |
none |
The entity set with one row per user. Its properties are the request facts user.<property>. |
context.user_source.subject |
string |
none |
The property holding the token's subject. |
context.user_source.required |
bool |
false |
A caller with no row gets 403. |
limits.* |
section |
the top-level limits |
Any key of Limits, for this service only. A key left out keeps the top-level value. |
Databases
Each key below sits under databases.<name>. The name is for operators (logs, metrics, and the readiness listener). Clients never see it.
| Key |
Type |
Default |
Effect |
kind |
string |
required |
postgres, mariadb, sqlite, duckdb, mssql (SQL Server), oracle, db2, tigerbeetle or memory. postgres, mariadb and memory are in the default build, and the others where the build includes them. An unknown kind is a start-up error that lists the kinds the build has. |
url_env |
string |
none |
Environment variable that holds the connection URL. Read again on every attempt to open the database. |
url_file |
file |
none |
File that holds the connection URL. Read again on every attempt. |
host, port, user, database |
string, int, string, string |
none |
The parts form, used instead of a URL. database is the connection's database (MariaDB: also its default schema). |
password_env, password_file |
string, file |
none |
The password for the parts form. |
schema |
string |
the kind's default |
The default schema of the database's sources. A source's own schema wins. PostgreSQL: public. DuckDB: main. MariaDB: the connection's database. |
tls |
disable, prefer, require, verify-ca or verify-full |
prefer |
prefer uses TLS when offered, without verification. A plaintext or unverified connection logs a warning. SQL Server, Oracle and Db2 accept fewer modes (see their pages); SQLite, DuckDB and TigerBeetle take none. |
ca_file |
file |
Mozilla roots |
PEM certificates that verify-ca and verify-full trust. |
tls_strict |
bool |
false |
A plaintext or unverified connection is a start-up error. Independent of required. Also set for every database by startup.require_tls. |
collation |
string |
none |
The collation published as AsterData.Collation for text fields that declare none. Checked against each column at start-up. |
setup |
existing or recreate |
existing |
existing uses the tables as they are. recreate creates a missing schema (it never drops one), drops and creates each source's table, then loads the seeds. For scratch and test databases only. |
read_only |
bool |
false |
No source on the database may write. The server refuses at load any set, binding or action that writes, and any setup: recreate or seed. |
required |
bool |
false |
A database that cannot be opened, or fails its start-up check, stops the process. By default the server starts, the sets stored on the database answer 503, and the server keeps retrying. |
retry.initial |
duration |
1s |
First reconnection delay. Backoff is exponential with jitter and no attempt limit. |
retry.max |
duration |
60s |
Longest reconnection delay. |
pool.max |
int |
10 |
Most connections the pool opens. |
pool.min_idle |
int |
0 |
Connections kept open while the pool is in use. |
pool.connect_timeout |
duration |
5s |
How long a connection attempt may take. |
pool.checkout_timeout |
duration |
5s |
How long a request waits for a free connection. An exhausted pool answers 503 PoolExhausted. |
options |
map |
none |
Settings of the database kind's own. PostgreSQL: single_statement (bool, default true): $expand and deep inserts run as one statement. Set false for the multi-statement form. TigerBeetle: cluster_id, addresses, timeout_ms. |
Limits
Limits sit under limits at the top level, and under services.<name>.limits for one service. Each key is optional. A key a service leaves out keeps the top-level value, and a top-level key left out keeps the built-in default.
| Key |
Type |
Default |
Effect |
residual_rows |
int |
50000 |
Most rows the in-engine executor holds at once. A read that needs more fails with 400 QueryTooExpensive. |
max_insert_rows |
int |
10000 |
Most rows one insert may take. |
max_batch_size |
int |
1000 |
Most operations in one $batch. |
max_expand_depth |
int |
8 |
Deepest $expand nesting. |
max_in_set |
int |
10000 |
Most items in one in list or array. |
request_deadline_ms |
int |
60000 |
Time a request may run before it is cut. |
statement_timeout_ms |
int |
30000 |
Time one database statement may run. A timeout answers 503 Timeout. |
max_traverse_depth |
int |
64 |
Deepest walk of a hierarchy (ancestors, descendants, traverse). |
max_body_bytes |
int |
16777216 (16 MiB) |
Largest request body accepted. |
unbounded_residual |
warn or refuse |
warn |
What a $skip or $count does when it would run in memory over every row of an unbounded backend fetch. warn runs it, logs it, and counts it. refuse answers 501. |
key_batch |
int |
8192 |
Most keys one statement of a key batch carries ($expand and navigation across databases). Larger levels are read in chunks. Must be at least 1. |
max_orderby_items |
int |
128 |
Most items in one $orderby. More answers 400 QueryTooExpensive. Must be at least 1. |
max_lambda_depth |
int |
4 |
Deepest nesting of any and all in one expression. Deeper answers 400 QueryTooExpensive. |
Authentication
| Key |
Type |
Default |
Effect |
auth.kind |
anonymous, fixed, dev-headers or jwt |
anonymous |
Which authenticator turns a request into a caller. |
auth.user |
string |
none |
fixed only: the user ID every request runs as. Absent: anonymous with the roles below. |
auth.roles |
list |
[] |
fixed only: the roles every request has. |
auth.user_header |
string |
X-Aster-User |
dev-headers only: the header naming the user. |
auth.roles_header |
string |
X-Aster-Roles |
dev-headers only: the header listing roles, comma-separated. |
auth.jwt.secret_env |
string |
none |
Environment variable that holds an HMAC secret of at least 32 bytes. |
auth.jwt.public_key_file |
file |
none |
PEM public key (RSA, EC or Ed25519). |
auth.jwt.jwks_file |
file |
none |
JWKS file. The token's kid picks the key. Read from a local file only. |
auth.jwt.algorithms |
list |
the one the key implies |
Accepted algorithms, for example HS256, RS256, ES256 or EdDSA. Required with a JWKS. |
auth.jwt.audience |
list |
required |
A token must name one of these audiences. |
auth.jwt.issuer |
list |
none |
A token must name one of these issuers. Absent: not checked. |
auth.jwt.user_claim |
string |
sub |
Claim that holds the user ID. |
auth.jwt.roles_claim |
string |
roles |
Claim that holds the roles: an array, or one space- or comma-separated string. |
auth.jwt.leeway_seconds |
int |
60 |
Clock skew allowed on exp and nbf. |
dev-headers lets any client choose its own user and roles. Use it for development only. The server writes a warning at start-up when it is set.
Request facts and CORS
| Key |
Type |
Default |
Effect |
request_facts.headers |
list |
[] |
Request headers that rules may read, in any case. A header not listed reads as null. Listed headers are added to Vary. |
request_facts.client_address_header |
string |
none |
Header a trusted reverse proxy sets to the client's address (for example X-Real-IP). Absent: the address the connection came from. Set it only behind a proxy that overwrites the header. |
cors.allowed_origins |
list |
required |
Allowed origins, for example https://ui.example.com. * allows any origin. |
cors.allow_credentials |
bool |
false |
Sends Access-Control-Allow-Credentials: true. Cannot be combined with *. |
cors.max_age_seconds |
int |
600 |
How long a browser may cache a preflight answer. |
cors.extra_allowed_headers |
list |
[] |
Request headers a page may send, beyond the OData headers the server always allows. |
Internationalisation
| Key |
Type |
Default |
Effect |
i18n.default |
string |
none |
Language of the default document. Absent: message references are published unresolved. |
i18n.messages |
map |
{} |
Per language tag, a JSON file of message key to text. $metadata resolves references in the Accept-Language language. |
Logging and shutdown
| Key |
Type |
Default |
Effect |
log.format |
json or text |
json |
One JSON object per line, or text, on stderr. |
log.level |
error, warn, info, debug or trace |
unset |
One level for every target. Unset: the default directives, which are warn, with Aster's targets at info. ASTER_LOG and RUST_LOG override it. |
shutdown.grace_seconds |
int |
30 |
After the first stop signal, how long requests in flight may run before they are cut. A second signal stops the process at once. |
shutdown.ready_delay_seconds |
int |
0 |
After the first signal, readiness goes false at once, and the server keeps serving this long before it stops accepting. Set 5 behind a load balancer. |
Updates
| Key |
Type |
Default |
Effect |
disable_update_check |
bool |
false |
In a preview build, look at the update feed once at start-up and then daily, and log one line when a newer build exists. It installs nothing. true turns it off, as does ASTER_WEBDATA_UPDATE_CHECK=0. Other builds never look. See Preview builds. |
Scripts
| Key |
Type |
Default |
Effect |
scripts.ceilings |
map |
built-in ceilings |
The most any script may use, whatever its own limits: say. Keys: memoryMiB, runMs, turnMs, hostCalls, decimalCalls, recursion, stackKiB, printBytes. An omitted key keeps its built-in ceiling. |
HTTP connections
Each key below sits under http.<name>. The name is what a script's call names (connection= in Python's http.get(...), connection: in TypeScript's fetch(...)), and it is the aster_webdata.http.connection label on the outbound metrics. Connections belong to the server, so every service can use them. Virtual data sources shows one in use.
| Key |
Type |
Default |
Effect |
base_url |
string |
required |
An http or https URL with a host, no query and no credentials. A call's relative path is joined to it. |
auth.bearer_env, auth.bearer_file |
string, file |
none |
Sends Authorization: Bearer with the token. |
auth.basic |
map |
none |
Sends Authorization: Basic. Takes user, and password_env or password_file. |
auth.header |
string |
none |
The name of an API-key header. Takes value_env or value_file for its value. |
timeout_ms |
int |
30000 |
The most a call may take, retries and waits included. A call may set its own. The request's deadline is the outer bound. |
retries |
int |
2 |
Attempts after the first. The engine retries on a connection error, 429, 502, 503 or 504, for GET, HEAD, PUT, DELETE and OPTIONS. A POST or PATCH is retried only when the call asks. Waits are exponential with jitter, from 100 ms doubling to at most 10 s, or the Retry-After the server sent. |
rate_limit.per_second |
number |
none |
Calls per second, as a token bucket shared by every call on the connection in the process. A call waits for its token. |
rate_limit.burst |
int |
per_second, at least 1 |
The size of the bucket: the calls that may go at once after a quiet spell. |
headers |
map |
none |
Headers sent on every call. A call's own headers win. The credential's header cannot be set here. |
ca_file |
file |
Mozilla roots |
PEM certificates to verify the server with instead of the Mozilla roots. |
max_response_bytes |
int |
10485760 (10 MiB) |
A larger response ends the call with HttpResponseTooLarge. |
An auth block takes exactly one form, and the credential is never written inline. A variable named by *_env is read at start-up, and an unset one stops the start-up. A file named by *_file is read at start-up and again on every call, so a rotated secret takes effect without a restart. Scripts never see the value. An unknown key under http.<name> is a start-up error, as everywhere in the file.
http:
tracker:
base_url: http://127.0.0.1:8090/api/v1
auth:
bearer_env: TRACKER_TOKEN
timeout_ms: 10000
retries: 3
rate_limit:
per_second: 10
burst: 20
headers: {Accept: application/json}
Explain
| Key |
Type |
Default |
Effect |
explain.enabled |
bool |
false |
Serves the x-aster-explain header. Off, the x-aster-explain-request header and the aster.explain query option are ignored. |
explain.role |
string |
none |
Only a caller whose roles include this one gets the header. Unset, any caller does, which suits local development. |
See The explain header.
Observability and health
The observability values come from the file, and the environment overrides them.
| Key |
Type |
Default |
Effect |
observability.service_name |
string |
aster-webdata |
Service name on exported telemetry. Environment: OTEL_SERVICE_NAME. |
observability.disabled |
bool |
unset |
Turns the telemetry pipeline off. Environment: OTEL_SDK_DISABLED. |
observability.traces_exporter |
otlp, prometheus or none |
unset (no export) |
Environment: OTEL_TRACES_EXPORTER. |
observability.metrics_exporter |
otlp, prometheus or none |
unset (no export) |
Environment: OTEL_METRICS_EXPORTER. |
observability.logs_exporter |
otlp or none |
unset (no export) |
Environment: OTEL_LOGS_EXPORTER. |
observability.otlp_endpoint |
string |
none |
Environment: OTEL_EXPORTER_OTLP_ENDPOINT. Put credentials in OTEL_EXPORTER_OTLP_HEADERS, from a secret store, never in this file. |
observe.plan_shapes |
on or off |
on |
Counts and times each read by its plan shape. off makes the request path skip this work. See Metrics and logs. |
observe.max_plan_shapes |
int, 1 to 100000 |
1000 |
Most shapes tracked separately per service. Others are counted together as _other. |
health.port |
int |
none |
Separate listener for /healthz, /readyz and /metrics, and for /shapes, which only this listener serves. Absent: the first three share the OData port. |
health.host |
string |
127.0.0.1 |
Address of the separate listener. Environment: ASTER_HEALTH_HOST. |
health.enabled |
bool |
true |
false turns /healthz, /readyz and /metrics off. |
health.ping_interval_seconds |
int |
5 |
Seconds between background pings of each database that is up. |
The health port also reads ASTER_HEALTH_PORT, which overrides health.port.
Environment variables
The server reads these names directly. The file's keys can name others: url_env, password_env and auth.jwt.secret_env each name the variable they read.
| Variable |
Effect |
ASTER_LOG |
Log filter directives. Overrides RUST_LOG and log.level. |
RUST_LOG |
Log filter directives, used when ASTER_LOG is unset. |
ASTER_HEALTH_PORT, ASTER_HEALTH_HOST |
Override health.port and health.host. |
ASTER_WEBDATA_REQUIRE_DATABASES |
1 or true, or 0 or false. Overrides startup.require_databases. |
ASTER_WEBDATA_RESIDUAL_ROWS |
A positive integer. Sets limits.residual_rows when the configuration file does not. |
ASTER_WEBDATA_MAX_INSERT_ROWS |
A positive integer. Sets limits.max_insert_rows when the configuration file does not. |
ASTER_WEBDATA_MAX_QUEUE_OPS |
A positive integer. Sets limits.max_batch_size when the configuration file does not. |
ASTER_WEBDATA_UPDATE_CHECK |
0 turns off the preview build's look at the update feed, whatever disable_update_check says. |
ASTER_WEBDATA_REQUIRE_TLS |
1 or true, or 0 or false. Overrides startup.require_tls. |
OTEL_SDK_DISABLED, OTEL_SERVICE_NAME, OTEL_TRACES_EXPORTER, OTEL_METRICS_EXPORTER, OTEL_LOGS_EXPORTER, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS |
Telemetry export. Each has an observability key, and the environment wins over the file. |