Calling web services from SQL (http_get, http_post)
http_get and http_post call a web address from SQL, a procedure or a timer. Off until an admin lists the hosts they may call.
- Category: Stored procedures
- Keywords: http_get, http_post, http, https, web service, webhook, call url, rest api, outbound, http_functions, http_timeout_ms, KDB_HTTP_FUNCTIONS, allowlist, fetch, curl
- See also: Stored procedures, Timers, Triggers, JSON functions, Users and roles, Settings page (data folder, old log, capacity, program files and users)
http_get and http_post let SQL call another service. A procedure can tell a settlement service that a day is done. A timer can ask a checker every hour.
- They are off until an admin lists the hosts they may call (the setting
http_functions). - They need role write on the database, because a call changes things outside it.
- Every call really runs. The answer is never kept in the result cache.
- The headers you send are never written to a log. They often hold a token.
Example: On a server where nobody turned them on, a call is refused (shows an error)
SELECT http_get('http://10.0.0.5:8080/health');
Result:
Error: line 1, column 8: http_get: calling web addresses from SQL is off on this server; an admin turns it on by listing the hosts it may call in the setting http_functions (kdb.conf, KDB_HTTP_FUNCTIONS or the Settings page)
http_get
Syntax:
http_get(url)
http_get(url, headers)
Sends a GET request and waits for the whole answer.
| Argument | Type | Meaning |
|---|---|---|
url | text | http://host[:port]/path or https://.... |
headers | JSON object | extra request headers, like '{"Authorization":"Bearer abc"}'. Optional. |
- Returns:
JSONlike{"status":200,"headers":{"content-type":"application/json"},"body":"..."}.statusis the HTTP status. A404or a500is an answer, not an error.headershas the answer's headers, names in lower case.bodyis the answer as text.
- NULL: a
NULLurl givesNULL.NULLheaders count as none. - Errors: the statement fails when the host is not allowed, the address cannot be reached, the time limit passes, or the answer is over 16 MB.
http_post
Syntax:
http_post(url, body)
http_post(url, body, content_type)
http_post(url, body, content_type, headers)
Sends a POST request with a body.
| Argument | Type | Meaning |
|---|---|---|
url | text | as for http_get. |
body | text or JSON | what to send. |
content_type | text | the Content-Type. Default application/json for a JSON value, else text/plain; charset=utf-8. |
headers | JSON object | extra request headers. Optional. |
- Returns: the same JSON as
http_get.
Reading the answer
Use the JSON operators and functions on the result:
| You want | Write |
|---|---|
| the status | json_value_long(r, '$.status') |
| the body as text | r ->> 'body' |
| one header | r -> 'headers' ->> 'content-type' |
| a field of a JSON body | json(r ->> 'body') ->> 'ok' |
A procedure that calls a service and keeps what it said (it runs once http_functions lists 10.0.0.5:8080):
CREATE TABLE settle_log (at TIMESTAMP, status INT, body STRING);
CREATE PROCEDURE settle_day() AS BEGIN
INSERT INTO settle_log
SELECT now(), json_value_long(r, '$.status'), r ->> 'body'
FROM (SELECT http_post('http://10.0.0.5:8080/settle', json_object('day', current_date),
'application/json', '{"Authorization":"Bearer my-token"}') AS r) AS call;
END;
Turning them on
| Setting | Where | Default | Meaning |
|---|---|---|---|
http_functions | kdb.conf, KDB_HTTP_FUNCTIONS, the Settings page | off | the hosts SQL may call, separated by commas |
http_timeout_ms | kdb.conf, KDB_HTTP_TIMEOUT_MS, the Settings page | 10000 | the most milliseconds one call may take, redirects included |
kdb.conf wins over the environment. A save on the Settings page applies at once, without a restart.
How to write the list:
| Entry | Allows |
|---|---|
api.example.com | that host, any port |
10.0.0.5:8080 | that address, port 8080 only |
* | every host (still not 169.254.x.x, see below) |
off | nothing: the functions are off |
{"http_functions": "settle.internal:8080, 10.0.0.5", "http_timeout_ms": 5000}
What a call may do
| Rule | Why |
|---|---|
http:// and https:// only | nothing else is a web service |
| https checks the certificate against the authorities the computer trusts | so nobody in between can answer instead |
| at most 3 redirects, each to an allowed host | a redirect cannot lead out of the list |
Authorization and Cookie are not sent on to another host | a token is for the host it was written for |
169.254.x.x and 0.x.x.x are refused unless that host is listed by itself | clouds give out secret keys at 169.254.169.254 |
| at most 16 MB of answer | a big answer is an error, never a cut body |
| IPv4 only |
- A self-signed certificate is not trusted. Call such a service on the local network over
http://. - On Linux the trusted authorities come from the usual CA bundle file (
/etc/ssl/certs/ca-certificates.crtand others). SetSSL_CERT_FILEto use another file. - A build without TLS says so when asked for
https://.
Who may call
| Caller | May call |
|---|---|
| no login (a local tool, the server token) | yes |
a user with role write or admin | yes |
a user with role read | no: "needs role write", also through a view |
a procedure (CALL needs write), a trigger, a timer | yes |
The text of a statement goes to the activity log and the slow-query log. There, every argument after the address shows as '***', so a token in the headers is never kept.