Web Programming

SWI-Prolog ships a production-grade HTTP stack (it powers swi-prolog.org and SWISH).

41.1 A minimal web server

:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/html_write)).
:- use_module(library(http/http_parameters)).

:- http_handler(root(.), home, []).
:- http_handler(root(hello), hello, []).

server(Port) :- http_server(http_dispatch, [port(Port)]).

home(_Request) :-
    reply_html_page(title('Prolog Web'),
        [ h1('Hello from Prolog!'),
          p(['Try ', a(href('/hello?name=Ann'), '/hello?name=Ann')]) ]).

hello(Request) :-
    http_parameters(Request, [name(Name, [default(world)])]),
    reply_html_page(title('Hello'), [h1(['Hello, ', Name, '!'])]).

?- server(8080).

41.2 JSON APIs

:- use_module(library(http/http_json)).
:- use_module(library(http/json)).

:- http_handler(root(api/users), users_api, [method(get)]).
:- http_handler(root(api/echo), echo_api, [method(post)]).

users_api(_Request) :-
    findall(_{name: N, age: A}, user(N, A), Users),
    reply_json_dict(_{users: Users}).

echo_api(Request) :-
    http_read_json_dict(Request, Dict),
    reply_json_dict(_{received: Dict}).

user(ann, 30). user(bob, 25).

% JSON <-> terms/dicts
?- atom_json_dict('{"a": [1, 2]}', D, []).     % D = _{a:[1, 2]}
?- atom_json_term(A, json([x=1]), []).
?- json_write_dict(current_output, _{ok: true}).

41.3 HTTP client

:- use_module(library(http/http_open)).
:- use_module(library(http/http_client)).

?- setup_call_cleanup(http_open('https://api.github.com/repos/SWI-Prolog/swipl-devel', In, []),
                      json_read_dict(In, D), close(In)),
   X = D.stargazers_count.

?- http_get('https://example.com', Body, []).
?- http_post(URL, json(_{a: 1}), Reply, [json_object(dict)]).

41.4 More web features

HTML generation DSL (html//1, html_write), templates, library(http/js_write) for JavaScript.

Sessions (http_session), authentication (http_authenticate), CORS, HTTPS (library(ssl)), WebSockets (http_upgrade_to_websocket), server-sent events.

Pengines: run Prolog queries remotely from JavaScript or other Prologs (pengine_rpc/3).

SWISH: web-based Prolog notebooks; self-host for teams.

Deployment: http_daemon with systemd, behind nginx; Docker images (swipl official image).