Exposing APL Business Logic as JSON Endpoints in Dyalog
Dyalog's built-in JSON support and HTTP server let you wrap APL functions as REST endpoints without external middleware, but concurrency and state management require care.
06 Aug 2025, 22:48 UTC

The last mile problem
Your team keeps critical pricing logic in an APL function. It works, it is fast, and nobody wants to rewrite it. But the new customer portal is written in JavaScript, the mobile team wants a REST endpoint, and an integration partner asked for JSON. Wrapping the APL in a batch file that writes to a shared directory is fragile. Standing up a separate application server adds a second language, a second deployment pipeline, and a second set of bugs. The practical question is how to expose that APL logic as a network service without abandoning the interpreter.
Dyalog's answer is to let the workspace host HTTP endpoints directly. Combined with its built-in JSON support, you can turn an APL function into a stateless web service in a few dozen lines. This is not a full web framework, and it will not replace your API gateway. But for the narrow job of exposing array-oriented business logic to JSON clients, it removes an entire layer of middleware.
JSON as the integration contract
Before HTTP, you need a data format both sides agree on. Dyalog provides ⎕JSON, a system function that converts between JSON text and APL arrays or namespaces. A JSON object becomes an APL namespace, arrays become vectors, and numbers and strings map to their APL equivalents. The reverse conversion works the same way.
The important detail is that ⎕JSON is strict about structure. If your APL function returns a nested array, it serializes to a nested JSON array. If the client expects a dictionary with named keys, you must build an APL namespace, not a matrix. Getting this mapping right is usually the first debugging task, not the HTTP plumbing.
Hosting the endpoint with HttpServer
Dyalog includes an HttpServer class. In a recent version of the interpreter, you subclass it and override the request handler. The server runs in its own thread, which means your workspace must be thread-safe: any global variables or shared resources accessed by the endpoint need protection, or the endpoint must be written as a pure function.
This is the main architectural decision. If your APL code relies on global state—say, a cached lookup table—you have two options. You can serialize access with a critical section, or you can pre-load the data into each request handler and keep the endpoint stateless. The second option scales more predictably, but it costs memory if the dataset is large.
A worked example: sum two numbers
Suppose the client sends a POST body of {"a":5,"b":7} and expects {"sum":12} back. The core APL function is trivial:
∇ json←AddTwo json;data;result
data←⎕JSON json ⍝ parse inbound JSON
result←⎕NS ''
result.sum←(data.a)+data.b
json←⎕JSON result ⍝ serialize outbound JSON
∇
In the HTTP handler, you parse the request body, call this function, and set the response content type to application/json. The exact method names depend on the Dyalog version, so consult the version-specific documentation for HttpServer and HttpResponse. The pattern, however, is stable: parse, compute, serialize, respond.
Concurrency and state: the real constraint
The biggest limitation is not throughput; it is correctness under concurrency. APL's global variables are convenient in a single-user session, but an HTTP server is inherently multi-threaded. A race condition on a global counter or an unprotected ⎕FX edit can corrupt state across requests.
Start with endpoints that are pure functions of their input. If you must share state, use Dyalog's threading primitives to lock access, and test with concurrent clients before production. Also remember that the HTTP server does not provide authentication, rate limiting, or TLS termination out of the box; you will likely need a reverse proxy for those concerns.
Getting started
Pick one read-only endpoint from your existing APL codebase. Wrap it with ⎕JSON input and output, host it with HttpServer, and measure the round-trip latency from a test client. If the performance is acceptable, expand to write operations with proper locking. If not, keep the APL logic but move the HTTP boundary to a separate service that calls the APL through a queue or file interface. Either way, you avoid rewriting the business logic while still meeting the integration deadline.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.