<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-01-06T16:19:23+00:00</updated><id>/feed.xml</id><title type="html">Jonathon McMurray</title><subtitle>I am a software developer working at AquaQ Analytics, specialising in kdb+/q. This site contains (or will contain...it&apos;s a work in progress!) documentation on a number of q packages/libraries I develop, as well as some general musings on interesting kdb+ related topics.</subtitle><entry><title type="html">Streaming realtime data from kdb+ with WebSockets</title><link href="/kdb/q/websockets/2019/08/12/ws-server.html" rel="alternate" type="text/html" title="Streaming realtime data from kdb+ with WebSockets" /><published>2019-08-12T00:00:00+00:00</published><updated>2019-08-12T00:00:00+00:00</updated><id>/kdb/q/websockets/2019/08/12/ws-server</id><content type="html" xml:base="/kdb/q/websockets/2019/08/12/ws-server.html"><![CDATA[<p>Pretty much everyone who works with kdb+ will be familiar with the standard
<a href="https://github.com/KxSystems/kdb-tick">kdb+tick</a> setup (and usually enhanced
frameworks such as <a href="https://github.com/AquaQAnalytics/TorQ">TorQ</a> with
additional functionality). This system allows a tickerplant to receive data
e.g. from a market data feed &amp; disseminate this data to subscriber processes,
such as a realtime database (RDB). And of course, other processes can subscribe
e.g. a realtime metrics process.</p>

<p>This is all very well as long as all the processes subscribing are also q
processes &amp; can therefore use q IPC for subscribing &amp; receiving messages etc.
However, sometimes you may wish to stream the incoming data to processes
written in other languages. While a number of languages have <a href="https://code.kx.com/q/interfaces/">interfaces</a>
to/from q, a more universal solution can be imagined using WebSockets.</p>

<p>Virtually all popular modern languages have support for WebSockets &amp; JSON
parsing, so we can feasibly use these two technologies (both natively supported
in q) to build a simple system for streaming data from a kdb+ system to non-q
processes.</p>

<p>I have built a couple of simple libraries related to WebSockets, available in
my GitHub repo: <a href="https://github.com/jonathonmcmurray/ws.q">https://github.com/jonathonmcmurray/ws.q</a>
Within this repo there are 3 scripts; <code class="language-plaintext highlighter-rouge">ws-handler.q</code> is a general script that
eases the use of WebSockets, allowing both server side &amp; client side in one
process; <code class="language-plaintext highlighter-rouge">ws-client.q</code> is for using q as a WebSocket client (see my <a href="https://jmcmurray.co.uk/kdb/q/websocket/gdax/cryptocurrency/2018/06/09/q-as-a-websocket-client.html">previous blogpost</a>
note: the library has been updated slightly since then, but usage should be the
same); and finally, <code class="language-plaintext highlighter-rouge">ws-server.q</code> is for using q as a WebSocket server, which
is what we’re interested in currently.</p>

<p>There are two ways to get this up &amp; running; if you are using <a href="https://jmcmurray.co.uk/kdb/q/package/qutil/anaconda/conda/2018/07/16/q-package-management-with-conda.html">qutil &amp; conda</a>
for package management in q, you can simply run</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>conda <span class="nb">install</span> <span class="nt">-c</span> jmcmuray ws-server
</code></pre></div></div>

<p>and then within a q session you simply need to do</p>

<div class="language-q highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">.utl.require</span><span class="s">"ws-server"</span>
</code></pre></div></div>

<p>Alternatively, you can clone the <code class="language-plaintext highlighter-rouge">ws.q</code> repo linked above &amp; load <code class="language-plaintext highlighter-rouge">ws-handler.q</code>
followed by <code class="language-plaintext highlighter-rouge">ws-server.q</code>.</p>

<p>This provides WebSocket equivalennts to the functions found in the standard
<a href="https://github.com/KxSystems/kdb-tick/blob/master/tick/u.q">u.q</a> in the <code class="language-plaintext highlighter-rouge">.wsu</code>
namespace.</p>

<p>The final piece of the puzzle is creating a tickerplant that can relay data
from a kdb+tick setup to a non-q process. Working off the standard <a href="https://github.com/simongarland/tick/blob/master/chainedtick.q"><code class="language-plaintext highlighter-rouge">chainedtick.q</code></a>
I created <a href="https://github.com/jonathonmcmurray/ws.q/blob/master/wschaintick.q"><code class="language-plaintext highlighter-rouge">wschaintick.q</code></a>.
This is a relatively simple script that will connect to a standard tickerplant,
subscribe for all symbols in all tables, and then publish to any subscribing
processes over WebSockets.</p>

<p>Assuming a tickerplant running on the default port (<code class="language-plaintext highlighter-rouge">5010</code>) on localhost, we 
can simply start a WebSocket chain tickerplant like so:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>q wschaintick.q
</code></pre></div></div>

<p>(with different ports etc., usage is <code class="language-plaintext highlighter-rouge">q wschaintick.q [host]:port[:usr:pwd] [-p 5110] [-t N]</code>)</p>

<p>It should also be noted here that if you are not using <code class="language-plaintext highlighter-rouge">qutil</code>, you will need
to modify line 8 of <code class="language-plaintext highlighter-rouge">wschaintick.q</code> to load <code class="language-plaintext highlighter-rouge">ws-handler.q</code> &amp; <code class="language-plaintext highlighter-rouge">ws-server.q</code>.</p>

<p>We can then connect to this chain tickerplant &amp; subscribe from other processes.
For example, the following JavaScript code running with Node.js:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">WebSocket</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">ws</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">ws</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebSocket</span><span class="p">(</span><span class="dl">'</span><span class="s1">ws://127.0.0.1:</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>

<span class="nx">ws</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">open</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span> <span class="nx">open</span><span class="p">()</span> <span class="p">{</span>
  <span class="nx">ws</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="dl">'</span><span class="s1">{"type":"sub","syms":["AAPL","IBM"]}</span><span class="dl">'</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">ws</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">message</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span> <span class="nx">incoming</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div></div>

<p>When we run this, we get the following output:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jonny@grizzly ~/git/ws.q <span class="o">(</span>master<span class="o">)</span> <span class="nv">$ </span>node eg.js 5110
<span class="o">[</span><span class="s2">"trade"</span>,[<span class="o">{</span><span class="s2">"time"</span>:<span class="s2">"0D22:03:21.093413000"</span>,<span class="s2">"sym"</span>:<span class="s2">"AAPL"</span>,<span class="s2">"price"</span>:132.51,<span class="s2">"size"</span>:75,<span class="s2">"stop"</span>:false,<span class="s2">"cond"</span>:<span class="s2">"G"</span>,<span class="s2">"ex"</span>:<span class="s2">"N"</span><span class="o">}</span>,
 <span class="o">{</span><span class="s2">"time"</span>:<span class="s2">"0D22:03:21.093413000"</span>,<span class="s2">"sym"</span>:<span class="s2">"IBM"</span>,<span class="s2">"price"</span>:27.03,<span class="s2">"size"</span>:20,<span class="s2">"stop"</span>:false,<span class="s2">"cond"</span>:<span class="s2">"A"</span>,<span class="s2">"ex"</span>:<span class="s2">"N"</span><span class="o">}]]</span>
<span class="o">[</span><span class="s2">"quote"</span>,[<span class="o">{</span><span class="s2">"time"</span>:<span class="s2">"0D22:03:21.593401000"</span>,<span class="s2">"sym"</span>:<span class="s2">"AAPL"</span>,<span class="s2">"bid"</span>:132.01,<span class="s2">"ask"</span>:133.02,<span class="s2">"bsize"</span>:32,<span class="s2">"asize"</span>:77,<span class="s2">"mode"</span>:<span class="s2">"Z"</span>,<span class="s2">"ex"</span>:<span class="s2">"N"</span><span class="o">}</span>,
 <span class="o">{</span><span class="s2">"time"</span>:<span class="s2">"0D22:03:21.593401000"</span>,<span class="s2">"sym"</span>:<span class="s2">"IBM"</span>,<span class="s2">"bid"</span>:26.15,<span class="s2">"ask"</span>:27.98,<span class="s2">"bsize"</span>:21,<span class="s2">"asize"</span>:17,<span class="s2">"mode"</span>:<span class="s2">" "</span>,<span class="s2">"ex"</span>:<span class="s2">"N"</span><span class="o">}</span>,
 <span class="o">{</span><span class="s2">"time"</span>:<span class="s2">"0D22:03:21.593401000"</span>,<span class="s2">"sym"</span>:<span class="s2">"IBM"</span>,<span class="s2">"bid"</span>:26.7,<span class="s2">"ask"</span>:27.89,<span class="s2">"bsize"</span>:37,<span class="s2">"asize"</span>:83,<span class="s2">"mode"</span>:<span class="s2">"R"</span>,<span class="s2">"ex"</span>:<span class="s2">"N"</span><span class="o">}]]</span>
</code></pre></div></div>

<p>Naturally, this streaming data can be used in any way desired. The subscriber
could, for example, be a browser page displaying a live plot of the data using
one of the numerous JavaScript charting libraries available.</p>

<p>On a performance note, it should be noted that when streaming to a JS client,
better performance can likely be achieved by serialising on the q side with <code class="language-plaintext highlighter-rouge">-8!</code>
and using <code class="language-plaintext highlighter-rouge">c.js</code> from kx to deserialise on JS side, instead of using JSON as
the transport format. However, I have chosen to demonstrate using JSON here as
this is more universal; most languages with WebSocket support will be able to
parse JSON, but kdb+ deserialisation libraries are not available everywhere.</p>]]></content><author><name></name></author><category term="kdb" /><category term="q" /><category term="websockets" /><summary type="html"><![CDATA[Pretty much everyone who works with kdb+ will be familiar with the standard kdb+tick setup (and usually enhanced frameworks such as TorQ with additional functionality). This system allows a tickerplant to receive data e.g. from a market data feed &amp; disseminate this data to subscriber processes, such as a realtime database (RDB). And of course, other processes can subscribe e.g. a realtime metrics process.]]></summary></entry><entry><title type="html">Redirecting HTTP to HTTPS in q</title><link href="/kdb/q/http/https/ssl/tls/2018/12/10/https-redirect.html" rel="alternate" type="text/html" title="Redirecting HTTP to HTTPS in q" /><published>2018-12-10T00:00:00+00:00</published><updated>2018-12-10T00:00:00+00:00</updated><id>/kdb/q/http/https/ssl/tls/2018/12/10/https-redirect</id><content type="html" xml:base="/kdb/q/http/https/ssl/tls/2018/12/10/https-redirect.html"><![CDATA[<p>In my <a href="https://jmcmurray.co.uk/kdb/q/https/api/2018/12/08/https-api-letencrypt.html">previous post</a>
I discussed using Let’s Encrypt to generate a CA-signed certificate for use in
q to run an HTTPS server. At the tail end of that post, I mentioned redirecting
HTTP requests to run over HTTPS. Since then, I have written &amp; published a small
package to do exactly that.</p>

<p>This package (available at the <a href="https://github.com/jonathonmcmurray/https-redirect">GitHub repo</a>) overwrites <code class="language-plaintext highlighter-rouge">.z.ph</code> &amp;
<code class="language-plaintext highlighter-rouge">.z.pp</code> to check if the current request is HTTP (checking <code class="language-plaintext highlighter-rouge">.z.e</code> to determine
this), &amp; if so, returns a <code class="language-plaintext highlighter-rouge">301 Permanently Moved</code> HTTP response, redirecting
the client to HTTPS. If the connection is already HTTPS, the exisitng <code class="language-plaintext highlighter-rouge">.z.ph</code>
or <code class="language-plaintext highlighter-rouge">.z.pp</code> definition is called as usual.</p>

<p>The package can easily be installed using conda e.g.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>conda <span class="nb">install</span> <span class="nt">-c</span> jmcmurray https-redirect
</code></pre></div></div>

<p>I think this is a fairly straightforward &amp; easy-to-use module, which “should”
require no interaction other than loading:</p>

<div class="language-q highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">jonny</span><span class="o">@</span><span class="n">grizzly</span><span class="w"> </span><span class="o">~/</span><span class="n">git</span><span class="o">/</span><span class="n">qwebapi</span><span class="w"> </span><span class="p">(</span><span class="n">master</span><span class="p">)</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">q</span><span class="w"> </span><span class="o">-</span><span class="n">E</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">-</span><span class="n">p</span><span class="w"> </span><span class="mi">8100</span>
<span class="n">KDB</span><span class="o">+</span><span class="w"> </span><span class="mf">3.6</span><span class="w"> </span><span class="ld">2018.05.17</span><span class="w"> </span><span class="n">Copyright</span><span class="w"> </span><span class="p">(</span><span class="n">C</span><span class="p">)</span><span class="w"> </span><span class="mi">1993</span><span class="o">-</span><span class="mi">2018</span><span class="w"> </span><span class="n">Kx</span><span class="w"> </span><span class="n">Systems</span>
<span class="n">l32</span><span class="o">/</span><span class="w"> </span><span class="mi">2</span><span class="p">()</span><span class="n">core</span><span class="w"> </span><span class="mi">1944</span><span class="n">MB</span><span class="w"> </span><span class="n">jonny</span><span class="w"> </span><span class="n">grizzly</span><span class="w"> </span><span class="mf">127.0.1.1</span><span class="w"> </span><span class="n">NONEXPIRE</span>

<span class="kd">q)</span><span class="n">.utl.require</span><span class="s">"webapi"</span>
<span class="kd">q)</span><span class="o">\</span><span class="n">l</span><span class="w"> </span><span class="n">example.q</span>
<span class="kd">q)</span><span class="n">.utl.require</span><span class="s">"https-redir"</span>
</code></pre></div></div>

