Interfacing with Angular

Thanks for sharing.

This is a bit old. New code better use library(http/http_dyn_workers) or load all server basics using library(http/http_server).

On public ports some browsers insist on https (wss). If you use nginx as proxy you need something like below. This rule is from SWISH. The first two lines (resolver and proxy_pass) are there to find the lxc container in which SWISH runs and probably needs adapting.

        location /chat {
                resolver 10.0.3.1;
                proxy_pass http://$container$request_uri;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header X-Real-IP $remote_addr;
                proxy_read_timeout 86400;
        }
1 Like

simpelst is to set up de swi- http server, then test that you can output data on http requests, then let the output be in JSON for example, then in Angular you can make ajax http calls, receive the data and let it parse and use the data

1 Like

Agree. Websockets have benefits especially when server push is required or to reduce latency. They also come at a price. It is an open connection that easily breaks on some network issue and requires support in proxy servers. That is more readily available these days, but still not always guaranteed :frowning:

A good use case is probably using a browser as GUI for an application on the same host or in a LAN, so connection issues are irrelevant and latency really goes down to the sub-millisec range.

I’m a bit lost here. Do I simply add this library to the list as in

and then simply shorten the command to start the server to

swipl server.pl --port=6455 --pidfile=http.pid

or do I need to add anything else to the Prolog script?

That is just fine. The http_server.pl library loads a reasonable part of the server architecture that just about any server needs. This avoid having to remember all the basic server libraries. Add what is missing (in this case websockets and the Unix daemon infrastructure) and you’re ready to go.

1 Like

After several hours of trying to get wss:// and nginx to play nicely, I’ve conceded defeat and got JavaScript in the browser and SWI Prolog server to communicate via JSON like so:

:- use_module(library(http/http_server)).
:- use_module(library(http/http_files)).
:- use_module(library(http/http_unix_daemon)).

:- initialization http_daemon.

:- http_handler(root(.), http_reply_from_files('.', [indexes(['./index.html'])]), [prefix]).
:- http_handler(root(prolog), prolog_handler, []).

prolog_handler(Request) :-
  http_read_json_dict(Request, DictIn),
  request_handler(DictIn.request, DictIn, DictOut),
  reply_json_dict(DictOut).

request_handler("ping", _Dict, json{reply: pong}).

Browser code:

function prologServer(Request) {
  return fetch("prolog",
  { method: "POST"
  , headers: { "Content-Type": "application/json"}
  , body: JSON.stringify(Request)
  }
);
}

prologServer({"request": "ping"})
.then(response => response.json())
.then(data => document.querySelector("#message").innerText = data.reply);

The next interesting question is how to format the Json values so that Prolog and Javascript can use it as a lingua franca.

Using the introductory example from Bratko as an example by initial thought is if the Prolog looks like:

parent(pam, bob).
parent(tom, bob).
parent(tom, liz).
parent(bob, pat).
parent(pat, jim).

Then the Json should be

[ ["parent", "pam", "bob"],
  ["parent", "tom",  "bob"],
  ["parent", "tom", "liz"],
  ["parent", "bob", "pat"],
  ["parent", "pat", "jim"]
]

which the Prolog script could then iteratively translate with term_string (?Term, ?String) and then Term =.. List to translate, and then do the reverse in the reply to the browser.

Though not difficult, I wondered if there’s already a convention and libraries to do this?

Not sure if it covers all your need, but check out this library:

https://www.swi-prolog.org/pldoc/man?section=termtojson

1 Like

Thanks @torbjorn.lager

I managed to get what I wanted:

?- json_prolog([["parent", "pam", "bob"],["parent", "tom", "bob"],["parent", "tom", "liz"], ["parent", "bob", "pat"],["parent", "pat", "jim"]], Terms).
Terms = [parent(pam, bob), parent(tom, bob), parent(tom, liz), parent(bob, pat), parent(pat, jim)].

?- json_prolog(L, [parent(pam, bob), parent(tom, bob), parent(tom, liz), parent(bob, pat), parent(pat, jim)]).
L = [["parent", "pam", "bob"], ["parent", "tom", "bob"], ["parent", "tom", "liz"], ["parent", "bob", "pat"], ["parent", "pat", "jim"]].

With the little module below. Making this bidirectional was a bit of a hack, but it works. I might need to make it more elaborate to handle nested lists/compounds, but this is all I need for now:

:- module(json_prolog, [json_prolog/2]).

unquote_quote(Unquoted, Quoted) :-
  maplist(term_string, Unquoted, Quoted).

json_prolog(QLists, PrologList) :-
  nonvar(QLists), var(PrologList), !,
  maplist(unquote_quote, UQLists, QLists),
  maplist(=.., PrologList, UQLists).

json_prolog(QLists, PrologList) :-
  var(QLists), nonvar(PrologList), !,
  maplist(=.., PrologList, UQLists),
  maplist(unquote_quote, UQLists, QLists).
1 Like

I have some code that uses “bare” JavaScript (using WindowOrWorkerGlobalScope.fetch()) and a simple Prolog server using http_handler and http_read_json_dict. If anyone is interested, I can excerpt a simple code example (it’ll take me a few hours; but the code needs some refactoring anyway).

It would be nice to have a simple self-contained example code for that.

If you find the time to do it, I would be interested to look at a minimum viable example with comments to explain what does what and where to put our own business code. Thanks for offering !