Send Feedback
Skip to content

How to use HTTP in KDB-X

This page explains how to use KDB-X to serve and consume HTTP and HTTPS requests, build web services, and interact with external APIs.

Build a simple JSON API

Start a web server in less than a minute. This example creates an API that serves a table of trade data as JSON.

  1. Start the server: Start a q process on port 5000:

    $ q -p 5000
    

  2. Define the logic: Define dummy data and a request handler:

    q)// Create a dummy table
    q)trades:([] time:3#.z.t; sym:`AAPL`GOOG`MSFT; price:150.5 2800.0 300.0; size:100 50 200)
    q)// Define the HTTP GET handler (.z.ph)
    q)// .h.hy generates a valid HTTP response with the correct Content-Type
    q).z.ph:{[x] .h.hy[`json] .j.j trades}
    

  3. Test it: Open http://localhost:5000 in a web browser. The trade data displays as a JSON array

About the .h namespace

The code above uses .h.hy to construct the HTTP response. The .h namespace contains many utilities for handling HTTP, HTML, and URL encoding.

Use KDB-X as an HTTP server

Configure a KDB-X process as a web server to handle HTTP requests directly. This allows you to create custom APIs, serve data, and build web interfaces.

Setup and configuration

Configure the listening port and security options.

  • Listening port: The built-in HTTP server shares the listening port with KDB-X IPC and WebSocket services. HTTP requires no separate configuration. KDB-X automatically detects the protocol (HTTP, WebSocket, or IPC) of incoming connections
  • SSL/TLS for HTTPS: To handle https traffic and secure the server, configure KDB-X to use SSL/TLS. This ensures all communication between the client and server is encrypted

Enable HTTPS in two steps:

  1. Configure certificates: Set the environment variables (such as SSL_CERT_FILE and SSL_KEY_FILE) to point to the server's certificate and private key files
  2. Enable TLS mode: Start the KDB-X process with the -E command-line option (for example, -E 1 for optional TLS or -E 2 for mandatory TLS) to enable the TLS server mode

For a comprehensive guide on generating certificates and configuring these options, refer to the SSL/TLS configuration guide.

Request processing

Define how the server authenticates clients and handles different HTTP methods.

Authenticate and authorize

Secure HTTP endpoints by implementing custom logic in the .z.ac callback. This function acts as a gateway to integrate security mechanisms like LDAP, OAuth2, or OpenID Connect.

Method handlers

Override callback functions to define server behavior for different HTTP methods:

  • .z.ph: Handles HTTP GET requests
  • .z.pp: Handles HTTP POST requests
  • .z.pm: Handles OPTIONS, PATCH, PUT, and DELETE requests

Default request handling

If you do not override default callbacks, KDB-X provides a built-in web interface:

  • View data: Navigate to the root URL (for example, http://localhost:5000) to view all variables and views in the global namespace
  • Execute code: Pass a q expression as a URL argument. For example, http://localhost:5000?1+1 returns 2
  • Serve static files: Set .h.HOME to a directory path. For example, if .h.HOME is "/webserver", http://localhost:5000/index.html serves the index.html file from that directory

Security risk

Executing arbitrary code from a URL is a security risk in production. Implement robust authentication and authorization, or disable this feature.

Explore a custom web server example

For a practical example of a customized web server, refer to the simongarland/doth project.

Server performance

KDB-X includes features to optimize server performance and resource management.

  • Keep-alive: Set .h.ka to enable persistent connections and reduce latency for clients making multiple requests
  • Compression: KDB-X automatically applies gzip compression for form?… requests if:
    • The client request header includes Accept-Encoding: gzip
    • The response payload is 2000 characters or larger

Version requirement

Automatic gzip compression is available in v4.0 2020.03.17 and later.

Make HTTP requests from KDB-X

KDB-X acts as an HTTP client to fetch or send data to external web services and APIs.

Simple requests with helper functions

Use the .Q namespace helpers for common requests:

  • .Q.hg: HTTP GET request
  • .Q.hp: HTTP POST request

Automatic decompression

The .Q.hg function automatically handles decompression of gzipped responses.

Send a POST request

q)// Send a POST request with "my data" as the body and a plain text content type.
q)// Expected output (a JSON string from httpbin.org confirming the request)
q).Q.hp[`:http://httpbin.org/post; .h.ty`txt; "my data"]
"{\n  \"args\": {}, \n  \"data\": \"my data\", \n  \"files\": {}, \n  \"form\": {}, \n  \"headers\": {\n    \"Accept-Encoding\": \"gzip\", \n    \"Content-Length\": \"7\", \n    \"Content-Type\": \"text/plain\", \n    \"Host\": \"httpbin.org\", \n    \"X-Amzn-Trace-Id\": \"Root=1-665711e1-19e62fef6b6e4d192a9a7096\"\n  }, \n  \"json\": null, \n  \"origin\": \"78.147.173.108\", \n  \"url\": \"http://httpbin.org/post\"\n}\n"

Request and decode a gzipped response

q)// .Q.hg fetches the URL and automatically handles decompression.
q)// .j.k then decodes the resulting JSON response into a KDB-X dictionary.
q)// Expected output (a dictionary)
q).j.k .Q.hg "http://httpbin.org/gzip"
gzipped| 1b
headers| `Accept-Encoding`Host`X-Amzn-Trace-Id!("gzip";"httpbin.org";"Root=1-665710aa-50bd49d724b532913348a62a")
method | "GET"
origin | "78.147.173.108"

Send raw HTTP requests

For complete control over headers and methods (like DELETE or PUT), send a raw HTTP request string.

`:http://host:port "raw http request string"