<p><em>NOTE: We need to use <code class="language-plaintext highlighter-rouge">-E 1</code> to allow HTTP connections, which can then be
redirected to HTTPS. With <code class="language-plaintext highlighter-rouge">-E 2</code>, HTTP connections will signal in a way we
can’t catch &amp; respond to</em></p>

<p>Also note that we load <code class="language-plaintext highlighter-rouge">webapi</code> module <em>first</em>; <code class="language-plaintext highlighter-rouge">https-redir</code> requires any
other definitions of <code class="language-plaintext highlighter-rouge">.z.ph</code> &amp; <code class="language-plaintext highlighter-rouge">.z.pp</code> to be set before loading.</p>

<p>Following this, any HTTP request will automatically be redirected to HTTPS.</p>

<p>For example, using <a href="https://jmcmurray.co.uk/kdb/q/http/req/2018/06/19/req-0.1.1-release.html">reQ</a>
in verbose mode, we can see the flow of requests &amp; responses. Note that due to
how q sends server SSL certificates (see note in <a href="https://jmcmurray.co.uk/kdb/q/https/api/2018/12/08/https-api-letencrypt.html">previous post</a>)
we have to disable SSL server verfication for q - other clients such as web
browsers will download intermediate certificates &amp; this will not be an issue.</p>

<div class="language-q highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">jonny</span><span class="o">@</span><span class="n">grizzly</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">export</span><span class="w"> </span><span class="n">SSL_VERIFY_SERVER</span><span class="o">=</span><span class="n">NO</span>
<span class="n">jonny</span><span class="o">@</span><span class="n">grizzly</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">q</span>
<span class="n">KDB</span><span class="o">+</span><span class="w"> </span><span class="mf">3.6</span><span class="w"> </span><span class="ld">2018.05.17</span><span class="w"> </span><span class="n">Copyright</span><span class="w"> </span><span class="p">(</span><span class="n">C</span><span class="p">)</span><span class="w"> </span><span class="mi">1993</span><span class="o">-</span><span class="mi">2018</span><span class="w"> </span><span class="n">Kx</span><span class="w"> </span><span class="n">Systems</span>
<span class="n">l32</span><span class="o">/</span><span class="w"> </span><span class="mi">2</span><span class="p">()</span><span class="n">core</span><span class="w"> </span><span class="mi">1944</span><span class="n">MB</span><span class="w"> </span><span class="n">jonny</span><span class="w"> </span><span class="n">grizzly</span><span class="w"> </span><span class="mf">127.0.1.1</span><span class="w"> </span><span class="n">NONEXPIRE</span>

