SQL-koppelingen via de API¶
Het concept achter tools staat in Tools.
Een SQL-koppeling geeft het model één vaste query op een database van je organisatie. Jij
schrijft de query bij het registreren; het model vult alleen de waarden in. Elke koppeling levert
één tool op, sql__<naam>. Core maakt zelf verbinding met je databaseserver, over TLS, met een
gebruikersnaam en wachtwoord die je één keer opslaat. Postgres, MySQL, SQL Server en Oracle worden
ondersteund.
Een SQL-koppeling stel je in via de API, zoals hieronder, of in de console onder Tools >
SQL-koppelingen. Daar voeg je er een toe op een eigen pagina, lees je de verbinding, de query en
de versies van een koppeling, bewerk je hem tot een nieuwe versie, verwijder je hem, en laat je
Core met Testen inloggen en SELECT 1 uitvoeren. Het wachtwoord zie je nooit terug; laat het
leeg bij bewerken om het opgeslagen wachtwoord te houden. Een koppeling die uit een publicatie is
geïnstalleerd, kun je daar niet bewerken of verwijderen. Je sleutel heeft de capability tooling
nodig, en de host van de databaseserver moet bij de toegestane
hosts van je organisatie staan.
Een koppeling registreren¶
curl -s -X POST "$CORE_URL/sql_connectors" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"name": "orders",
"description": "Zoekt de recente bestellingen van één klant op.",
"dialect": "postgres",
"host": "db.jouw-app.example",
"database": "shop",
"statement": "SELECT id, status, total FROM {$schema}.orders WHERE customer_id = {customer} ORDER BY created_at DESC",
"parameters": {"type": "object",
"properties": {"customer": {"type": "string", "description": "Het klantnummer"}},
"required": ["customer"]},
"install_values": {"schema": {"type": "identifier", "value": "public"}},
"max_rows": 20,
"auth": {"type": "basic", "username": "core_reader", "password": "..."}}'
Het antwoord is 201 met de koppeling, versie 1. Bied hem aan met
{"type": "tool", "name": "sql__orders"} in tools[], of neem hem op in een
toolset.
| Veld | Wat je invult |
|---|---|
name |
hoe het model de tool noemt (sql__<name>): kleine letters, cijfers, - en _, maximaal 48 tekens. Wijzigt na aanmaken niet meer |
description |
wat de tool doet, zoals het model het leest, maximaal 1024 tekens |
dialect |
postgres, mysql, sqlserver of oracle |
host |
de hostnaam of het adres van de server, zonder schema, poort of pad |
port |
optioneel; standaard 5432, 3306, 1433 of 1521, naar het dialect |
database |
de database; bij Oracle de servicenaam |
statement |
de ene query die de tool uitvoert, zie De query |
parameters |
een JSON Schema-object met de argumenten die het model invult |
mode |
read (standaard) of write, zie Lezen en schrijven |
max_rows |
hoeveel rijen één aanroep hoogstens teruggeeft: 1 tot 1.000, standaard 100 |
timeout |
seconden die één aanroep mag duren; Core neemt de kortste van deze en de tooltime-out van de installatie, 30 seconden tenzij je operator een andere instelde |
tls, ca_pem |
hoe Core het certificaat van de server controleert, zie TLS |
install_values |
waarden die je één keer vastlegt, zie De query |
call_variables |
waarden die je applicatie per verzoek meestuurt, zie De query |
auth |
{"type": "basic", "username", "password"}; een andere soort is er niet |
region, labels, background, metadata |
zoals bij een API-koppeling, zie verderop |
Het wachtwoord wordt versleuteld opgeslagen en nooit teruggegeven: GET antwoordt met de soort
en de gebruikersnaam en has_secret. Geef Core een databasegebruiker die precies mag wat de query
nodig heeft, en voor een leestool een gebruiker die niet kan schrijven.
GET /sql_connectors toont de koppelingen van je organisatie, GET /sql_connectors/{id} er één,
PATCH wijzigt er een en DELETE verwijdert er een. Verwijderen geeft 409 met de namen van de
agents zolang de nieuwste versie van een agent de tool noemt; haal hem daar eerst weg.
De query¶
De query ligt vast; het model kiest alleen waarden. In statement staan drie soorten
plaatshouders:
| Plaatshouder | Wie de waarde geeft | Voorbeeld |
|---|---|---|
{naam} |
het model, als argument uit parameters |
WHERE customer_id = {customer} |
{$naam} |
jij, één keer, in install_values |
FROM {$schema}.orders |
{@naam} |
je applicatie, per verzoek, in tool_variables |
AND tenant = {@account} |
Core geeft elke waarde als gebonden parameter aan de driver, nooit als stuk SQL-tekst. Een
waarde in een argument kan de query dus niet veranderen, wat er ook in staat. Daarom mag een
plaatshouder alleen staan waar een waarde hoort: na een operator, een komma, een haakje of een
woord als WHERE, VALUES of LIMIT.
De enige uitzondering is een invulwaarde van het type identifier: de naam van een schema, een
tabel of een kolom. Core schrijft die in de query, gequote volgens de regel van het dialect.
Alleen jij zet zo'n naam, nooit het model. In Oracle behoudt een gequote naam zijn
hoofdletters, dus schrijf hem zoals de server hem bewaart, meestal in hoofdletters.
Een invulwaarde is een object {type, value, allowed, description} met als type string,
number, enum (met allowed) of identifier. Elke {$naam} heeft een waarde nodig en elke
waarde moet in de query staan. Een invulwaarde is geen geheim; het wachtwoord hoort in auth.
Aanroepvariabelen declareer je in call_variables zoals bij een API-koppeling, en je applicatie
stuurt hun waarden in tool_variables op het verzoek (Een modelaanroep doen).
Het model ziet ze nooit. Een optionele variabele zonder waarde en zonder standaard wordt NULL;
een verplichte die het verzoek weglaat, geeft 400 op tool_variables.<naam>.
Een optioneel argument dat het model weglaat, wordt ook NULL. Ontbreekt een verplicht argument,
dan draait er niets en leest het model Tool arguments were missing a required value.
Core weigert bij het registreren, met 422 op statement:
- meer dan één statement;
- een plaatshouder in een tekstwaarde, een gequote naam of commentaar, of waar een naam hoort;
- een plaatshouder die
parameters,install_valuesofcall_variablesniet declareert; - een invulwaarde die de query niet gebruikt. Een aanroepvariabele die de query niet gebruikt,
wordt ook geweigerd, met
422opcall_variables; een argument inparametersdat de query niet gebruikt, mag wel; CREATE,ALTER,DROP,TRUNCATE,RENAME,GRANT,REVOKE,COMMITenROLLBACK;- wat afhangt van instellingen van de server: in Postgres en MySQL een backslash in een
tekstwaarde, en in MySQL een
--zonder spatie erna en de commentaarvormen/*!,/*+en/*M!.
Per dialect komt daar iets bij. SQL Server weigert een GO. Oracle weigert een puntkomma aan het
eind, een PL/SQL-blok (BEGIN, DECLARE), RETURNING en een eigen bindvariabele zoals :naam.
Een argument dat een lijst is, gaat in SQL Server en Oracle mee als JSON-tekst, omdat die drivers geen lijstparameter kennen.
Lezen en schrijven¶
Met mode: "read" accepteert Core alleen een query die begint met SELECT of WITH (in Postgres
ook VALUES of TABLE), zonder INSERT, UPDATE, DELETE, MERGE of INTO. De query draait
in een alleen-lezentransactie die altijd wordt teruggedraaid. SQL Server kent geen
alleen-lezentransactie: daar is de controle van de query wat een leestool tegen schrijven
beschermt. Daarom weigert ze in een leesquery ook EXEC, EXECUTE, OPENROWSET, OPENQUERY en
OPENDATASOURCE. Geef zo'n koppeling een gebruiker die niet kan schrijven.
Met mode: "write" mag de query ook met een van deze beginnen:
| Dialect | Schrijfstatements |
|---|---|
| Postgres | INSERT, UPDATE, DELETE, MERGE, CALL |
| MySQL | INSERT, UPDATE, DELETE, REPLACE, CALL |
| SQL Server | INSERT, UPDATE, DELETE, MERGE, EXEC van een procedure |
| Oracle | INSERT, UPDATE, DELETE, MERGE, CALL |
INTO wordt overal geweigerd behalve in een INSERT, een REPLACE of een MERGE, want
SELECT ... INTO maakt een tabel en MySQL's INTO OUTFILE schrijft een bestand op de server. De
query draait in één transactie die wordt vastgelegd. Core probeert een aanroep nooit opnieuw. In SQL Server weigert een schrijftool
dynamische SQL (EXEC (...), sp_executesql) en EXECUTE AS.
TLS¶
Core praat altijd versleuteld met je database; een instelling zonder TLS bestaat niet.
tls |
Wat Core controleert |
|---|---|
verify-full (standaard) |
het certificaat van de server en of het de naam van de host draagt |
require |
versleutelt, en controleert het certificaat alleen tegen een ca_pem die je meegeeft. Bij SQL Server controleert de driver het certificaat altijd, dus daar slaat require alleen de controle van de naam over |
ca_pem is de certificaatautoriteit van je eigen server, als PEM. Laat hem weg om het certificaat
te controleren tegen de autoriteiten die de installatie vertrouwt. Een MySQL-server die geen TLS
aanbiedt, wordt geweigerd voordat Core inlogt.
Wat het model terugkrijgt¶
Het antwoord is gestructureerd: {columns, rows, row_count, truncated}, met elke rij als een lijst
waarden in de volgorde van columns. Het model leest het als compacte JSON; een
directe aanroep geeft het in structured.
{"columns": ["id", "status", "total"],
"rows": [["A-1042", "shipped", "129.95"], ["A-1038", "open", "18.50"]],
"row_count": 2, "truncated": false}
- Een decimaal getal is tekst, zodat er geen cijfer verloren gaat; een tijd is ISO 8601; bytes zijn
[binary]. - Er komen hoogstens
max_rowsrijen terug, en hoogstens wat in een toolresultaat past (32 KiB).truncated: truezegt dat er rijen zijn weggelaten. - Een query die geen rijen teruggeeft, zoals een
UPDATE, geeft inrow_counthet aantal gewijzigde rijen.
Mislukt een aanroep, dan leest het model één vaste zin, nooit de foutmelding van de server, want die kan de waarden van de query bevatten. De beurt gaat door.
| Het model leest | Wat er gebeurde | Wat je kunt doen |
|---|---|---|
Denied by policy. |
de host staat niet bij je toegestane hosts, de regels van de sleutel weigeren hem, of de installatie blokkeert de host of het adres waar hij naar verwijst (een privé- of loopback-adres, een naam als localhost of een naam op .internal) |
zet de host op de lijst, of maak de server bereikbaar op een adres dat de installatie niet blokkeert, zie Toegestane hosts |
Tool authentication failed. |
de server weigerde de gebruikersnaam of het wachtwoord | sla met PATCH een nieuwe auth op |
Database unreachable. |
de server antwoordde niet, of de TLS-controle mislukte | controleer host, poort, tls en ca_pem met de test |
Database query timed out. |
de query duurde langer dan de timeout |
maak de query sneller of de timeout ruimer |
Database refused the query. |
de server weigerde de query, of een schrijfquery gaf meer terug dan Core mag lezen | probeer de query zelf op de server met dezelfde gebruiker |
Het auditspoor en de trace van de beurt noemen de soort fout en de foutcode van de server (de SQLSTATE-klasse of het foutnummer), niet de melding zelf.
Een koppeling testen¶
POST /sql_connectors/{id}/test logt in en voert SELECT 1 uit, onder dezelfde regels voor hosts
als een aanroep. Er wordt niets opgeslagen.
curl -s -X POST "$CORE_URL/sql_connectors/sqlc_01J.../test" \
-H "Authorization: Bearer $CORE_KEY"
Het antwoord is altijd 200:
{"object": "sql_connector_test", "ok": true, "code": null}
Bij een mislukking is ok false en zegt code waarom:
egress_denied (de host of zijn adres is niet toegestaan), unreachable, auth_failed, timeout
of refused.
Toegestane hosts¶
Core bereikt je database alleen als de hostnaam bij de toegestane hosts van je organisatie staat,
dezelfde lijst als voor een API-koppeling (Toegestane
bestemmingen). Het veld egress op elke read zegt
per host of hij is toegestaan (allowed) en of de installatie hem blokkeert (blocked).
De installatie blokkeert een adres in een privénetwerk, een loopback-adres en een naam die alleen
binnen een netwerk bestaat, zoals localhost of een naam op .internal. Je databaseserver moet
dus bereikbaar zijn op een adres dat Core mag bellen. Stuurt de server Core door naar een andere
host, zoals een Azure SQL-gateway of een Oracle-listener doet, dan moet die host ook zijn
toegestaan.
region zegt waar de server draait, zoals bij een API-koppeling
(Waar de host draait).
Versies¶
Een koppeling is geversioneerd. Een PATCH die wijzigt wat de tool doet (de query, de
argumenten, de server, de modus, de grenzen, de invulwaarden, de aanroepvariabelen of
background) maakt een nieuwe versie. Een PATCH van alleen auth, region, labels of
metadata maakt er geen.
GET /sql_connectors/{id}/versions toont de versies, nieuwste eerst (?order=asc voor oudste eerst), en
GET /sql_connectors/{id}/versions/{version} er één. Pin een versie op een verzoek:
{ "type": "tool", "name": "sql__orders", "version": 2 }
Zonder version krijgt een beurt de nieuwste (Een versie vastpinnen).
Op de achtergrond, labels en een afbeelding¶
- Achtergrond.
backgroundbepaalt of het model de tool als taak mag starten, met dezelfde velden als bij een API-koppeling (Een tool op de achtergrond draaien). Het hoort bij de versie. - Labels.
labelsis de eigen indeling van je organisatie, waarover regels voor personen worden geschreven (Labels op alles). Voor een verzoek dat een persoon noemt, beslissen dezelfde regels oversql__<naam>ofGET /sql_connectorsde koppeling toont en of ze gewijzigd of verwijderd mag worden (Registraties). - Afbeelding.
PUT /tools/sql__orders/coverzet een afbeelding bij de tool die de console naast de naam toont: PNG, JPEG of WebP als ruwe body, hoogstens 512 KiB tenzij je operator een andere grens instelde.DELETEhaalt hem weg. Het model ziet de afbeelding nooit.
Delen in een publicatie¶
Een SQL-koppeling kan mee in een publicatie, als lid van
de soort sql_connector. Zeg net als bij een API-koppeling wat er met de inloggegevens gebeurt:
{"kind": "sql_connector", "id": "sqlc_01J...", "auth": "parameter", "auth_parameter": "database_login"}
auth |
Wat er gebeurt |
|---|---|
parameter |
elke organisatie die installeert, vult een eigen gebruikersnaam en wachtwoord in |
carried |
je eigen gegevens reizen versleuteld mee; alleen bij een publicatie aan organisaties onder je |
none |
er gaan geen gegevens mee, en de geïnstalleerde kopie heeft er geen |
Elke invulwaarde wordt een parameter van de bundel, met jouw waarde als standaard. Wie installeert,
vult dus een eigen schemanaam of waarde in, en Core controleert de query daarmee opnieuw bij het
installeren. Een kopie die met auth: "none" is geïnstalleerd, kan niet inloggen: een verzoek dat
haar tool aanbiedt, antwoordt 503 met The SQL connector's stored credential could not be read.
Kies parameter als elke installeerder een eigen login moet gebruiken. Een installatie onder de voorwaarde Inhoud verbergen toont de query, de host, de
database en de argumenten als null; de tool werkt gewoon. Een kopie uit een publicatie wijzig je
niet, ook de afbeelding niet: zo'n PUT of DELETE geeft 409.
Fouten bij het registreren¶
| Status | Wanneer |
|---|---|
409 |
er is al een SQL-koppeling met deze naam; of bij DELETE noemt een agent de tool nog |
422 op statement |
de query mag niet, zie De query |
422 op call_variables |
een declaratie die de query niet gebruikt, of een naam die ook een argument of invulwaarde is |
422 op ca_pem |
geen PEM, of geen certificaat dat de server kan laden |
503 |
de installatie heeft geen sleutel om het wachtwoord mee te versleutelen; vraag het je operator |
Elke route heeft een tweeling onder /tenants/{tenant_id}/sql_connectors voor een beheerder die
met een beheerderstoken werkt, met dezelfde velden en antwoorden.