Use casesData teamsLegacy databases09 / 12
How it fits together

The same governed front, with the vendor's own driver behind it

QueryAPIGate loads the vendor's JDBC driver into a JVM in its own process, so nothing is installed on the database. Keys, limits, quotas, caching and audit work as for any connection. Where it can't check something on JDBC (column masking, table allow-lists), it refuses the caller rather than serving them unfiltered. The database user you give it, read-only, is the real safeguard.

3fields: the jar, its class, a JDBC URL
0things installed on the database
1read-only user, the real safeguard
Who asks
The governed core
An embedded JVM, in the server's process
The database you don't change
↗ Procurement app queries: open_purchase_orders 200 · text/csv · streamed
↗ Supplier portal mask: SUPPLIERS.BANK_ACCOUNT 403 mask_unresolvable
↗ An analyst connections: [erp] 403 read_only
The governed coreGET /q/<name> · POST /execute_sql↗

01 · Grant

Keys, rate limits and quotas, as on every connection.

procurement ✓ 429 rate_limited

02 · SQL guard

One read-only statement. On JDBC, the only write check QueryAPIGate makes.

SELECT ✓ 403 read_only

03 · Masking

Can't be traced on JDBC: a caller with rules is refused, never served unmasked.

no rules ✓ 403 mask_unresolvable
↗ As on every connection
saved queriesrate limitsquotascache_ttlstreaming exportsrun historyaudit log
↗

Embedded JVMExp

the -h2 image includes Java
ojdbc11.jar oracle.jdbc.OracleDriver jdbc:oracle:thin:@// erp-db.internal:1521/ERP
pool · idle connections kept and reused Classpath fixed when the JVM starts: a new jar needs a restart. Columns come back as the driver names them: PO_ID.
↗

Oraclenothing installed

erp-db.internal:1521/ERP user api_readonly · SELECT only the real safeguard
PURCHASE_ORDERS SUPPLIERS INVOICES GL_ENTRIES
statement timeout · set it here Or SQL Server, DB2, Snowflake: any database with a JDBC driver.
On a jdbc connectionwhere it can't check, it refuses
Refused, never weakened mask rules → 403 mask_unresolvable allowed_tables → 403 table_check_unsupported schema browser → 400 unsupported_operation Yours to set a database user that can only read a statement timeout in the database
Expmay change in a minor release Tested in CI with H2's driver standing in for a vendor. The full comparison is in the support matrix →
Who asksApps, partners, analystsThe same keys, limits and quotas as on any connection.
The governed coreGrant → SQL guard → maskingA write is refused. A caller with mask rules is refused too: on JDBC masking can't be traced, so nothing is served unmasked.
An embedded JVM ExpThe vendor's own driverA jar, its class and a JDBC URL, in the server's process. A new jar needs a restart.
The database you don't changeNothing installed on itGive it a user that can only read, and a statement timeout of its own.
Refused, or yours to setMasking, table allow-lists, schema browsing: refusedA read-only user and a statement timeout: set in the database.

The same governed core as the full architecture.

For legacy and vendor databasesEXPERIMENTAL

Put a governed API in front of a database you can't change

The core system runs on Oracle, SQL Server or DB2, and nobody wants to touch it. Generic JDBC loads the vendor's own driver, so that data can be served through saved queries with the same keys, limits, quotas and audit as any other connection.

✓A jdbc connection takes the vendor's driver .jar, its driver class and a JDBC URL. Run the image's -h2 variant, which includes Java.
✓Saved queries, grants, rate limits, quotas, caching, run history and the audit log work as on every other connection. Column masking and table allow-lists can't be checked on JDBC, so a caller with them is refused, never served unfiltered.
✓Known limits, verified: no query time limit (set one in the database), and no table allow-lists or schema browser on JDBC connections.
✓Experimental: CI tests JDBC with H2's driver standing in for a vendor. Connect with a database user that can only read.
Legacy databases
# the vendor's driver, its class and a JDBC URL
curl -X POST https://data.example.com/api/v1/connections \
  -H 'X-API-Key: <admin>' -H 'Content-Type: application/json' -d '{
  "name": "erp", "db": "jdbc", "active": true,
  "jar": "/opt/jdbc/ojdbc11.jar",
  "driver_class": "oracle.jdbc.OracleDriver",
  "jdbc_url": "jdbc:oracle:thin:@//erp-db.internal:1521/ERP",
  "user": "api_readonly", "password": "${ERP_PASSWORD}"
}'

# then saved queries and keys, as anywhere else
GET /q/open_purchase_orders?supplier=ACME
X-API-Key: sk_live_…procurement
More use casesAll twelve →

Not sure which fits?

The example APIs ship with a generated database and one scoped key per scenario, so you can try each of these in a few minutes without connecting anything of your own.

Run the examplesCompare alternatives