<span class="kd">q)</span><span class="n">.utl.require</span><span class="s">"req"</span>
<span class="kd">q)</span><span class="n">.req.VERBOSE</span><span class="o">:</span><span class="mb">1b</span>
<span class="kd">q)</span><span class="n">.req.g</span><span class="s">"http://jmcmurray.hopto.org:8100/gettime"</span>
<span class="o">--</span><span class="w"> </span><span class="n">REQUEST</span><span class="w"> </span><span class="o">--</span>
<span class="o">:</span><span class="n">http</span><span class="o">://</span><span class="n">jmcmurray.hopto.org</span><span class="o">:</span><span class="mi">8100</span>
<span class="n">GET</span><span class="c1"> /gettime HTTP/1.1</span>
<span class="n">Host</span><span class="o">:</span><span class="w"> </span><span class="n">jmcmurray.hopto.org</span><span class="o">:</span><span class="mi">8100</span>
<span class="n">Connection</span><span class="o">:</span><span class="w"> </span><span class="n">Close</span>
<span class="n">User</span><span class="o">-</span><span class="n">Agent</span><span class="o">:</span><span class="w"> </span><span class="n">kdb</span><span class="o">+/</span><span class="mf">3.6</span>
<span class="n">Accept</span><span class="o">:</span><span class="w"> </span><span class="o">*/*</span>


<span class="o">--</span><span class="w"> </span><span class="n">RESPONSE</span><span class="w"> </span><span class="o">--</span>
<span class="n">HTTP</span><span class="o">/</span><span class="mf">1.1</span><span class="w"> </span><span class="mi">301</span><span class="w"> </span><span class="n">Moved</span><span class="w"> </span><span class="n">Permanently</span>
<span class="n">Content</span><span class="o">-</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">text</span><span class="o">/</span><span class="n">html</span>
<span class="n">Content</span><span class="o">-</span><span class="n">Length</span><span class="o">:</span><span class="w"> </span><span class="mi">227</span>
<span class="n">Connection</span><span class="o">:</span><span class="w"> </span><span class="n">close</span>
<span class="n">Location</span><span class="o">:</span><span class="w"> </span><span class="n">https</span><span class="o">://</span><span class="n">jmcmurray.hopto.org</span><span class="o">:</span><span class="mi">8100</span><span class="o">/</span><span class="n">gettime</span>

<span class="o">&lt;!</span><span class="n">DOCTYPE</span><span class="w"> </span><span class="n">HTML</span><span class="w"> </span><span class="n">PUBLIC</span><span class="w"> </span><span class="s">"-//IETF//DTD HTML 2.0//EN"</span><span class="o">&gt;&lt;</span><span class="n">head</span><span class="o">&gt;&lt;</span><span class="n">title</span><span class="o">&gt;</span><span class="mi">301</span><span class="w"> </span><span class="n">Moved</span><span class="w"> </span><span class="n">Permanently</span><span class="o">&lt;/</span><span class="n">title</span><span class="o">&gt;&lt;/</span><span class="n">head</span><span class="o">&gt;&lt;</span><span class="n">body</span><span class="o">&gt;&lt;</span><span class="n">h1</span><span class="o">&gt;</span><span class="n">Moved</span><span class="w"> </span><span class="n">Permanently</span><span class="o">&lt;/</span><span class="n">h1</span><span class="o">&gt;&lt;</span><span class="n">p</span><span class="o">&gt;</span><span class="n">The</span><span class="w"> </span><span class="n">document</span><span class="w"> </span><span class="n">has</span><span class="w"> </span><span class="n">moved</span><span class="w"> </span><span class="o">&lt;</span><span class="n">a</span><span class="w"> </span><span class="n">href</span><span class="o">=</span><span class="s">"https://jmcmurray.hopto.org:8100/gettime"</span><span class="o">&gt;</span><span class="n">here</span><span class="o">&lt;/</span><span class="n">a</span><span class="o">&gt;&lt;/</span><span class="n">p</span><span class="o">&gt;&lt;/</span><span class="n">body</span><span class="o">&gt;</span>
<span class="o">--</span><span class="w"> </span><span class="n">REQUEST</span><span class="w"> </span><span class="o">--</span>
<span class="o">:</span><span class="n">https</span><span class="o">://</span><span class="n">jmcmurray.hopto.org</span><span class="o">:</span><span class="mi">8100</span>
<span class="n">GET</span><span class="c1"> /gettime HTTP/1.1</span>
<span class="n">Host</span><span class="o">:</span><span class="w"> </span><span class="n">jmcmurray.hopto.org</span><span class="o">:</span><span class="mi">8100</span>
<span class="n">Connection</span><span class="o">:</span><span class="w"> </span><span class="n">Close</span>
<span class="n">User</span><span class="o">-</span><span class="n">Agent</span><span class="o">:</span><span class="w"> </span><span class="n">kdb</span><span class="o">+/</span><span class="mf">3.6</span>
<span class="n">Accept</span><span class="o">:</span><span class="w"> </span><span class="o">*/*</span>


<span class="o">--</span><span class="w"> </span><span class="n">RESPONSE</span><span class="w"> </span><span class="o">--</span>
<span class="n">HTTP</span><span class="o">/</span><span class="mf">1.1</span><span class="w"> </span><span class="mi">200</span><span class="w"> </span><span class="n">OK</span>
<span class="n">Content</span><span class="o">-</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">application</span><span class="o">/</span><span class="n">json</span>
<span class="n">Connection</span><span class="o">:</span><span class="w"> </span><span class="n">close</span>
<span class="n">Content</span><span class="o">-</span><span class="n">Length</span><span class="o">:</span><span class="w"> </span><span class="mi">40</span>

<span class="p">{</span><span class="s">"time"</span><span class="o">:</span><span class="s">"2018-12-10T13:07:41.900367000"</span><span class="p">}</span>
<span class="n">time</span><span class="o">|</span><span class="w"> </span><span class="s">"2018-12-10T13:07:41.900367000"</span>
</code></pre></div></div>

<p>We see here that the first request recieves a <code class="language-plaintext highlighter-rouge">301</code> status &amp; the redirect is
followed automatically by reQ to send the request to the HTTPS URL.</p>]]></content><author><name></name></author><category term="kdb" /><category term="q" /><category term="http" /><category term="https" /><category term="ssl" /><category term="tls" /><summary type="html"><![CDATA[In my previous post I discussed using Let’s Encrypt to generate a CA-signed certificate for use in q to run an HTTPS server. At the tail end of that post, I mentioned redirecting HTTP requests to run over HTTPS. Since then, I have written &amp; published a small package to do exactly that.]]></summary></entry><entry><title type="html">Using LetsEncrypt to run an HTTPS server in q</title><link href="/kdb/q/https/api/2018/12/08/https-api-letencrypt.html" rel="alternate" type="text/html" title="Using LetsEncrypt to run an HTTPS server in q" /><published>2018-12-08T00:00:00+00:00</published><updated>2018-12-08T00:00:00+00:00</updated><id>/kdb/q/https/api/2018/12/08/https-api-letencrypt</id><content type="html" xml:base="/kdb/q/https/api/2018/12/08/https-api-letencrypt.html"><![CDATA[<p>In a <a href="https://jmcmurray.co.uk/kdb/q/rest/api/2018/05/22/rest-api-in-kdb.html">previous post</a>
I discussed creating an HTTP API in q. Back then I mentioned that I may explore
adding HTTPS support at a later point; I’ve recently had a chance to give this
a try, and thanks to <a href="https://letsencrypt.org/">Let’s Encrypt</a> it’s very easy
to do!</p>

<p>This will work regardless of whether you are using the <code class="language-plaintext highlighter-rouge">webapi</code> library from my
previous post (now available from conda: <code class="language-plaintext highlighter-rouge">conda install -c jmcmurray webapi</code> -
see <a href="https://jmcmurray.co.uk/kdb/q/package/qutil/anaconda/conda/2018/07/16/q-package-management-with-conda.html">this post</a>
about q package management for more details on that) or another custom
<code class="language-plaintext highlighter-rouge">.z.ph</code>/<code class="language-plaintext highlighter-rouge">.z.pp</code> definition (or even the default q HTTP interface).</p>

<p>Step one is to generate your certificates; this is pretty simple using certbot
from Let’s Encrypt. This is a fairly straightforward process, documented
<a href="https://certbot.eff.org/lets-encrypt/ubuntuartful-other">here</a> [instructions
for various OSes available]. For example on Ubuntu, once certbot is installed
we simply do something like:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>certbot certonly <span class="nt">--standalone</span> <span class="nt">-d</span> jmcmurray.hopto.org
</code></pre></div></div>

<p>(obviously <code class="language-plaintext highlighter-rouge">jmcmurray.hopto.org</code> is a domain I control). Certs will be
generated in e.g. <code class="language-plaintext highlighter-rouge">/etc/letsencrypt/live/jmcmurray.hopto.org</code></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jonny@grizzly ~ <span class="nv">$ </span><span class="nb">sudo ls</span> <span class="nt">-lFh</span> /etc/letsencrypt/live/jmcmurray.hopto.org
total 4.0K
lrwxrwxrwx 1 root root  43 Oct 25 15:08 cert.pem -&gt; ../../archive/jmcmurray.hopto.org/cert1.pem
lrwxrwxrwx 1 root root  44 Oct 25 15:08 chain.pem -&gt; ../../archive/jmcmurray.hopto.org/chain1.pem
lrwxrwxrwx 1 root root  48 Oct 25 15:08 fullchain.pem -&gt; ../../archive/jmcmurray.hopto.org/fullchain1.pem
lrwxrwxrwx 1 root root  41 Dec  8 14:10 jmcmurray.hopto.org -&gt; /etc/letsencrypt/live/jmcmurray.hopto.org/
lrwxrwxrwx 1 root root  46 Oct 25 15:08 privkey.pem -&gt; ../../archive/jmcmurray.hopto.org/privkey1.pem
<span class="nt">-rw-r--r--</span> 1 root root 682 Oct 25 15:08 README
</code></pre></div></div>

<p>As the certs are created as root, we have a couple of options. We could run our
q server as root, allowing us to read the certs. Alternatively, we can copy (as
root) to another readable location e.g.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jonny@grizzly ~ <span class="nv">$ </span><span class="nb">mkdir </span>certs
jonny@grizzly ~ <span class="nv">$ </span><span class="nb">sudo </span>su
root@grizzly:/home/jonny# <span class="nb">cp</span> /etc/letsencrypt/live/jmcmurray.hopto.org/<span class="k">*</span> certs/
<span class="nb">cp</span>: <span class="nt">-r</span> not specified<span class="p">;</span> omitting directory <span class="s1">'/etc/letsencrypt/live/jmcmurray.hopto.org/jmcmurray.hopto.org'</span>
root@grizzly:/home/jonny# <span class="nb">exit
exit
</span>jonny@grizzly ~ <span class="nv">$ </span>ll certs/
total 20K
<span class="nt">-rw-r--r--</span> 1 root root 2.2K Dec  8 15:06 cert.pem
<span class="nt">-rw-r--r--</span> 1 root root 1.7K Dec  8 15:06 chain.pem
<span class="nt">-rw-r--r--</span> 1 root root 3.8K Dec  8 15:06 fullchain.pem
<span class="nt">-rw-r--r--</span> 1 root root 1.7K Dec  8 15:06 privkey.pem
<span class="nt">-rw-r--r--</span> 1 root root  682 Dec  8 15:06 README
</code></pre></div></div>

<p>Now we can set the necessary environment variables &amp; load up our q session:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jonny@grizzly ~ <span class="nv">$ </span><span class="nb">export </span><span class="nv">SSL_CERT_FILE</span><span class="o">=</span>~/certs/fullchain.pem
jonny@grizzly ~ <span class="nv">$ </span><span class="nb">export </span><span class="nv">SSL_KEY_FILE</span><span class="o">=</span>~/certs/privkey.pem
jonny@grizzly ~ <span class="nv">$ </span>q <span class="nt">-E</span> 1 <span class="nt">-p</span> 8100
KDB+ 3.6 2018.05.17 Copyright <span class="o">(</span>C<span class="o">)</span> 1993-2018 Kx Systems
l32/ 2<span class="o">()</span>core 1944MB jonny grizzly 127.0.1.1 NONEXPIRE

q<span class="o">)</span>.utl.require<span class="s2">"webapi"</span>
q<span class="o">)</span><span class="se">\l</span> git/qwebapi/example.q
</code></pre></div></div>

