Web Sockets - very basic example

This is very basic example code demonstarting web sockets using SWI-Prolog. There are three files, sever.pl, index.html and time.js. While the code could be further refactored it is left in its present form as it is typical of standard use cases.

File: server.pl

:- module(server,[]).

:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/websocket)).

:- initialization
    http_server(http_dispatch, [port(8000)]).

:- http_handler(root(.),          http_reply_file('index.html', []), []).
:- http_handler(root('time.js'),  http_reply_file('time.js',    []), []).
:- http_handler(root(time),
    http_upgrade_to_websocket(time_handler, []),

time_handler(WebSocket) :-
    ws_receive(WebSocket, Message, [format(json)]),  % This waits until a message is received.
        Message.opcode == close
        ws_send(WebSocket, json(Response_dict)),

time_response(Response_dict) :-
    format_time(string(Message), '%c', Time),
    dict_create(Data, _, [message-Message]),
    dict_create(Response_dict, _, [data-Data,format-json,opcode-text]).

File: index.html

<!DOCTYPE html>
  <title>Web Socket Example</title>
  <script charset="utf-8" src="time.js"></script>
  <h2>Current Time</h2>
  <p id="time">&nbsp;</p>
  <button id="message-submit" type="button">Get current time</button>

File: time.js

// Called when page loads
document.addEventListener('DOMContentLoaded', (e) => {
  const input_button = document.getElementById("message-submit")
  const connection = openWebSocket()
  input_button.addEventListener("click", (event) => {

// Called by addEventListener to get the connection when page loads
function openWebSocket() {
  connection = new WebSocket("ws://" + window.location.host + "/time")
  connection.onerror = (error) => {
  connection.onmessage = wsMessageHandler
  return connection

// Called when Web Socket message arrives.
function wsMessageHandler(event) {
  const payload = JSON.parse(event.data)
  const message = payload.data.message
  document.getElementById("time").innerHTML = message

Example run

Using SWI-Prolog

Welcome to SWI-Prolog (threaded, 64 bits, version 9.1.6)

?- working_directory(_,'C:/Users/Groot)').

?- [server].
% Started server at http://localhost:8000/


then using an Internet browser

URL: http://localhost:8000/

The page will load looking like this


click Get current time will update the time and look like this



Explain code to a programmer new to Prolog, HTML and JavaScript.

Note: All of the code above was included in the prompt

ChatGPT Completion

This code sets up a simple web socket server that responds to requests for the current time.

The server.pl module sets up the server using the http_server predicate from the http/thread_httpd library. It also registers several handlers for different URLs.

The handler for the root URL (/) responds with the index.html file, which contains a button and a placeholder for the current time.

The handler for the /time URL upgrades the connection to a web socket and passes it to the time_handler predicate. This predicate waits for a message from the web socket and then responds with the current time in a JSON format. It then waits for another message and repeats the process.

The index.html file contains a script (time.js) that sets up an event listener on the button. When the button is clicked, it sends an empty JSON message to the web socket connection.

The script also defines two functions (openWebSocket and wsMessageHandler) that handle the web socket connection. openWebSocket sets up the connection and registers a message handler. wsMessageHandler extracts the time from the JSON payload and updates the placeholder in the HTML file.

Overall, this code demonstrates a simple example of a web socket server and client that communicate using JSON messages.

For more basic examples of working code see

If you know web sockets you will notice that this is not demonstrating an automatic push of data to the page. That can be easily be done but that makes the very basic example a bit more complicated and picks a specific use case so was not done.

Note: You may find it difficult to get ChatGPT to generate such an example as it struggles with certain parts of SWI-Prolog. The lack of examples for certain modules and predicates means that ChatGPT often hallucinates to get a completion which can be incorrect. However, if you are a skilled Prolog programmer, you can work out the kinks. The prompt can became so detailed in instructions that it was not worth using ChatGPT.