Start with one full-read source
The base interface is intentionally small:Configure can therefore keep a client,
connection pool, or parsed configuration on the struct, and Teardown releases
it when the run ends.
Extract is where data crosses into Filament. This minimal example writes two
columns for every requested resource:
Null() for a null value. EndRow closes the row and may block while a
full batch waits for the sink; returning its error is how backpressure and
pipeline failures reach the source.
The pipeline closes builders after extraction. A source normally calls neither
Close nor Drain; those are lifecycle details for advanced resumable or CDC
sources. A long-lived stream may call Flush when it goes idle and needs to
send a partially filled batch.Resources and parts
A builder belongs to one(resource, part) pair. Most sources start with part
0. A source that splits a large table into independently read ranges opens
one builder per range and assigns each a stable part number.
ExtractOpts.Parallelism is the run’s concurrency budget, not an instruction
to create that many parts. The source decides whether its backend can safely
read in parallel. Each builder must be written by only one goroutine.
Row metadata for recovery and CDC
Most full-read sources can pass an emptyRowMeta. Recovery and CDC sources use
it to carry information that travels with a row without becoming a
destination column:
Opis insert, update, or delete. Full reads normally leave it at insert.Keyis the source position for a keyset-resumable part.Coarsemarks progress that can only be acknowledged by row count.LSNandSeqorder a CDC stream.
Describe and register the source
Spec supplies the catalog name, configuration fields, and supported read
policies. Keep the advertisement aligned with behavior: advertising incremental
or CDC support does not implement the corresponding extraction interfaces.
Register a factory so each run receives a fresh instance:
alpha, then
raise maturity when the connector has been exercised end to end.
Add capabilities deliberately
A useful next step isDiscoverable, which lets users browse resources before
creating a pipeline. A SchemaProvider is required when the source must feed a
schema-aware sink.
Resume, incremental reads, and CDC require several contracts to work together;
they are not single-interface switches. See
Optional interfaces
for those capability sets.
The repository’s connectors/sample
package is the smallest complete source. It demonstrates the same builder flow
without an external dependency.
OAuth tokens
The rootoauth package handles client credentials and refresh-token grants.
It refreshes on demand and exposes Token(ctx) to Go drivers. HTTP manifests
use the same implementation. Browser authorization and callback handlers are
outside this package.
Bind a run-scoped store to an existing connection refresh-token secret. The
provider must implement filament.SecretRotator. PostgreSQL, SQLite, AWS and
GCP providers support it.
oauth.TokenSource interface. For an HTTP
source, call source.SetOAuthStore(store) before Configure or TestConnection.
This is an explicit Go integration hook.
A driver can implement oauth/secrets.Configurable to identify its saved
refresh-token field and authorization settings. The runner binds that secret
through oauth/secrets.Bind before source configuration. Binding performs no
secret reads or exchanges. Unsaved connection validation must not exchange
rotating tokens.
The store loads the refresh token on first use and keeps access tokens and
expiry in memory for that run. Only a changed refresh token is written back.
PostgreSQL and SQLite use an encrypted update of the existing secret row. AWS
uses PutSecretValue. GCP uses AddSecretVersion and destroys the previous
version. Rotation never creates a secret or updates the connection row.
Refreshes serialize within the store. Separate runs have independent token
state. No database transaction spans a token request and no coordination table
is required. Token requests default to a 30-second timeout.
Use oauth.NewMemoryStore for temporary credentials or tests. The environment
provider is read-only and cannot persist rotating tokens. Other integrations can
implement oauth.Store or use oauth.StoreFunc.
A returned token is available only after any refresh-token write succeeds. A
failed save retains the exchange in memory for another save attempt without
exchanging the consumed token again. A process exit between upstream rotation
and persistence can require fresh authorization.
Check errors.Is(err, oauth.ErrReauthorizationRequired) for an expired or revoked
refresh grant. Endpoint errors expose HTTP status and an allowlisted OAuth code,
without provider descriptions or raw responses. Token requests do not retry
automatically. The HTTP adapter’s optional retry policy accepts explicit
temporary rejections and avoids retrying ambiguous transport failures.
Use the connection’s existing secret lifecycle when removing an authorization. Provider-side revocation remains a separate operation. Token values
must never appear in logs, events, ordinary connection config or API responses.