<p>(Here I load my <code class="language-plaintext highlighter-rouge">webapi</code> module previously mentioned &amp; the same example script
I used in my previous post on HTTP APIs)</p>

<p>Now, we can query the API over HTTPS:</p>

<p><img src="/assets/https_api.png" alt="HTTPS API" /></p>

<p>All in all, the process is pretty simple &amp; straightforward, and takes about 5
minutes. As a couple of closing notes:</p>

<ul>
  <li>Using <code class="language-plaintext highlighter-rouge">-E 1</code> as I showed here still allows HTTP access; with <code class="language-plaintext highlighter-rouge">-E 2</code> only
HTTPS is allowed (however, HTTP requests will not be redirected to HTTPS - I’ll
be looking into this in future)</li>
  <li>As per the <a href="https://code.kx.com/q/cookbook/ssl/#tls-server-mode">kx docs</a>
<code class="language-plaintext highlighter-rouge">-u 1</code> should be used to prevent remote access to your server key file, &amp; q
should not be run from a directory where the keys can be accessed</li>
</ul>

<p><em>UPDATE:</em> After publishing this post, I realised that kdb+ seemingly does not
publish the full certificate chain it is provided, only the server certificate.</p>

<p>This means that, when using Let’s Encrypt, the intermediate LE certificate is
not provided to clients. Some clients (e.g. web browsers) will download the
intermediate(s) as necessary &amp; the user will likely not notice anything is
“wrong”. Other clients (e.g. another q session) will not, and will therefore
fail to verify the server certificate.</p>

<p><img src="/assets/https-chain.png" alt="HTTPS Chain" />
<em>Report from <a href="https://www.ssllabs.com/ssltest/index.html">SSL Labs</a></em></p>

