Connectors
This page documents how the connector engine discovers schema at runtime, manages the connector registry and gates permissions. For task-oriented walkthroughs — create a query, clone a connector, scaffold a sequence or a lookup — see Build → Queries and Build → Menus → Make a connector an app.
A connector is the bridge between the framework and a data source — a database, an HTTP API, or a third-party service. Connectors are created and edited from Settings → Connectors, one entry per source. Every screen, dashboard, chart, job step and AI tool that needs data names a connector to use.
The framework supports three connector types:
| Type | What it reaches | Editor |
|---|---|---|
| SQL | A relational database via a pool. Each connector groups a set of named queries — read and write. | Settings → Connectors → SQL sub-tab |
| HTTP | A REST / GraphQL endpoint. Each connector groups a set of named endpoints with method + path + auth. | Settings → Connectors → HTTP sub-tab |
| API | A generic remote service whose calls are dispatched to either SQL or HTTP under the hood (compatibility variant). | Settings → Connectors → API sub-tab |
The schema of every read query / endpoint response is discovered at runtime — the framework asks the database or the API "what columns / fields does this return?" on first use and caches the answer. No column type, length or position is ever typed by hand.
At a glance
The catalogue — Settings → Connectors
The page lists every connector on the install. Each row shows the connector type, the pool / base URL, the connection status (a live probe) and the number of declared queries / endpoints.
Toolbar filters narrow the list by App and Type. + New connector opens the editor on a blank entry; clicking any row opens the editor on that connector.
| Status pill | Meaning |
|---|---|
| connected | The live probe to the pool / base URL succeeded within the last 30 seconds. |
| offline | The probe failed. The connector still appears, but every query against it will fail until the source comes back. |
| licensed (badge) | Marked with Licensed = true. Only loads when the license key carries it. |
The connector editor
Clicking a row opens a three-tab editor on the right. The tabs are the same for every type, but each tab's content adapts to the picked Type.
| Tab | Purpose |
|---|---|
| Connection | How the framework reaches the source — pool / base URL, authentication, common headers. |
| Queries / Endpoints | The named queries (SQL) or endpoints (HTTP/API) that callers reference. |
| Permissions | Read-only summary — which permission codes this connector generates, who currently carries them. |
SQL connector
Connection fields
| Field | Effect |
|---|---|
| Name | Identifier used everywhere — the URL, the permission code (sql:<name>:*), the AI tool name. Short, kebab-case. |
| App | Dropdown of registered apps. Drives the connector's namespace and the workspace it appears in. |
| Type | SQL here. Changing the type re-shapes the form. |
| Pool | Dropdown of pools defined under Settings → Pools. The connector inherits the pool's URL, credentials and dialect. |
| Description | Free text. Shown on the catalogue, as the tooltip on screens that pick this connector, and — crucially — in the AI assistant tool description. A two-sentence summary in the user's language goes a long way. |
| Licensed | When on, the connector loads only when the license key lists its identifier. Used by Nomana-IT to gate vendor connectors; customer connectors leave it off. |
| Expose to AI assistant | When on, the connector's read queries become tools the AI assistant can pick. Write queries are excluded by default. See AI assistant. |
The Test connection button (top right) hits the pool with a SELECT 1 and reports success / failure inline — useful to confirm the pool is reachable before adding queries.
Query editor
Clicking + Add query or an existing row opens the query editor:
| Field | Effect |
|---|---|
| Name | Identifier of the query — surfaces in the URL (/api/sql/billing/<name>), the permission code (sql:billing:<name>) and the AI tool name. |
| Label | Human display label — appears in the menu builder picker, screen builder picker, etc. |
| Operation | Read / Write. Write queries get the :write suffix on their permission code. |
| SQL | The query body. A Monaco editor with SQL syntax highlighting, schema-aware autocomplete (column names from the pool), and parameter highlighting (:name placeholders). |
| Dialect overrides | Optional per-dialect variants (oracle, postgresql, sqlite) for cases where the canonical SELECT doesn't translate. The framework picks the right one based on the pool's dialect. |
| Description | Two-sentence summary. Shown on the screen builder pickers and in the AI assistant tool description. |
| Parameters | Sub-table — see Parameter binding for every field. |
| Column hints | Optional sub-table. Each row binds a result column to a dictionary entry: Column (dropdown of columns the Test button discovered) + Dictionary (dropdown of dictionary entries). Drives labels, formats, enums, lookups. Columns without a hint fall back to the column name as the label. |
The ▶ Test button at the top of the editor runs the query against the live pool with placeholder values for the parameters and shows the first 50 rows. The first successful test populates the Column hints dropdown with the discovered columns; subsequent tests refresh it.
The framework uses the discovered schema to:
- Build grid columns on screens.
- Validate column hints (a hint pointing at a column that no longer exists is flagged red).
- Type-coerce parameter values before binding.
- Feed the AI assistant's tool schema with the right field shapes.
HTTP connector
The form re-shapes when Type is set to HTTP. The pool dropdown disappears; a Base URL + Authentication block takes its place.
| Field | Effect |
|---|---|
| Base URL | Origin of the API (e.g. https://crm.example.com). The endpoints below are appended to this. |
| Authentication | None / Basic / Bearer / OAuth2. Each picks a sub-form. Basic asks for user + 🔒 password; Bearer takes a 🔒 token; OAuth2 asks for the token endpoint, client id, 🔒 client secret and the scope list. |
| Headers | Common headers applied to every endpoint — e.g. a static User-Agent or an X-Tenant. |
| Default timeout | Seconds before a call is aborted. Default 30. |
The endpoints sub-table replaces the SQL queries:
| Field | Effect |
|---|---|
| Name | Endpoint identifier — surfaces in the URL (/api/http/<connector>/<name>), the permission code (api:<connector>:<name>) and the AI tool name. |
| Label / Description | Same as for SQL queries. |
| Method | GET / POST / PUT / PATCH / DELETE. |
| Path | Path appended to the base URL. Supports :name placeholders bound from parameters. |
| Body template | For non-GET methods, a JSON template. Supports ${name} substitution from parameters. |
| Parameters | Same shape as for SQL — see Parameter binding. |
| Response shape | Auto-detected when the Test button is used; the operator can refine the discovered shape (rename keys, group nested fields) to align it with what consumers expect. |
The ▶ Test button issues the call live with the configured authentication and parameter defaults; the response body is shown formatted, with the discovered shape surfaced as chips below.
API connector
API is a hybrid type kept for compatibility with installs that route some calls to SQL and others to HTTP under a single connector name. The editor exposes both Queries and Endpoints sub-tables; the Operation field on each entry picks the underlying engine.
In a new install you'll almost always pick SQL or HTTP directly. API is the path when consolidating multiple legacy connectors under one umbrella.
Schema discovery and column hints
A read query has no manually-declared column list. On first call (or when the operator clicks Test), the framework executes the query, looks at the cursor's column descriptions and caches them:
| Field discovered | What the framework records |
|---|---|
| Column name | Used as the default label when no dictionary hint applies. |
| Database type | Drives the type-coercion of parameter values on subsequent calls. |
| Nullable / not nullable | Used by screens to decide whether the column gets a "required" asterisk. |
| Length / precision | Surfaced as constraints on the field editor (max-length on a string, max-digits on a decimal). |
The Column hints sub-table is where you override the default. A hint maps a discovered column to a dictionary entry — that's how the column gets a localised label, a boolean / enum / lookup rule, a number format, etc.
You don't have to declare a hint for every column; columns without a hint render with the raw database name and the default widget for their type.
Permissions
Every connector generates a permission code per query / endpoint:
| Code template | Granted to |
|---|---|
sql:<connector>:<query> | Run the read query. |
sql:<connector>:<query>:write | Run the write query. |
api:<connector>:<endpoint> | Call the HTTP endpoint. |
The codes appear on the Permissions tab of the connector editor and in the Permission picker of Settings → Roles. Wildcards sql:billing:* and api:crm:* are supported.
The connector itself isn't gated — what's gated is each call. A user with no permissions sees no queries; a user with sql:billing:* sees every read + write of the billing connector.
Hot-reload behaviour
A Save & reload on the connector editor rebuilds the connector registry in place — every consumer (screens, charts, dashboards, AI tools) picks up the change on its next render. Requests already in flight finish on the previous version; no abort is needed. See Hot-reload for the full contract.
Tips & best practices
- Always click Test before Save. A query that the database refuses at execution time is the most common cause of broken screens. The Test button catches it early.
- Write a good Description. It surfaces in the AI assistant, the menu builder, the screen builder — two sentences in the user's language pays for itself many times.
- Prefix queries with the entity —
invoices-list,invoices-by-status,invoice-detail. Makes the catalogue self-documenting. - Keep read and write paths separate. Don't write
INSERT INTO ... RETURNING ...as a read query; the framework's permission model gates writes separately for a reason. - Use column hints sparingly. A column that just needs its database name is fine without a hint — define hints only when the dictionary adds value (a localised label, a format, a lookup).
- Set Licensed off on customer connectors. Reserve the badge for vendor-shipped connectors that need a key.
Under the hood
Connector definitions are stored in liberty-apps/config/connectors.toml (or liberty-next/config/connectors.toml when LIBERTY_APPS_DIR is unset). Operators do not edit this file by hand in normal operation; the Connectors builder is the canonical interface. The Raw TOML tab of Settings → Connectors is the escape hatch for the rare case where the builder doesn't cover a field.
For CI scripts and external orchestrators, the same surface is reachable via REST at /admin/config/connectors/* — see REST API reference.
What's next
- Dictionary — per-column metadata: labels, formats, enums, lookups.
- Parameter binding — declared parameters, defaults, cascading filters.
- Screens — turn a connector into a grid + edit dialog.
- Charts — wrap a query into a visualisation.
- Encryption & secrets — the 🔒 toggle on passwords / tokens.