A valid request string contains:

  1. A request line (for example, METHOD /path HTTP/1.1) ending with \r\n
  2. Zero or more header fields (for example, Header-Name: value), each ending with \r\n
  3. An empty line (\r\n) to signal the end of the headers
  4. An optional message body

Send a DELETE request

// Construct a raw HTTP DELETE request string and send it.
request: "DELETE /anything HTTP/1.1\r\n",
    "Connection: close\r\n",
    "Host: httpbin.org\r\n",
    "\r\n";

`:http://httpbin.org request
// Expected response (a raw string)
"HTTP/1.1 200 OK\r\ndate: Thu, 04 Dec 2025 02:05:56 GMT\r\ncontent-type: application/json\r\ncontent-length: 287\r\nconnection: close\r\nserver: gunicorn/19.9.0\r\naccess-control-allow-origin: *\r\naccess-control-allow-credentials: true\r\n\r\n{\n  \"args\": {}, \n  \"data\": \"\", \n  \"files\": {}, \n  \"form\": {}, \n  \"headers\": {\n    \"Host\": \"httpbin.org\", \n    \"X-Amzn-Trace-Id\": \"Root=1-6930ec84-57d8e9635721a096476a167a\"\n  }, \n  \"json\": null, \n  \"method\": \"DELETE\", \n  \"origin\": \"24.57.14.96\", \n  \"url\": \"http://httpbin.org/anything\"\n}\n"

Send a POST request with a dynamic body

// Define the data to be sent
postdata: "hello"

// Construct the full request string, calculating Content-Length dynamically
request: "POST /anything HTTP/1.1\r\n",
         "Connection: close\r\n",
         "Host: httpbin.org\r\n",
         "Content-Length: ",(string count postdata),"\r\n",
         "\r\n",
         postdata

`:http://httpbin.org request
// Expected response (a raw string)
"HTTP/1.1 200 OK\r\ndate: Thu, 04 Dec 2025 02:06:31 GMT\r\ncontent-type: application/json\r\ncontent-length: 318\r\nconnection: close\r\nserver: gunicorn/19.9.0\r\naccess-control-allow-origin: *\r\naccess-control-allow-credentials: true\r\n\r\n{\n  \"args\": {}, \n  \"data\": \"hello\", \n  \"files\": {}, \n  \"form\": {}, \n  \"headers\": {\n    \"Content-Length\": \"5\", \n    \"Host\": \"httpbin.org\", \n    \"X-Amzn-Trace-Id\": \"Root=1-6930eca6-720b0c230412593a392f6fa9\"\n  }, \n  \"json\": null, \n  \"method\": \"POST\", \n  \"origin\": \"24.57.14.96\", \n  \"url\": \"http://httpbin.org/anything\"\n}\n"

Parse the response body

The server response is a raw string. Parse it to separate the headers from the body.

q)// Execute the request and store the full raw response in 'x'
q)x: `:http://httpbin.org "DELETE /delete HTTP/1.1\r\nConnection: close\r\nHost: httpbin.org\r\n\r\n"
q)// Split the response string 'x' by the double newline ("\r\n\r\n")
q)// and take the second item (index 1), which is the body.
q)body: @["\r\n\r\n" vs x; 1];
q)// Expected output (the JSON body as a string)
q)show body;
"{\n  \"args\": {}, \n  \"data\": \"\", \n  \"files\": {}, \n  \"form\": {}, \n  \"headers\": {\n    \"Host\": \"httpbin.org\", \n    \"X-Amzn-Trace-Id\": \"Root=1-66572924-7396cee34f268fcd406e94d5\"\n  }, \n  \"json\": null, \n  \"origin\": \"78.147.173.108\", \n  \"url\": \"http://httpbin.org/delete\"\n}\n"

Chunked transfer encoding

If a server uses chunked transfer encoding, KDB-X automatically reconstructs the full response from the chunks. This feature is available in v3.3 2014.07.31 and later.

Use HTTPS in client requests

Prerequisite for HTTPS

To send client requests over HTTPS, first configure KDB-X to use SSL/TLS.

Once configured, replace http with https in your target URL. All methods described above work over the secure connection.

Further reading

Refer to the .h namespace for utilities for HTTP protocol formatting, URL encoding, and HTML markup generation.

For more information, refer to:

Summary

In this guide, you:

  • Configured a KDB-X process as an HTTP/S server
  • Implemented custom logic for GET, POST, and other requests
  • Used helper functions for simple client requests
  • Sent low-level HTTP requests for advanced control
  • Configured SSL/TLS for secure server and client operations