<p>In order to send an HTTPS query from another q session, you will need to either
disable SSL server verification (set env var <code class="language-plaintext highlighter-rouge">SSL_VERIFY_SERVER=NO</code> before
starting q) or add your server cert to the CA bundle you are using.</p>]]></content><author><name></name></author><category term="kdb" /><category term="q" /><category term="https" /><category term="api" /><summary type="html"><![CDATA[In a previous post I discussed creating an HTTP API in q. Back then I mentioned that I may explore adding HTTPS support at a later point; I’ve recently had a chance to give this a try, and thanks to Let’s Encrypt it’s very easy to do!]]></summary></entry><entry><title type="html">q package management with Anaconda &amp;amp; qutil</title><link href="/kdb/q/package/qutil/anaconda/conda/2018/07/16/q-package-management-with-conda.html" rel="alternate" type="text/html" title="q package management with Anaconda &amp;amp; qutil" /><published>2018-07-16T00:00:00+00:00</published><updated>2018-07-16T00:00:00+00:00</updated><id>/kdb/q/package/qutil/anaconda/conda/2018/07/16/q-package-management-with-conda</id><content type="html" xml:base="/kdb/q/package/qutil/anaconda/conda/2018/07/16/q-package-management-with-conda.html"><![CDATA[<p>One thing I’ve always envied in other languages is package management. Python
has <code class="language-plaintext highlighter-rouge">pip</code>, Node.js has <code class="language-plaintext highlighter-rouge">npm</code>, R has CRAN, ruby has gems…the list goes on. For
a kdb+ dev, the situation is a little different. For a start, there’s much less
open source (or closed source, for that matter) code available to be used in
our projects. And when there are bits and pieces available, they’re not always
written in a way that easily integrates into other code. We end up copying &amp;
pasting code into our code base, making it trickier to get (or contribute)
upstream changes.</p>

<p>For a while there have existed a few options for easing the pain of loading
other people’s code in your project; options such as the excellent <a href="https://github.com/nugend/qutil">qutil</a>
from Dan Nugent. In short, qutil provides a nice, standardised way of packaging
code (i.e. a directory with an <code class="language-plaintext highlighter-rouge">init.q</code> file), and also a standardised way of
organising &amp; loading these packages (i.e. in a directory pointed to by an env
var, and loading them with <code class="language-plaintext highlighter-rouge">.utl.require</code> function). There are a couple of
other options (<a href="https://github.com/BuaBook/kdb-common/wiki/require.q">require.q</a>, <a href="https://github.com/yang-guo/qp">qpm</a>), but I prefer <code class="language-plaintext highlighter-rouge">qutil</code>.</p>

<p>So that leaves one thing missing that the other languages have; an easy to use
command line installer for packages with a central repo. I had thought for a
while it would be really nice to have such a thing for q packages; I even
toyed with the idea of building such a thing. But when kx <a href="https://kx.com/blog/kdb-on-anaconda-and-google-cloud/">announced</a> the
availablity of kdb+, jupyterq &amp; embedPy on <a href="https://anaconda.org/">Anaconda</a>, I realised
that Anaconda (which I had previously thought was “just for python”) provided a
cross-platform, language agnostic package manager in the form of <code class="language-plaintext highlighter-rouge">conda</code>.</p>

<p>So I started packaging some q packages for installation with <code class="language-plaintext highlighter-rouge">conda</code>. One of
these packages is <code class="language-plaintext highlighter-rouge">qutil</code> itself, which sets up the package loading code within
the conda environment. Other packages I have packaged are dependent on this, so
you shouldn’t have to install it directly, it’ll automatically be set up when
you install another package.</p>

<p>I deliberately did <em>not</em> make any of my packages dependent on the kx kdb
package - while this is a nice, easy way to get 64-bit kdb+ up &amp; running, it is
on-demand only <del>&amp; only for Mac &amp; Linux</del>; Anaconda itself works fine on Windows,
and 32-bit (here’s hoping that kx add <del>a Windows version soon, and</del> 32-bit). So
the q packages installed in this way will work with either Anaconda kdb or
system kdb (installed via traditional means). <strong>UPDATE: kx have now added Windows
releases of kdb on Anaconda cloud; still 64-bit on-demand only</strong></p>

<p>The easiest way to get up &amp; running is to install <a href="https://conda.io/miniconda.html">miniconda</a> (a minimal 
Anaconda distribution) and then use <code class="language-plaintext highlighter-rouge">conda install</code> to install some of my
<a href="https://anaconda.org/jmcmurray/repo">packages</a>, for example:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">jonny@kodiak ~ <span class="nv">$ </span>wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
<span class="c">## allow script to download</span>
jonny@kodiak ~ <span class="nv">$ </span>sh Miniconda3-latest-Linux-x86_64.sh
<span class="c">## accept the agreement etc.</span>
jonny@kodiak ~ <span class="nv">$ </span><span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span>/home/jonny/miniconda3/bin:<span class="nv">$PATH</span>       <span class="c"># add miniconda to PATH</span>
jonny@kodiak ~ <span class="nv">$ </span><span class="nb">source </span>activate base                               <span class="c"># activate base conda env</span>
<span class="o">(</span>base<span class="o">)</span> jonny@kodiak ~ <span class="nv">$ </span>conda <span class="nb">install</span> <span class="nt">-c</span> jmcmurray req              <span class="c"># install reQ package &amp; dependencies</span>
<span class="c">## accept prompt to install</span>
<span class="o">(</span>base<span class="o">)</span> jonny@kodiak ~ <span class="nv">$ </span>q                                           <span class="c"># start q &amp; test newly install pkg</span>
KDB+ 3.5 2018.04.25 Copyright <span class="o">(</span>C<span class="o">)</span> 1993-2018 Kx Systems
l64/ 4<span class="o">(</span>16<span class="o">)</span>core 7360MB jonny kodiak 127.0.1.1 EXPIRE 2019.05.21 jonathon.mcmurray@aquaq.co.uk KOD <span class="c">#4160315</span>

q<span class="o">)</span>.utl.require<span class="s2">"req"</span>
q<span class="o">)</span>.req.g<span class="s2">"https://httpbin.org/get"</span>
args   | <span class="o">(</span><span class="sb">`</span>symbol<span class="si">$()</span><span class="o">)!()</span>
headers| <span class="sb">`</span>Accept<span class="sb">`</span>Connection<span class="sb">`</span>Host<span class="sb">`</span>User-Agent!<span class="o">(</span><span class="s2">"*/*"</span><span class="p">;</span><span class="s2">"close"</span><span class="p">;</span><span class="s2">"httpbin.org"</span><span class="p">;</span><span class="s2">"kdb..
origin | "</span>146.199.80.196<span class="s2">"
url    | "</span>https://httpbin.org/get<span class="s2">"</span></code></pre></figure>

<p>Over the next few weeks, I hope to release a bunch more packages, and I really
hope that we are at the beginning of kdb+ going far more mainstream and 
building a much larger open source community, with lots of packages available
for use in our various projects.</p>

<p>I’ll post more about creating conda packages for q code in a future blog post,
but for those interested you can check my <a href="https://github.com/jonathonmcmurray/conda-recipes">conda-recipes</a> repo 
containing the “recipes” used to build most of my conda packages.</p>]]></content><author><name></name></author><category term="kdb" /><category term="q" /><category term="package" /><category term="qutil" /><category term="anaconda" /><category term="conda" /><summary type="html"><![CDATA[One thing I’ve always envied in other languages is package management. Python has pip, Node.js has npm, R has CRAN, ruby has gems…the list goes on. For a kdb+ dev, the situation is a little different. For a start, there’s much less open source (or closed source, for that matter) code available to be used in our projects. And when there are bits and pieces available, they’re not always written in a way that easily integrates into other code. We end up copying &amp; pasting code into our code base, making it trickier to get (or contribute) upstream changes.]]></summary></entry><entry><title type="html">reQ v0.1.2 Official Release</title><link href="/kdb/q/http/req/2018/06/19/req-0.1.1-release.html" rel="alternate" type="text/html" title="reQ v0.1.2 Official Release" /><published>2018-06-19T00:00:00+00:00</published><updated>2018-06-19T00:00:00+00:00</updated><id>/kdb/q/http/req/2018/06/19/req-0.1.1-release</id><content type="html" xml:base="/kdb/q/http/req/2018/06/19/req-0.1.1-release.html"><![CDATA[<p>In previous blog posts, both here and on the <a href="https://www.aquaq.co.uk/q/using-kdb-with-rest-apis/">AquaQ blog</a>, I have
mentioned the reQ HTTP library that I’ve been working on. And the time has come
for an “official” release! reQ has reached a point where I think it can be
quite useful, particularly for interacting with web APIs from q. You may be
wondering what’s wrong with <code class="language-plaintext highlighter-rouge">.Q.hg</code> and <code class="language-plaintext highlighter-rouge">.Q.hp</code>, the built in HTTP request
functions in q; reQ has a few nice additional features over these…</p>

<h4 id="automatically-parse-json-responses">Automatically parse JSON responses</h4>

<p>When your HTTP request returns JSON, reQ will allow parsing it automatically:</p>

<figure class="highlight"><pre><code class="language-q" data-lang="q"><span class="kd">q)</span><span class="no">.Q.hg</span><span class="ss">`</span><span class="o">$</span><span class="s">":https://httpbin.org/get"</span>
<span class="s">"{\"args\":{},\"headers\":{\"Connection\":\"close\",\"Host\":\"httpbin.org\"},\"origin\":\"146.199.80.196\",\"url\":\"https://httpbin.org/get\"}</span><span class="se">\n</span><span class="s">"</span>
<span class="kd">q)</span><span class="n">.req.g</span><span class="s">"https://httpbin.org/get"</span>
<span class="n">args</span><span class="w">   </span><span class="o">|</span><span class="w"> </span><span class="p">(</span><span class="ss">`symbol</span><span class="o">$</span><span class="p">())</span><span class="o">!</span><span class="p">()</span>
<span class="n">headers</span><span class="o">|</span><span class="w"> </span><span class="ss">`Accept`Connection`Host`User</span><span class="o">-</span><span class="n">Agent</span><span class="o">!</span><span class="p">(</span><span class="s">"*/*"</span><span class="p">;</span><span class="s">"close"</span><span class="p">;</span><span class="s">"httpbin.org"</span><span class="p">;</span><span class="s">"kdb+/3.5"</span><span class="p">)</span>
<span class="n">origin</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="s">"146.199.80.196"</span>
<span class="n">url</span><span class="w">    </span><span class="o">|</span><span class="w"> </span><span class="s">"https://httpbin.org/get"</span></code></pre></figure>

<h4 id="adding-custom-http-headers">Adding custom HTTP headers</h4>

<p>Some APIs etc. require custom headers (for example, authentication tokens, or
requiring requests to have a <code class="language-plaintext highlighter-rouge">User-Agent</code>, which they do not with <code class="language-plaintext highlighter-rouge">.Q.hg</code>/
<code class="language-plaintext highlighter-rouge">.Q.hp</code>). reQ allows for adding custom headers in a simple fashion using a kdb+
dictionary. For example:</p>

<figure class="highlight"><pre><code class="language-q" data-lang="q"><span class="kd">q)</span><span class="n">.req.get</span><span class="p">[</span><span class="s">"http://httpbin.org/headers"</span><span class="p">;</span><span class="ss">`custom`headers</span><span class="o">!</span><span class="p">(</span><span class="s">"with custom"</span><span class="p">;</span><span class="s">"values"</span><span class="p">)]</span>
<span class="w">       </span><span class="o">|</span><span class="w"> </span><span class="n">Accept</span><span class="w"> </span><span class="n">Connection</span><span class="w"> </span><span class="n">Custom</span><span class="w">        </span><span class="n">Headers</span><span class="w">  </span><span class="n">Host</span><span class="w">          </span><span class="n">User</span><span class="o">-</span><span class="n">Agent</span>
<span class="o">-------|</span><span class="w"> </span><span class="o">-----------------------------------------------------------------</span>
<span class="n">headers</span><span class="o">|</span><span class="w"> </span><span class="s">"*/*"</span><span class="w">  </span><span class="s">"close"</span><span class="w">    </span><span class="s">"with custom"</span><span class="w"> </span><span class="s">"values"</span><span class="w"> </span><span class="s">"httpbin.org"</span><span class="w"> </span><span class="s">"kdb+/3.5"</span></code></pre></figure>

<h4 id="http-redirection">HTTP redirection</h4>

<p>reQ will automatically follow HTTP redirects (3XX status codes)</p>

<figure class="highlight"><pre><code class="language-q" data-lang="q"><span class="kd">q)</span><span class="n">.req.get</span><span class="p">[</span><span class="s">"http://httpbin.org/relative-redirect/2"</span><span class="p">;()</span><span class="o">!</span><span class="p">()];</span>
<span class="n">args</span><span class="w">   </span><span class="o">|</span><span class="w"> </span><span class="p">(</span><span class="ss">`symbol</span><span class="o">$</span><span class="p">())</span><span class="o">!</span><span class="p">()</span>
<span class="n">headers</span><span class="o">|</span><span class="w"> </span><span class="ss">`Accept`Connection`Host`User</span><span class="o">-</span><span class="n">Agent</span><span class="o">!</span><span class="p">(</span><span class="s">"*/*"</span><span class="p">;</span><span class="s">"close"</span><span class="p">;</span><span class="s">"httpbin.org"</span><span class="p">;</span><span class="s">"kdb+/3.5"</span><span class="p">)</span>
<span class="n">origin</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="s">"146.199.80.196"</span>
<span class="n">url</span><span class="w">    </span><span class="o">|</span><span class="w"> </span><span class="s">"http://httpbin.org/get"</span></code></pre></figure>

<h4 id="cookie-support">Cookie support</h4>

<p>reQ will store received cookies &amp; automatically send them with future HTTP
requests where applicable.</p>

<figure class="highlight"><pre><code class="language-q" data-lang="q"><span class="kd">q)</span><span class="n">.req.get</span><span class="p">[</span><span class="s">"http://httpbin.org/cookies/set?abc=123&amp;def=456"</span><span class="p">;()</span><span class="o">!</span><span class="p">()]</span>
<span class="w">       </span><span class="o">|</span><span class="w"> </span><span class="n">abc</span><span class="w">   </span><span class="n">def</span>
<span class="o">-------|</span><span class="w"> </span><span class="o">-----------</span>
<span class="n">cookies</span><span class="o">|</span><span class="w"> </span><span class="s">"123"</span><span class="w"> </span><span class="s">"456"</span>
<span class="kd">q)</span><span class="n">.req.cookiejar</span>
<span class="n">host</span><span class="w">           </span><span class="n">path</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">val</span><span class="w">   </span><span class="n">expires</span><span class="w"> </span><span class="n">maxage</span><span class="w"> </span><span class="n">secure</span><span class="w"> </span><span class="n">httponly</span><span class="w"> </span><span class="n">samesite</span>
<span class="o">-------------------------|</span><span class="w"> </span><span class="o">---------------------------------------------</span>
<span class="s">".httpbin.org"</span><span class="w"> </span><span class="s">"/*"</span><span class="w"> </span><span class="s">"abc"</span><span class="o">|</span><span class="w"> </span><span class="s">"123"</span><span class="w">                </span><span class="mi">0</span><span class="w">      </span><span class="mi">0</span>
<span class="s">".httpbin.org"</span><span class="w"> </span><span class="s">"/*"</span><span class="w"> </span><span class="s">"def"</span><span class="o">|</span><span class="w"> </span><span class="s">"456"</span><span class="w">                </span><span class="mi">0</span><span class="w">      </span><span class="mi">0</span></code></pre></figure>

