Skip to content

gRPC API reference

Generated from proto/axiom/v1/axiom.proto. Edit that file and run make docs-generate; CI fails on an uncommitted difference.

Package axiom.v1. All calls are TLS-only; credentials are never message fields.

Service GatewayService

GatewayService is the cluster-side service the Postgres extension talks to.

RPC Request Response
Ping PingRequest PingResponse
Get GetRequest GetResponse
List ListRequest ListResponse
Create CreateRequest CreateResponse
Update UpdateRequest UpdateResponse
Delete DeleteRequest DeleteResponse
Subscribe SubscribeRequest stream of SubscribeResponse
DiscoverSchema DiscoverSchemaRequest DiscoverSchemaResponse
ListKinds ListKindsRequest ListKindsResponse
Stats StatsRequest StatsResponse

Ping

rpc Ping(PingRequest) returns (PingResponse);

Ping is a liveness round-trip used by the extension's background worker to verify connectivity and TLS setup. The gateway echoes the caller's nonce so the caller can detect a mismatched/out-of-order reply, and reports its own version and clock for diagnostics.

Errors: INVALID_ARGUMENT if the request nonce is zero (zero is reserved as "unset" so accidental default-constructed requests are rejected loudly).

Get

rpc Get(GetRequest) returns (GetResponse);

Get fetches a single object by kind, namespace and name, straight from the API server (never from a cache).

Errors: INVALID_ARGUMENT for an unsupported/malformed gvk or an invalid namespace/name; NOT_FOUND if the object does not exist; PERMISSION_DENIED if the gateway's own RBAC identity may not read it; FAILED_PRECONDITION if the gateway has no cluster configured; UNAVAILABLE if the API server cannot be reached.

List

rpc List(ListRequest) returns (ListResponse);

List fetches objects of one kind, optionally narrowed to a namespace and/or a single name. Filters are applied server-side (namespace scoping and a metadata.name field selector), never by fetching everything and filtering in the gateway.

Errors: as for Get, except that a filter matching nothing is an empty response, not NOT_FOUND.

Create

rpc Create(CreateRequest) returns (CreateResponse);

Create creates one object from its JSON body. The gateway forces apiVersion/kind from gvk and requires body metadata.name/namespace (if present) to equal the request fields.

Errors: INVALID_ARGUMENT for an unsupported gvk, invalid names, a body that is not a JSON object or whose identity disagrees with the request, or a body the API server rejects as invalid; ALREADY_EXISTS if an object with that name exists; PERMISSION_DENIED / FAILED_PRECONDITION / UNAVAILABLE as for Get.

Update

rpc Update(UpdateRequest) returns (UpdateResponse);

Update replaces one object (HTTP PUT) with optimistic concurrency: the request must carry the resource_version the caller last read, and the API server rejects the write if the object has changed since.

Errors: INVALID_ARGUMENT if resource_version is empty or the body/identity is invalid (as for Create); ABORTED if the resource_version is stale (HTTP 409 Conflict) so callers can distinguish "retry after re-read" from every other failure; NOT_FOUND if the object no longer exists; PERMISSION_DENIED / FAILED_PRECONDITION / UNAVAILABLE as for Get.

Delete

rpc Delete(DeleteRequest) returns (DeleteResponse);

Delete deletes one object by name.

Errors: INVALID_ARGUMENT for unsupported gvk / invalid names; NOT_FOUND if it does not exist; PERMISSION_DENIED / FAILED_PRECONDITION / UNAVAILABLE as for Get.

Subscribe

rpc Subscribe(SubscribeRequest) returns (stream SubscribeResponse);

Subscribe streams the current state and then live changes of one kind, optionally narrowed to a namespace. This is the feed behind the extension's shared-memory cache; one stream per (cluster, kind, namespace) is held open by the extension's background worker.

