| Did you know ... | Search Documentation: |
| Pack logtalk -- logtalk-3.101.0/docs/handbook/_sources/libraries/http_client.rst.txt |
.. _library_http_client:
http_client
The http_client library provides a request-oriented client layer on
top of the http_core, url, and HTTP transport libraries. It is
the request-oriented client-side entry point: it builds normalized
requests from absolute URLs plus options and delegates transport to the
selected http_transport_protocol-compatible layer, such as
http_socket_transport or http_process_transport.
This library can be used with backend Prolog systems that support
unbound integer arithmetic and the sockets library: ECLiPSe, SICStus
Prolog, SWI-Prolog, Trealla Prolog, and XVM.
By default, transport(default) selects http_socket_transport for
http:// and ws:// URLs, and http_process_transport for
https:// and wss:// URLs. Applications can select a transport
explicitly with the transport/1 option when they need lower-level
control or a custom transport object.
When the selected transport supports secure schemes, the
request-oriented facade defaults https:// and wss:// URLs
without an explicit port to port 443 and adds
connection_transport(tls) to the connection options automatically
unless already specified explicitly. This TLS-aware behavior applies
notably to http_process_transport, which provides transport support
for secure schemes via the same http_transport_protocol interface.
Open the `../../apis/library_index.html#http_client <../../apis/library_index.html#http_client>`__ link in a web browser.
To load the library, load the loader.lgt file:
::
| ?- logtalk_load(http_client(loader)).
To test this library, load the tester.lgt file:
::
| ?- logtalk_load(http_client(tester)).
The examples below are self-contained. They use the high-level
http_server facade to start a local loopback server, so they can be
reproduced without any external service. They assume that both
http_client(loader) and http_server(loader) are loaded and that
the backend supports threads, as the http_server::start/4-5 and
http_server::stop/1 helpers run the local server concurrently with
the client call.
Define a small echo handler once:
::
:- object(notes_http_client_echo_handler,
implements(http_handler_protocol)).
handle(Request, Response) :-
http_core::version(Request, Version),
http_core::body(Request, Body),
http_core::response(Version, status(200, 'OK'), [], Body, [], Response).
:- end_object.
Start a local server, send a request, and inspect the normalized
response. The unbound Port argument is unified with the actual port
selected by the backend:
::
| ?- http_server::start('127.0.0.1', Port, notes_http_client_echo_handler, Server, []),
atomic_list_concat(['http://127.0.0.1:', Port, '/echo'], URL),
http_client::post(URL, content('text/plain', text(hello)), Response, []),
http_server::stop(Server).
Response = response(http(1,1), status(200, 'OK'), _, content('text/plain', text(hello)), _).
The QUERY method uses the same body-carrying convenience shape as POST, PUT, and PATCH:
::
| ?- http_server::start('127.0.0.1', Port, notes_http_client_echo_handler, Server, []),
atomic_list_concat(['http://127.0.0.1:', Port, '/contacts'], URL),
http_client::query(URL, content('application/x-www-form-urlencoded', form([limit-'10'])), Response, []),
http_server::stop(Server).
Response = response(http(1,1), status(200, 'OK'), _, content('application/x-www-form-urlencoded', form([limit-'10'])), _).
For a multipart form-data request, define a handler that inspects the
normalized request body using http_multipart:
::
:- object(notes_http_client_multipart_handler,
implements(http_handler_protocol)).
handle(Request, Response) :-
http_core::version(Request, Version),
http_core::body(Request, Body),
http_multipart::fields(Body, [field(title, Title, _FieldParameters)]),
http_multipart::files(Body, [file(upload, Filename, 'text/plain', text(hello), _FileParameters)]),
atomic_list_concat(['title=', Title, '; upload=', Filename], Text),
http_core::response(Version, status(200, 'OK'), [], content('text/plain', text(Text)), [], Response).
:- end_object.
An example form-data request can then be:
::
start('127.0.0.1', Port, notes_http_client_multipart_handler, Server, []),
atomic_list_concat(['http://127.0.0.1:', Port, '/upload'], URL),
http_client::post(
URL,
form_data([
field(title, 'Logtalk', []),
file(upload, 'notes.txt', 'text/plain', text(hello), [])
]),
Response,
[]
),
http_server::stop(Server).
Response = response(http(1,1), status(200, 'OK'), _, content('text/plain', text('title=Logtalk; upload=notes.txt')), _).
For a WebSocket opening handshake, define a handler that accepts the upgrade:
::
:- object(notes_http_client_websocket_handler,
implements(http_handler_protocol)).
handle(Request, Response) :-
http_server_core::accept_websocket(Request, Response, [protocol(chat)]).
:- end_object.
An example opening handshake query can then be:
::
| ?- http_server::start('127.0.0.1', Port, notes_http_client_websocket_handler, Server, []),
atomic_list_concat(['ws://127.0.0.1:', Port, '/socket'], URL),
http_client::open_websocket(URL, Connection, Response, [protocols([chat]), key('dGhlIHNhbXBsZSBub25jZQ==')]),
http_socket_transport::close_connection(Connection),
http_server::stop(Server).
Response = response(http(1,1), status(101, 'Switching Protocols'), _, empty, _).
The Connection term returned by open_websocket/4 remains open.
After the handshake, either close it explicitly with
http_socket_transport::close_connection/1 or hand it to the
http_websocket, http_websocket_messages,
http_websocket_session, or http_websocket_service libraries.
The initial request-oriented implementation provides:
101
response.get/3-4, head/3-4, delete/3-4, post/4-5, put/4-5,
and patch/4-5 convenience predicates.
When the same request-construction or WebSocket opening-handshake option is given multiple times, the first occurrence is used.
Supported request options are:
transport(Transport) to select the transport object. Default:
default, which selects the transport from the URL scheme.headers(Headers) to supply normalized request headers.body(Body) to supply a normalized request body. The
request-oriented facade also accepts body(form_data(Items)) as a
convenience descriptor for multipart form-data requests; in that case
it builds the multipart body via http_multipart and injects a
generated boundary property unless the caller already provided one in
properties/1.query(Pairs) to append URL-encoded query pairs to the URL query
string.version(Version) to override the default http(1,1) version.properties(Properties) to supply additional normalized request
properties.connection_options(Options) to pass transport-specific options
through to the underlying open_connection/4 call for one-shot
requests. When the URL uses the https:// scheme,
connection_transport(tls) is added automatically unless
Options already specify a transport explicitly.
Supported WebSocket opening-handshake options are:
transport(Transport) to select the transport object. Default:
default, which selects the transport from the URL scheme.headers(Headers) to supply additional normalized handshake request
headers other than the handshake-managed headers.query(Pairs) to append URL-encoded query pairs to the URL query
string.version(Version) to override the default http(1,1) version.
The opening handshake requires HTTP/1.1 or later.protocols(Protocols) to request one or more subprotocol tokens.key(Key) to provide an explicit Sec-WebSocket-Key value. When
omitted, a fresh key is generated automatically.connection_options(Options) to pass transport-specific options
through to the selected transport open_connection/4 predicate.
When the URL uses the wss:// scheme, connection_transport(tls)
is added automatically unless Options already specify a transport
explicitly.
The stream-based primitives remain available from the
http_client_core object.
The current multipart workflow is intentionally small but practical:
content(MediaType, multipart(Parts)) terms.form_data(Items)
through the existing body path, including post/4-5, put/4-5,
and patch/4-5.Items descriptors are the same
field(Name, Value, Parameters) and
file(Name, Filename, MediaType, Payload, Parameters) descriptors
supported by the http_multipart::form_data_body/2 helper.Parameters is the ordered list of extra
Content-Disposition: form-data parameters to preserve or generate.name and filename parameters stay explicit helper
arguments and must not be repeated in the Parameters list.For example, callers can send extra disposition parameters explicitly:
::
| ?- http_client::post(
URL,
form_data([
field(title, 'Logtalk', [charset-utf8]),
file(upload, 'notes.txt', 'text/plain', text(hello), [creation_date-'2026-06-08'])
]),
Response,
[]
).
The current WebSocket workflow is intentionally limited to the opening handshake:
101
response including the Sec-WebSocket-Accept value.http_websocket frame predicates, the
http_websocket_messages message predicates, or the stateful
http_websocket_session predicates with explicit close-state and
automatic control-message handling, including the higher-level
http_websocket_service run_session/3-4 callback loop.http_websocket_client_service::open/4-5 predicates
layer on top of open_websocket/4, can write optional initial
outbound messages, and then run the callback-driven session loop.http_websocket_service::run_session/3-4 predicates do take
ownership of the upgraded connection and close it automatically when
the session loop finishes, as do the higher-level
http_websocket_client_service::open/4-5 predicates.