<p>(It’s also possible to read &amp; write cookiejar files in the cURL/Netscape 
format)</p>

<p>More details about all these features can be found on the <a href="http://jmcmurray.co.uk/reQ">documentation site</a></p>

<h4 id="installation">Installation</h4>

<p>reQ can be “installed” by simply downloading <code class="language-plaintext highlighter-rouge">req.q</code> and loading it within your
q session. Alternatively, you can download the <a href="https://github.com/jonathonmcmurray/reQ/archive/v0.1.2.zip">release package</a> &amp; use
this as a package for <a href="https://github.com/nugend/qutil">qutil</a>.</p>

<p>Finally, and this is the one I recommend, you can install the package using
<a href="https://www.anaconda.com/download">Anaconda</a>. Assuming Anaconda is installed (and regardless of platform),
you can install quite simply like so:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="o">(</span>kdb<span class="o">)</span> jonny@kodiak ~ <span class="nv">$ </span>conda <span class="nb">install</span> <span class="nt">-c</span> jmcmurray req
<span class="o">[</span> snipped <span class="nb">install</span> <span class="o">]</span>
<span class="o">(</span>kdb<span class="o">)</span> jonny@kodiak ~ <span class="nv">$ </span>q
KDB+ 3.5 2018.04.25 Copyright <span class="o">(</span>C<span class="o">)</span> 1993-2018 Kx Systems
l64/ 4<span class="o">(</span>16<span class="o">)</span>core 7360MB jonny kodiak 127.0.1.1 EXPIRE 2019.05.21 jonathon.mcmurray@aquaq.co.uk KOD <span class="c">#4160315</span>

q<span class="o">)</span>.utl.require<span class="s2">"req"</span>
q<span class="o">)</span>.req.g<span class="s2">"https://httpbin.org/get"</span>
args   | <span class="o">(</span><span class="sb">`</span>symbol<span class="si">$()</span><span class="o">)!()</span>
headers| <span class="sb">`</span>Accept<span class="sb">`</span>Connection<span class="sb">`</span>Host<span class="sb">`</span>User-Agent!<span class="o">(</span><span class="s2">"*/*"</span><span class="p">;</span><span class="s2">"close"</span><span class="p">;</span><span class="s2">"httpbin.org"</span><span class="p">;</span><span class="s2">"kdb..
origin | "</span>146.199.80.196<span class="s2">"
url    | "</span>https://httpbin.org/get<span class="s2">"</span></code></pre></figure>

<p>I’ll be writing another post soon about using Anaconda to install packages for
<a href="https://github.com/nugend/qutil">qutil</a>, but for now, there’s a few packages available <a href="https://anaconda.org/jmcmurray/repo">on my repo</a>.</p>

<p>Note that due to the dependency system in Anaconda, by installing <code class="language-plaintext highlighter-rouge">req</code>, you’ll
also get <code class="language-plaintext highlighter-rouge">qutil</code> setup, as well as the <code class="language-plaintext highlighter-rouge">json</code> package to provide JSON support
below version 3.1, and the <code class="language-plaintext highlighter-rouge">qhttps</code> package, which enables HTTPS support in q,
using a set of certificates provided as an Anaconda package.</p>

<p>I intentionally did <em>not</em> make the package dependent on kx’s kdb package, so
you can use this no matter how you installed q; it will work with or without
the kx kdb conda package.</p>

<p>Hopefully you can find this library useful, feedback is very welcome! Let me 
know what you’re using it for, and feel free to open an issue on <a href="https://github.com/jonathonmcmurray/reQ">GitHub</a>
for any bugs or problems you encounter!</p>]]></content><author><name></name></author><category term="kdb" /><category term="q" /><category term="http" /><category term="req" /><summary type="html"><![CDATA[In previous blog posts, both here and on the AquaQ blog, I have mentioned the reQ HTTP library that I’ve been working on. And the time has come for an “official” release! reQ has reached a point where I think it can be quite useful, particularly for interacting with web APIs from q. You may be wondering what’s wrong with .Q.hg and .Q.hp, the built in HTTP request functions in q; reQ has a few nice additional features over these…]]></summary></entry><entry><title type="html">q as a WebSocket client</title><link href="/kdb/q/websocket/gdax/cryptocurrency/2018/06/09/q-as-a-websocket-client.html" rel="alternate" type="text/html" title="q as a WebSocket client" /><published>2018-06-09T00:00:00+00:00</published><updated>2018-06-09T00:00:00+00:00</updated><id>/kdb/q/websocket/gdax/cryptocurrency/2018/06/09/q-as-a-websocket-client</id><content type="html" xml:base="/kdb/q/websocket/gdax/cryptocurrency/2018/06/09/q-as-a-websocket-client.html"><![CDATA[<p>WebSockets are a technology enabling two-way communication between a client and
server over a single TCP connection, defined in <a href="https://tools.ietf.org/html/rfc6455">RFC6455</a>. Essentially
an initial “handshake” HTTP request is sent from client to server, requesting
an upgrade from HTTP to WebSocket protocol. The server responds with an Upgrade
message, and communciation begins.</p>

<p>q has been able to act as a WebSocket client since v3.2, but the default usage
is not the most intuitive, requiring the construction of a raw HTTP request
string to be sent to the server e.g.</p>

<figure class="highlight"><pre><code class="language-q" data-lang="q"><span class="kd">q)</span><span class="no">.z.ws</span><span class="o">:</span><span class="p">{</span><span class="kc">0N</span><span class="o">!</span><span class="n">x</span><span class="p">;}</span><span class="c1"> / print incoming msgs to console, no echo.</span>
<span class="kd">q)</span><span class="n">r</span><span class="o">:</span><span class="p">(</span><span class="ss">`</span><span class="o">$</span><span class="s">":ws://demos.kaazing.com"</span><span class="p">)</span><span class="s">"GET /echo HTTP/1.1</span><span class="se">\r\n</span><span class="s">Host: demos.kaazing.com</span><span class="se">\r\n\r\n</span><span class="s">"</span>
<span class="kd">q)</span><span class="n">r</span>
<span class="mi">4i</span>
<span class="s">"HTTP/1.1 101 Web Socket Protocol Handshake</span><span class="se">\r\n</span><span class="s">Connection: Upgrade</span><span class="se">\r</span><span class="s">..</span><span class="err">
</span><span class="s">q)neg[r 0]"</span><span class="n">echo</span><span class="s">"</span><span class="err">
</span><span class="s">q)"</span><span class="n">echo</span><span class="s">"</span></code></pre></figure>

<p>(In order to allow this, kdb+ automatically adds a number of header fields to
the HTTP request; <code class="language-plaintext highlighter-rouge">Sec-WebSocket-Key</code>, <code class="language-plaintext highlighter-rouge">Sec-WebSocket-Version</code>, 
<code class="language-plaintext highlighter-rouge">Sec-WebSocket-Extensions</code>, <code class="language-plaintext highlighter-rouge">Upgrade</code>, <code class="language-plaintext highlighter-rouge">Connection</code>)</p>

<p>In this example, an echo server is used which will simply echo whatever is sent
to it. Note that in addition to having to manually construct the query, the
handle returned is a positive int, while WebSockets require async messaging,
and therefore need a negative handle. Additionally, by default all messages
arriving over a WebSocket will be handled by <code class="language-plaintext highlighter-rouge">.z.ws</code>, which is a little tricky
if you’re connecting to multiple servers from one q session.</p>

<p>To combat these annoyances, I built <a href="https://github.com/jonathonmcmurray/ws.q">ws.q</a>. This is a very simple
library to wrap around the above functionality &amp; provide WebSocket client
functionality in a more convenient manner.</p>

<p>To set up <code class="language-plaintext highlighter-rouge">ws.q</code>, clone the repo recursively e.g.</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>git clone <span class="nt">--recursive</span> https://github.com/jonathonmcmurray/ws.q.git</code></pre></figure>

<p>(The <code class="language-plaintext highlighter-rouge">--recursive</code> flag is necessary to also pull reQ, an HTTP request library
which is used by <code class="language-plaintext highlighter-rouge">ws.q</code>; this allows easily building the initial HTTP requests)</p>

<p><code class="language-plaintext highlighter-rouge">ws.q</code> allows for multiple callback functions, one per connection, set when
opening a WebSocket connection. Opening a connection is via <code class="language-plaintext highlighter-rouge">.ws.open</code>, which
takes two arguments, the URL (as hsym, symbol or string) &amp; the name of callback
function for this connection (as symbol). <code class="language-plaintext highlighter-rouge">.ws.open</code> will return the negated
handle, ready for use in messaging. Taking the earlier example of the echo
server:</p>