Without resource_version the gateway performs a full LIST and emits every object as ADDED with an EMPTY resource_version (a partial listing is not a valid resume point), then a SYNCED event carrying the list's resourceVersion, then live ADDED/MODIFIED/DELETED events and BOOKMARK events. With a resource_version the gateway resumes the watch from that point and sends no initial listing and no SYNCED: the backlog since the bookmark is delivered as ordinary events, and the API server's first BOOKMARK (which it only sends once the watcher is caught up) is the caller's signal that the cache is current again. If the API server no longer has that history (HTTP 410 Gone) the gateway emits RESYNC_REQUIRED and ends the stream, and the caller must resubscribe without a resource_version and rebuild its cache.

Errors: INVALID_ARGUMENT for unsupported gvk / invalid namespace; PERMISSION_DENIED / FAILED_PRECONDITION / UNAVAILABLE as for Get. Once streaming, transient watch drops are handled inside the gateway by re-watching from the last seen resourceVersion; the stream only ends on RESYNC_REQUIRED, a non-retryable error, or client cancellation.

DiscoverSchema

rpc DiscoverSchema(DiscoverSchemaRequest) returns (DiscoverSchemaResponse);

DiscoverSchema resolves one kind against the cluster's discovery and OpenAPI documents and returns the foreign-table shape the extension should use for it. It is called at IMPORT FOREIGN SCHEMA time, never on the scan path: the generated DDL carries the resolved identity in table options, so a scan needs no discovery round-trip.

The columns returned are the promoted metadata scalars, the kind's own top-level object fields (spec/status/data/...), and raw — see docs/DESIGN.md §5.4. The gateway only decides which columns exist; how a column is read out of an object is fixed by the extension's projection rule, so the two sides cannot disagree about a column's value.

Errors: INVALID_ARGUMENT for a malformed gvk; NOT_FOUND if the cluster has no such kind; PERMISSION_DENIED if serving it is outside the gateway's configured allowlist or its own RBAC; FAILED_PRECONDITION if the gateway has no cluster configured; UNAVAILABLE if the API server cannot be reached.

ListKinds

rpc ListKinds(ListKindsRequest) returns (ListKindsResponse);

ListKinds enumerates the kinds this gateway is configured to serve, optionally narrowed to one API group and/or an explicit set of plural names. It backs IMPORT FOREIGN SCHEMA, which needs every kind's shape in one round-trip rather than one DiscoverSchema call per table.

The result is bounded by the gateway's serve allowlist, so it describes what this deployment offers, not everything the cluster has. A kind the allowlist permits but the API server does not have is omitted rather than reported as an error.

Errors: INVALID_ARGUMENT for a malformed filter; FAILED_PRECONDITION if the gateway has no cluster configured; UNAVAILABLE if the API server cannot be reached.

Stats

rpc Stats(StatsRequest) returns (StatsResponse);

Stats reports monotonic counters for the work this gateway process has done since it started, plus when that was.

It exists because counting is the only honest way to assert things like "the cache served that scan without touching the API server" or "the resumed watch did not relist". Those were asserted by grepping the gateway's stdout, which does not survive the process being restarted -- and a restart mid-watch is exactly the scenario worth testing. Counters reset with the process, which makes "since you came back, how many listings have you done" directly expressible.

Operationally it answers "what is this gateway actually doing", which is otherwise only visible by reading logs.

Errors: none beyond transport. Deliberately cheap and side-effect free, so it is safe to poll.

Enums

SqlType

SqlType is the Postgres type a discovered column is declared with.