<figure class="highlight"><pre><code class="language-q" data-lang="q"><span class="kd">q)</span><span class="o">\</span><span class="n">l</span><span class="w"> </span><span class="n">ws.q</span>
<span class="kd">q)</span><span class="n">.echo.upd</span><span class="o">:</span><span class="p">{</span><span class="nb">show</span><span class="w"> </span><span class="n">x</span><span class="p">}</span>
<span class="kd">q)</span><span class="n">.echo.h</span><span class="o">:</span><span class="n">.ws.open</span><span class="p">[</span><span class="s">"ws://demos.kaazing.com/echo"</span><span class="p">;</span><span class="ss">`.echo.upd</span><span class="p">]</span>
<span class="kd">q)</span><span class="n">.echo.h</span>
<span class="o">-</span><span class="mi">4i</span>
<span class="kd">q)</span><span class="n">.echo.h</span><span class="s">"echo"</span>
<span class="kd">q)</span><span class="s">"echo"</span></code></pre></figure>

<p>A table of open connections is found in <code class="language-plaintext highlighter-rouge">.ws.w</code>:</p>

<figure class="highlight"><pre><code class="language-q" data-lang="q"><span class="kd">q)</span><span class="n">.ws.w</span>
<span class="n">h</span><span class="o">|</span><span class="w"> </span><span class="n">hostname</span><span class="w">          </span><span class="n">callback</span>
<span class="o">-|</span><span class="w"> </span><span class="o">---------------------------</span>
<span class="mi">4</span><span class="o">|</span><span class="w"> </span><span class="n">demos.kaazing.com</span><span class="w"> </span><span class="n">.echo.upd</span></code></pre></figure>

<p>As mentioned before, it is possible to open multiple concurrent WebSocket
connetions:</p>

<figure class="highlight"><pre><code class="language-q" data-lang="q"><span class="kd">q)</span><span class="n">.bfx.upd</span><span class="o">:</span><span class="p">{</span><span class="n">.bfx.x</span><span class="o">,:</span><span class="nb">enlist</span><span class="w"> </span><span class="n">x</span><span class="p">}</span><span class="c1">                                   //define upd func for bitfinex</span>
<span class="kd">q)</span><span class="n">.spx.upd</span><span class="o">:</span><span class="p">{</span><span class="n">.spx.x</span><span class="o">,:</span><span class="nb">enlist</span><span class="w"> </span><span class="n">x</span><span class="p">}</span><span class="c1">                                   //define upd func for spreadex</span>
<span class="kd">q)</span><span class="n">.bfx.h</span><span class="o">:</span><span class="n">.ws.open</span><span class="p">[</span><span class="s">"wss://api.bitfinex.com/ws/2"</span><span class="p">;</span><span class="ss">`.bfx.upd</span><span class="p">]</span><span class="c1">      //open bitfinex socket</span>
<span class="kd">q)</span><span class="n">.spx.h</span><span class="o">:</span><span class="n">.ws.open</span><span class="p">[</span><span class="s">"wss://otcsf.spreadex.com/"</span><span class="p">;</span><span class="ss">`.spx.upd</span><span class="p">]</span><span class="c1">        //open spreadex socket</span>
<span class="kd">q)</span><span class="n">.bfx.h</span><span class="w"> </span><span class="n">.j.j</span><span class="w"> </span><span class="ss">`event`pair`channel</span><span class="o">!</span><span class="ss">`subscribe`BTCUSD`ticker</span><span class="c1">      //send subscription message over bfx socket</span>
<span class="kd">q)</span><span class="n">.bfx.x</span><span class="c1">                                                        //check raw messages stored</span>
<span class="s">"{\"event\":\"info\",\"version\":2,\"platform\":{\"status\":1}}"</span>
<span class="s">"{\"event\":\"subscribed\",\"channel\":\"ticker\",\"chanId\":3,\"symbol\":\"tBTCUSD\",\"pair\":\"BTCUSD\"}"</span>
<span class="s">"[3,[8903.2,67.80649424,8904.2,49.22740929,27.3,0.0031,8904.2,43651.93267067,9177.5,8752]]"</span>
<span class="kd">q)</span><span class="n">.spx.x</span><span class="c1">                                                        //check raw messages stored</span>
<span class="s">"{type:\"poll\"}"</span>
<span class="s">"{type:\"poll\"}"</span>
<span class="s">"{type:\"poll\"}"</span>
<span class="s">"{type:\"poll\"}"</span>
<span class="kd">q)</span><span class="n">.ws.w</span><span class="c1">                                                         //check list of opened sockets</span>
<span class="n">h</span><span class="o">|</span><span class="w"> </span><span class="n">hostname</span><span class="w">           </span><span class="n">callback</span>
<span class="o">-|</span><span class="w"> </span><span class="o">---------------------------</span>
<span class="mi">3</span><span class="o">|</span><span class="w"> </span><span class="n">api.bitfinex.com</span><span class="w">   </span><span class="n">.bfx.upd</span>
<span class="mi">4</span><span class="o">|</span><span class="w"> </span><span class="n">otcsf.spreadex.com</span><span class="w"> </span><span class="n">.spx.upd</span></code></pre></figure>

<p>Also present on the repo is an example WebSocket based feedhandler for the
<a href="https://www.gdax.com/">GDAX</a> cryptocurrency exchange, which provides a <a href="https://docs.gdax.com/#websocket-feed">WebSocket API</a>.
A number of other cryptocurrency exchanges provide WebSocket feeds, and I plan
to add more example feedhandlers to this repo in time for some of them; keep an
eye out for those if you’re interested! If there’s a particular feed you’d like
to get implemented, or if you’d like help to integrate the GDAX fh into your
kdb+ system, feel free to get in touch.</p>

<p>The repo also contains two files called <code class="language-plaintext highlighter-rouge">wsu.q</code> &amp; <code class="language-plaintext highlighter-rouge">wschaintick.q</code>; these files
provide functionality for a chained TP which republished data from a regular
tickerplant over WebSockets in JSON format - this will be the subject of a 
future post, but they should already be in a usable state if you need to stream
data from your TP over a WebSocket (e.g. perhaps to an HTML &amp; JS dashboard,
rather than using some form of polling).</p>]]></content><author><name></name></author><category term="kdb" /><category term="q" /><category term="websocket" /><category term="gdax" /><category term="cryptocurrency" /><summary type="html"><![CDATA[WebSockets are a technology enabling two-way communication between a client and server over a single TCP connection, defined in RFC6455. Essentially an initial “handshake” HTTP request is sent from client to server, requesting an upgrade from HTTP to WebSocket protocol. The server responds with an Upgrade message, and communciation begins.]]></summary></entry><entry><title type="html">Creating a REST API powered by kdb+/q</title><link href="/kdb/q/rest/api/2018/05/22/rest-api-in-kdb.html" rel="alternate" type="text/html" title="Creating a REST API powered by kdb+/q" /><published>2018-05-22T00:00:00+00:00</published><updated>2018-05-22T00:00:00+00:00</updated><id>/kdb/q/rest/api/2018/05/22/rest-api-in-kdb</id><content type="html" xml:base="/kdb/q/rest/api/2018/05/22/rest-api-in-kdb.html"><![CDATA[<p>A few weeks ago I published a post on the AquaQ Analytics (my employer) blog regarding using REST APIs in kdb+. You can read that blog post <a href="https://www.aquaq.co.uk/q/using-kdb-with-rest-apis/">on the AquaQ blog</a>. Just for fun, I decided to try building the “other side” - creating a REST API powered by kdb+. The result is found in my GitHub repo, <a href="https://github.com/jonathonmcmurray/qwebapi">qwebapi</a>.</p>

<p><img src="/assets/rest.png" alt="Creating a REST API powered by kdb+/q" class="center-image" /></p>

<p>You may be wondering why you would want to provide a REST API from kdb+ - it provides a very simple method of interoperability with other languages and technologies, beyond those with an existing interface (e.g. with <a href="https://code.kx.com/q/interfaces/fusion/">Fusion</a> interfaces from kx). Creating products such as web based dashboards is simplified by having data available over REST APIs, for example.</p>

<p>So far, the simple <code class="language-plaintext highlighter-rouge">api.q</code> script found in the repo supports defining functions for both GET &amp; POST HTTP methods, as well as defining default parameters and required parameters. In addition, basic HTTP authorization is supported, allowing restriction of access to authorized users.</p>

<p>Some of the ground work for building an HTTP API was already done in <a href="https://github.com/jonathonmcmurray/reQ">reQ</a>, an HTTP requests library, featured in the previously mentioned AquaQ blog point, and nearing a first “release”, at which point I’ll do a more detailed write-up here. Building on this, it was a fairly quick &amp; simple process to create a very basic HTTP API written in q. This is by no means a “production ready” library, and lacks a number of important features (e.g. error handling, logging etc.)</p>

<p>Using <code class="language-plaintext highlighter-rouge">api.q</code> is fairly simple; first of all, clone the repo (using the <code class="language-plaintext highlighter-rouge">--recurse-submodules</code> option to clone reQ as well):</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">jonny@kodiak ~ <span class="nv">$ </span>git clone <span class="nt">--recurse-submodules</span> https://github.com/jonathonmcmurray/qwebapi.git
jonny@kodiak ~ <span class="nv">$ </span><span class="nb">cd </span>qwebapi/
jonny@kodiak ~/qwebapi <span class="o">(</span>master<span class="o">)</span> <span class="nv">$ </span>tree <span class="nt">-L</span> 2
<span class="nb">.</span>
├── api.q
├── example.q
├── LICENSE
├── README.md
└── reQ
    ├── examples
    ├── json.k
    ├── LICENSE
    ├── README.md
    ├── req.q
    └── tests

3 directories, 8 files</code></pre></figure>

<p>Now, within a q session, load the <code class="language-plaintext highlighter-rouge">api.q</code> script &amp; set a port. In addition, define your API functions; these should be regular KDB functions, registered as an API function using the <code class="language-plaintext highlighter-rouge">.api.define</code> function. This function takes the name of the function, a dictionary of default values (which will be used for types), a list of required parameters and the supported HTTP methods (<code class="language-plaintext highlighter-rouge">`GET</code>,<code class="language-plaintext highlighter-rouge">`POST</code> or <code class="language-plaintext highlighter-rouge">`</code> for both).</p>

<p>Using <a href="https://raw.githubusercontent.com/KxSystems/kdb/master/sp.q">sp.q</a> from kx to provide some example data, here is a simple example of creating a basic API:</p>

<figure class="highlight"><pre><code class="language-q" data-lang="q"><span class="kd">q)</span><span class="o">\</span><span class="n">l</span><span class="w"> </span><span class="n">sp.q</span>
<span class="kd">q)</span><span class="o">\</span><span class="n">l</span><span class="w"> </span><span class="n">api.q</span>
<span class="kd">q)</span><span class="o">\</span><span class="n">p</span><span class="w"> </span><span class="mi">1235</span>
<span class="kd">q)</span><span class="n">example</span><span class="o">:</span><span class="p">{</span><span class="k">select</span><span class="w"> </span><span class="nb">distinct</span><span class="w"> </span><span class="n">p</span><span class="o">,</span><span class="n">s.city</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">sp</span><span class="p">}</span>
<span class="kd">q)</span><span class="n">.api.define</span><span class="p">[</span><span class="ss">`example</span><span class="p">;()</span><span class="o">!</span><span class="p">();();</span><span class="ss">`GET</span><span class="p">]</span>
<span class="kd">q)</span><span class="n">setcity</span><span class="o">:</span><span class="p">{[</span><span class="n">city</span><span class="p">]</span><span class="w"> </span><span class="n">cty</span><span class="o">::</span><span class="n">city</span><span class="p">;</span><span class="s">"City set to: "</span><span class="o">,</span><span class="nb">string</span><span class="w"> </span><span class="n">cty</span><span class="p">}</span>
<span class="kd">q)</span><span class="n">.api.define</span><span class="p">[</span><span class="ss">`setcity</span><span class="p">;(</span><span class="mi">1</span><span class="o">#</span><span class="ss">`city</span><span class="p">)</span><span class="o">!</span><span class="mi">1</span><span class="o">#</span><span class="ss">`</span><span class="p">;</span><span class="ss">`city</span><span class="p">;</span><span class="ss">`POST</span><span class="p">]</span>
<span class="kd">q)</span><span class="n">gets</span><span class="o">:</span><span class="p">{</span><span class="mi">0</span><span class="o">!</span><span class="k">select</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="ow">where</span><span class="w"> </span><span class="n">city</span><span class="o">=</span><span class="n">cty</span><span class="p">}</span>
<span class="kd">q)</span><span class="n">.api.define</span><span class="p">[</span><span class="ss">`gets</span><span class="p">;()</span><span class="o">!</span><span class="p">();();</span><span class="ss">`</span><span class="p">]</span>
<span class="kd">q)</span><span class="n">getp</span><span class="o">:</span><span class="p">{[</span><span class="n">city</span><span class="p">;</span><span class="n">color</span><span class="p">]</span><span class="n">ct</span><span class="o">:</span><span class="n">city</span><span class="p">;</span><span class="n">cl</span><span class="o">:</span><span class="n">color</span><span class="p">;</span><span class="mi">0</span><span class="o">!</span><span class="k">select</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="ow">where</span><span class="w"> </span><span class="n">city</span><span class="o">=</span><span class="n">ct</span><span class="o">,</span><span class="n">color</span><span class="o">=</span><span class="n">cl</span><span class="p">}</span>
<span class="kd">q)</span><span class="n">.api.define</span><span class="p">[</span><span class="ss">`getp</span><span class="p">;</span><span class="ss">`city`color</span><span class="o">!</span><span class="ss">`london`red</span><span class="p">;</span><span class="ss">`color</span><span class="p">;</span><span class="ss">`</span><span class="p">]</span></code></pre></figure>

<p>We now have a simple HTTP API running on port 1235; we can query this with any tool capable of sending HTTP queries. In other words, the vast majority of programming languages, a number of command line tools (cURL, wget etc.) and so on. For the sake of some examples, we’ll use <a href="https://www.getpostman.com/">Postman</a> to issue some queries to our API.</p>

<p>First off, we’ll call the <code class="language-plaintext highlighter-rouge">example</code> function defined above, with the <code class="language-plaintext highlighter-rouge">GET</code> method:</p>

<p><img src="/assets/example.png" alt="Example function call" /></p>

<p>Next up, we’ll set a city using <code class="language-plaintext highlighter-rouge">setcity</code>:</p>

<p><img src="/assets/invalid_method.png" alt="Invalid method" /></p>

<p>Oops, wrong method - when we called <code class="language-plaintext highlighter-rouge">.api.define</code> for this function, we only allowed POST requests:</p>

<p><img src="/assets/setcity.png" alt="setcity function call" /></p>

<p>That’s better! Now we can call <code class="language-plaintext highlighter-rouge">gets</code> to make use of the city we just set:</p>

<p><img src="/assets/gets.png" alt="gets" /></p>

<p>One function left, <code class="language-plaintext highlighter-rouge">getp</code>:</p>

<p><img src="/assets/missing_param.png" alt="Missing parameter" /></p>

<p>When we defined this one, we made <code class="language-plaintext highlighter-rouge">color</code> a required parameter, better include it with our request:</p>

<p><img src="/assets/getp.png" alt="getp" /></p>

<p>I haven’t shown the use of HTTP basic authorization, but it’s quite simple - start the process with <code class="language-plaintext highlighter-rouge">-auth user.txt</code> where user.txt is a text file containing <code class="language-plaintext highlighter-rouge">user:pass</code> combinations, one per line. Then, basic authorization will be enabled. Currently, HTTPS is not supported, although I may explore that option in a future post.</p>

<p>Additionally, in the above examples, for simplicity, I only used URL parameters to pass parameters to the functions; for POST requests, request bodies are also supported, supporting both <code class="language-plaintext highlighter-rouge">application/x-www-form-urlencoded</code> and <code class="language-plaintext highlighter-rouge">application/json</code> Content-Types. JSON, in particular, allows for more complex objects to be passed into the API if required for certain functions. For GET requests, only URL parameters can be used, and these work for POST requests also. Currently if the same parameter is in URL parameters &amp; POST body, the value from the URL parameter will be used preferentially.</p>

<p>For example, let’s define a trivial function that takes a dictionary as one of it’s parameters:</p>

<figure class="highlight"><pre><code class="language-q" data-lang="q"><span class="n">mapval</span><span class="o">:</span><span class="p">{[</span><span class="n">input</span><span class="p">;</span><span class="n">dict</span><span class="p">]</span><span class="w"> </span><span class="n">dict</span><span class="o">@</span><span class="n">input</span><span class="p">}</span>
<span class="n">.api.define</span><span class="p">[</span><span class="ss">`mapval</span><span class="p">;</span><span class="ss">`input`dict</span><span class="o">!</span><span class="p">(</span><span class="ss">`</span><span class="p">;</span><span class="ss">`a`b`c</span><span class="o">!</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">);</span><span class="ss">`input</span><span class="p">;</span><span class="ss">`POST</span><span class="p">]</span></code></pre></figure>

<p>Given this function requires a dictionary, we can’t pass that in URL parameters (so it makes no sense to allow GET requests) or a URL encoded body, but we can use a JSON body, for example:</p>

<p><img src="/assets/mapval.png" alt="mapval" /></p>

<p>It might be worth noting that kx have <a href="https://kx.com/news/kx-provides-rapid-access-to-unstructured-data/">recently announced</a> that the latest version of kdb+ (3.6) has enhanced support for unstructured data, with JSON support 10 times faster than in previous versions; this should make JSON based REST APIs considerably faster &amp; more efficient now! For further details on the 3.6 release see <a href="http://code.kx.com/q/ref/releases/ChangesIn3.6/">code.kx.com</a>.</p>

<p>As mentioned above, this is not really a “production ready” library, it is quite rudimentary and rough around the edges. The main point was to see if it was possible to write a REST API in pure q (which it is!). If you actually need to provide a kdb+ backed REST API, I suggest you keep an eye on <a href="https://github.com/AquaQAnalytics">AquaQ’s GitHub</a> and <a href="https://www.aquaq.co.uk/blog/">blog</a> for an upcoming open source release; I’m not a part of the team that’s been working on this, so I don’t know the full extent of the functionality etc., but I’m quite certain it’ll be a lot more polished and robust than this simple script!</p>]]></content><author><name></name></author><category term="kdb" /><category term="q" /><category term="rest" /><category term="api" /><summary type="html"><![CDATA[A few weeks ago I published a post on the AquaQ Analytics (my employer) blog regarding using REST APIs in kdb+. You can read that blog post on the AquaQ blog. Just for fun, I decided to try building the “other side” - creating a REST API powered by kdb+. The result is found in my GitHub repo, qwebapi.]]></summary></entry></feed>