A field is typed only when its OpenAPI schema names exactly one scalar type (docs/DESIGN.md §5.4, #79); anything structured or ambiguous is jsonb. The declared type is what the extension converts each value to and from.

BIGINT, BOOLEAN and TIMESTAMPTZ are sent only to a caller that sets typed_columns on its request. An extension that predates them maps an unknown value to "no column" and would silently drop the column from the table it generates, so it gets TEXT and JSONB as before.

Value Number Description
SQL_TYPE_UNSPECIFIED 0 —
SQL_TYPE_TEXT 1 —
SQL_TYPE_JSONB 2 —
SQL_TYPE_BIGINT 3 —
SQL_TYPE_BOOLEAN 4 —
SQL_TYPE_TIMESTAMPTZ 5 —

SubscribeResponse.Type

Value Number Description
TYPE_UNSPECIFIED 0 —
TYPE_ADDED 1 Object exists (initial listing) or was created.
TYPE_MODIFIED 2 Object changed.
TYPE_DELETED 3 Object was deleted; object carries its last known state.
TYPE_SYNCED 4 The initial listing is complete and the cache is current; resource_version is the list's.
TYPE_BOOKMARK 5 No change; resource_version advances the resume point. The API server emits bookmarks only for a caught-up watcher, so on a resumed stream the first BOOKMARK also means "current again".
TYPE_RESYNC_REQUIRED 6 The requested resource_version is too old (410 Gone). The stream ends after this event; resubscribe without a resource_version.

Messages

ColumnSchema

ColumnSchema is one column of a kind's foreign table.

Field Type Description
name string SQL column name. Always a lowercase identifier that needs no quoting; the extension quotes it anyway when generating DDL (docs/RULES.md §3).
sql_type SqlType —
source string Origin of the column, e.g. "metadata.name" or "spec". For a column the extension maps to a top-level field, it is that field's exact name, e.g. "stringData": IMPORT FOREIGN SCHEMA records it as the column's field option, which an INSERT needs to write the field under its real spelling (#97). For any other column it is diagnostics only.

CreateRequest

Field Type Description
gvk GroupVersionKind —
namespace string —
name string —
json bytes Full object as JSON. apiVersion/kind are overwritten from gvk.

CreateResponse

Field Type Description
object Object The object as stored by the API server (with uid, resourceVersion, defaults).

DeleteRequest

Field Type Description
gvk GroupVersionKind —
namespace string —
name string —

DeleteResponse

No fields.

DiscoverSchemaRequest

Field Type Description
gvk GroupVersionKind —
typed_columns bool The caller understands SQL_TYPE_BIGINT, SQL_TYPE_BOOLEAN and SQL_TYPE_TIMESTAMPTZ. Unset, every column is TEXT or JSONB, as it was before those existed.

DiscoverSchemaResponse

Field Type Description
schema KindSchema —

GetRequest

Field Type Description
gvk GroupVersionKind —
namespace string Required for namespaced kinds, must be empty for cluster-scoped kinds.
name string —

GetResponse

Field Type Description
object Object —

GroupVersionKind

GroupVersionKind identifies a Kubernetes resource kind. Group is empty for the core API group.

Field Type Description
group string —
version string —
kind string —

KindSchema

KindSchema is everything the extension needs to define and serve a foreign table for one kind.

Field Type Description
gvk GroupVersionKind —
plural string Plural resource name as it appears in the REST path, e.g. "pods", "widgets". This is the resource table option.
namespaced bool False for cluster-scoped kinds, whose objects have no namespace.
columns repeated ColumnSchema —
writable bool True when the API server advertises create/update/delete verbs for the kind. This reflects what the API supports, not what the gateway's RBAC identity is permitted to do: a write may still be denied at execution.
watchable bool True when the API server advertises the watch verb, so a cache_mode 'watch' table is possible for this kind.

ListKindsRequest

Field Type Description
plurals repeated string If non-empty, only kinds whose plural name appears here. Names that match nothing are silently absent from the response rather than an error, so a caller can pass a speculative list.
typed_columns bool As DiscoverSchemaRequest.typed_columns.

ListKindsResponse

Field Type Description
kinds repeated KindSchema —

ListRequest

Field Type Description
gvk GroupVersionKind —
namespace string Empty means all namespaces.
name string If non-empty, only the object with exactly this name is returned (server-side metadata.name field selector).
limit int32 Maximum objects in one response. Zero asks the gateway to choose. The gateway clamps this to its own maximum, so a caller cannot use it to demand a response too large to send. A page is bounded by bytes as well as by count, because objects vary by three orders of magnitude: a count that is comfortable for Pods can exceed the message limit for ConfigMaps holding a megabyte each.
continue_token string Continues a previous List. Pass back the continue_token from the last response; empty starts a new listing. The token is the gateway's, not the API server's: it wraps the Kubernetes continuation together with the page size settled for this walk, and is not usable against Kubernetes directly. Treat it as opaque. It carries a snapshot, so it expires when that snapshot is compacted. Resuming an expired one fails with ABORTED rather than silently restarting, because earlier pages have already been returned to the caller and restarting would duplicate them.

ListResponse

Field Type Description
objects repeated Object —
resource_version string resourceVersion of the list itself, usable as a watch start point.
continue_token string Non-empty when more objects remain: pass it as the next request's continue_token, unchanged. Empty means this was the last page. Opaque, and issued by the gateway rather than by Kubernetes.

Object

Object is one Kubernetes object as returned by the API server.

Field Type Description
namespace string metadata.namespace; empty for cluster-scoped kinds.
name string metadata.name.
resource_version string metadata.resourceVersion, opaque; carried for Phase 2 optimistic concurrency and Phase 3 watch bookmarks.
json bytes The full object as JSON, exactly as serialised by the API server. The receiver must treat this as untrusted input and bounds-check it.

PingRequest

Field Type Description
nonce uint64 Caller-chosen, non-zero. Echoed back verbatim in PingResponse.nonce.

PingResponse

Field Type Description
nonce uint64 Echo of PingRequest.nonce.
gateway_version string Gateway build version string (e.g. "0.1.0" or a git describe).
server_time google.protobuf.Timestamp Gateway wall-clock time at the moment the reply was built.

StatsRequest

No fields.

StatsResponse

StatsResponse carries counters for one gateway process. Every counter is monotonic within a process lifetime and resets when it restarts; started_at_unix_seconds is how a caller tells a restart from a quiet period.

Field Type Description
started_at_unix_seconds int64 Wall-clock time the process started, for detecting a restart.
get_calls uint64 Unary RPCs served, by kind of call.
list_calls uint64 —
create_calls uint64 —
update_calls uint64 —
delete_calls uint64 —
subscribe_calls uint64 Subscribe streams opened, and how many of those performed a full initial listing rather than resuming from a bookmark. A resume that relists shows up here as an increment the caller did not expect.
subscribe_list_calls uint64 —
openapi_fetches uint64 Discovery: OpenAPI documents fetched and parsed, and how many distinct group-versions those covered. Serving a whole cluster should fetch one document per group-version, not one per kind.
openapi_group_versions uint64 —
access_reviews uint64 Access reviews issued against the authorization API while deciding which kinds this gateway may serve.

SubscribeRequest

Field Type Description
gvk GroupVersionKind —
namespace string Empty means all namespaces.
resource_version string Empty means "list everything first"; otherwise resume the watch from here.

SubscribeResponse

SubscribeResponse is one watch event.

Field Type Description
type Type —
object Object Present for TYPE_ADDED/TYPE_MODIFIED/TYPE_DELETED.
resource_version string Present for TYPE_SYNCED/TYPE_BOOKMARK and, when known, for TYPE_RESYNC_REQUIRED, and for live TYPE_ADDED/MODIFIED/DELETED events. Empty on initial-listing TYPE_ADDED events: never resume from those.

UpdateRequest

Field Type Description
gvk GroupVersionKind —
namespace string —
name string —
resource_version string Required. The metadata.resourceVersion the caller last read.
json bytes Full replacement object as JSON. metadata.resourceVersion inside the body, if present, must equal resource_version.

UpdateResponse

Field Type Description
object Object —