HTTP Client Functions
This module contains functions to send HTTP requests and handle HTTP responses:
http:get,http:postand the other functions provide a map-based interface: requests are controlled by typed options, and the response is returned as a single record.http:send-requestis based on the EXPath HTTP Client Module.
Both interfaces can be used side by side. See Extensions for the features that BaseX adds to the specification. For simple GET requests, the Fetch Functions may be sufficient.
Despite the similar name, the Client Module is unrelated: it addresses BaseX server instances, whereas this module sends generic HTTP requests.
Conventions
All functions are in the http://expath.org/ns/http-client namespace, to which the http prefix is statically bound.
The errors of http:send-request are in the http://expath.org/ns/error namespace, to which the experr prefix is statically bound. The errors of the other functions are in the namespace of the module.
Functions
http:delete
Added: New function.
| Signature | http:delete( $href as xs:string, $options as map(*)? := {}) as http:response-recordcreate | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Summary | Sends a DELETE request to the URI $href and returns the response.
Notes:
| ||||||||||||
| Errors |
|
http:get
Added: New function.
| Signature | http:get( $href as xs:string, $options as map(*)? := {}) as http:response-recordcreate | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Summary | Sends a GET request to the URI $href and returns the response.
Notes:
| ||||||||||||
| Errors |
| ||||||||||||
| Examples | Result: 200 |
http:head
Added: New function.
| Signature | http:head( $href as xs:string, $options as map(*)? := {}) as http:response-recordcreate | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Summary | Sends a HEAD request to the URI $href and returns the response. A HEAD response has no body.
Notes:
| ||||||||||||
| Errors |
|
http:options
Added: New function.
| Signature | http:options( $href as xs:string, $options as map(*)? := {}) as http:response-recordcreate | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Summary | Sends an OPTIONS request to the URI $href and returns the response.
Notes:
| ||||||||||||
| Errors |
|
http:patch
Added: New function.
| Signature | http:patch( $href as xs:string, $body as item()* := (), $options as map(*)? := {}) as http:response-recordcreate | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Summary | Sends a PATCH request with the body $body to the URI $href and returns the response. See http:post for the conversion of the body.
Notes:
| ||||||||||||||||
| Errors |
|
http:post
Added: New function.
| Signature | http:post( $href as xs:string, $body as item()* := (), $options as map(*)? := {}) as http:response-recordcreate | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Summary | Sends a POST request with the body $body to the URI $href and returns the response.
The media type of the request, and the way the body is serialized, are derived from the type of the supplied item:
A Notes:
| ||||||||||||||||
| Errors |
|
http:put
Added: New function.
| Signature | http:put( $href as xs:string, $body as item()* := (), $options as map(*)? := {}) as http:response-recordcreate | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Summary | Sends a PUT request with the body $body to the URI $href and returns the response. See http:post for the conversion of the body.
Notes:
| ||||||||||||||||
| Errors |
|
http:query
Added: New function.
| Signature | http:query( $href as xs:string, $body as item()* := (), $options as map(*)? := {}) as http:response-recordcreate | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Summary | Sends a QUERY request with the body $body to the URI $href and returns the response. The QUERY method requests a resource without changing the state of the server. See http:post for the conversion of the body.
Notes:
| ||||||||||||||||
| Errors |
|
http:send
Added: New function.
| Signature | http:send( $href as xs:string, $method as xs:string, $body as item()* := (), $options as map(*)? := {}) as http:response-recordcreate | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Summary | Sends a request with the method $method and the body $body to the URI $href and returns the response. It can be used for methods that have no function of their own. Method names are case-sensitive and sent unchanged. See http:post for the conversion of the body.
Notes:
| ||||||||||||||||
| Errors |
|
http:send-request
Updated: New cookies, proxy, verify and xml attributes; follow-redirect accepts a maximum number of redirects; auth-method is case-insensitive; timeout accepts fractions of a second; href and version attributes in the response element.
| Signature | http:send-request( $request as element(http:request)?, $href as xs:string? := (), $bodies as item()* := ()) as item()+create | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Summary | Sends an HTTP request and interprets the corresponding response:
Notes:
| ||||||||||
| Errors |
|
Request Options
The following options can be supplied via the $options argument of http:get, http:post and the other functions with a map-based interface:
| Option | Description | Allowed | Default |
|---|---|---|---|
headers |
HTTP header fields. A field with an empty sequence as value is not sent; this also suppresses a field that would otherwise be added, such as User-Agent. |
map(xs:string, xs:string*) |
{} |
query |
Query parameters, appended to the query string of the URI. Keys and values are URI-encoded, and a key with several values yields one parameter per value. | map(xs:string, xs:anyAtomicType*) |
none |
auth |
Credentials, with the entries username, password, method (basic or digest) and preemptive. By default, credentials are only sent after the server has requested them. With preemptive, Basic credentials are sent with the first request; it has no effect on Digest authentication. |
http:auth-record |
none |
cookies |
Stores the cookies that a server assigns, and sends them with the subsequent requests of the query. | true, false |
false |
redirects |
Defines if redirects are followed. An integer limits their number; 0 returns the redirect response itself, and exceeding the limit raises an error. A 303 response, and a 301 or 302 response to a POST request, is followed with a GET request without body. Redirects from https to http are not followed, and the Authorization and Cookie header fields are not sent to another origin. |
boolean, integer | true |
timeout |
Maximum number of seconds to wait for a connection, for the response headers, and for further data while the body is read. Fractions of a second can be supplied. | xs:decimal |
none |
multipart |
Sends the items of the body as the parts of a multipart body. Each part is a record with the entries headers and body. The media type is multipart/form-data, unless another multipart type is supplied via the Content-Type header field. Form data parts need a Content-Disposition header field (see File Upload). |
true, false |
false |
response-body |
Representation of the response body: parsed by media type, returned as string or binary item, or discarded. Only parse splits a multipart body into its parts. |
parse, text, binary, none |
parse |
encoding |
Character encoding of the response body. It replaces the charset parameter of the media type. |
encoding | none |
parse-options |
Options for the parsing of response bodies, with the entries xml, html, json and csv. They are passed on to the corresponding parsers. Options that fetch external resources (trust-external, xinclude, use-xsi-schema-location) are rejected. |
http:parse-options-record |
none |
proxy |
Proxy server, supplied as URI with host and port (e.g. http://proxy:8080). A zero-length string requests a direct connection. Without this option, the PROXYHOST options apply. |
URI | none |
verify |
Verifies the certificate of an HTTPS server. If disabled, any certificate is accepted, but the host name must still match the certificate unless the IGNORECERT option is enabled. |
true, false |
true |
certificates |
Key stores for HTTPS connections: trust replaces the default trust store of the JVM, client supplies a key for client authentication. See Certificates for the entries. |
map(*) |
none |
Some options are supplied as records. Their types are known in the static context, so they can also be used in type declarations. Entries that are not declared are rejected, and entries with a ? in their type can be omitted:
declare record http:auth-record(
username as xs:string,
password as xs:string,
method as xs:string?, (: 'basic' or 'digest'; default: 'basic' :)
preemptive as xs:boolean? (: default: false() :)
);
declare record http:parse-options-record(
xml as map(*)?,
html as map(*)?,
json as map(*)?,
csv as map(*)?
);
declare record http:part-record(
headers as map(xs:string, xs:string*)?,
body as item()?
);
A function that processes a part can thus be declared as follows:
declare function local:name($part as http:part-record) as xs:string? {
$part?headers?Content-Disposition
};
Certificates
The certificates option is a map with two optional entries. Both are maps that reference a key store:
| Entry | Description |
|---|---|
trust |
Trust store with the certificates of the servers or certificate authorities that are accepted. It replaces the default trust store of the JVM, and it is ignored if verify is false. Entries: keystore, keystore-password. |
client |
Key store with the private key and certificate that are sent to servers requiring client authentication. Entries: keystore, keystore-password, password. |
keystore is the path or URL of the key store. Files with the suffix .jks are read as Java key stores, all others as PKCS #12 files (.p12, .pfx). keystore-password unlocks the key store, and password unlocks the private key in the client store. The alias entry for selecting a key is not supported yet:
http:get('https://internal.example.com/api', {
'certificates': {
'trust': { 'keystore': 'certs/ca.p12', 'keystore-password': 'changeit' },
'client': { 'keystore': 'certs/client.p12', 'keystore-password': 'secret', 'password': 'secret' }
}
})
Response Record
These functions return a record of the type http:response-record, which can equally be used in type declarations. All entries are always present:
| Entry | Type | Description |
|---|---|---|
status |
xs:integer |
HTTP status code. A status such as 404 or 500 does not raise an error. |
headers |
map(xs:string, xs:string+) |
Response header fields. Names are returned in lower case, and each field line yields a separate value. |
body |
item()* |
Response body. It is empty if the response has no body, or if the body is discarded. |
href |
xs:string |
URI of the response. If redirects were followed, it is the URI of the final request. |
version |
xs:string |
HTTP version of the response: 1.0, 1.1, 2 or 3. |
Request 1.0 Attributes
The following attributes can be attached to the http:request element. All of them are defined by the EXPath specification, except for cookies, proxy, verify, xml, csv, json and html:
| Attribute | Description | Allowed | Default |
|---|---|---|---|
method |
Defines the HTTP request method. | HTTP verb, case-insensitive | required |
href |
Defines the target URI. It is only considered if the $href argument is empty. |
URI | none |
status-only |
If enabled, the response body is discarded, and only the response element is returned. | true, false |
false |
override-media-type |
Overrides the media type of the response, and hence the way the body is converted. | media type | none |
proxy |
Proxy server for this request. A zero-length string requests a direct connection. Without this attribute, the PROXYHOST options apply. |
URI | none |
verify |
Verifies the certificate of an HTTPS server. If disabled, any certificate is accepted, but the host name must still match the certificate unless the IGNORECERT option is enabled. |
true, false |
true |
xml |
Options for parsing XML response bodies. Options that fetch external resources (trust-external, xinclude, use-xsi-schema-location) are rejected. |
options string | none |
follow-redirect |
Defines if redirects are followed. Only the headers of the final response are returned. | true, false |
true |
cookies |
If enabled, the cookies of a response are stored and attached to subsequent requests of the same query, including redirected ones. | true, false |
false |
timeout |
Defines how many seconds to wait for the response. | positive integer | none |
username |
Defines the user name for authentication. | string | none |
password |
Defines the password for authentication. It is required if a user name is specified. | string | none |
auth-method |
Defines the authentication method. | basic, digest |
basic |
send-authorization |
If enabled, basic credentials are already sent with the first request. Otherwise, they are only supplied after the server has requested authentication. | true, false |
false |
csv, json, html |
Define how a CSV, JSON or HTML response body is converted (see Response Conversion). | options of the CSV, JSON and HTML parsers | none |
Examples
JSON API
A map is sent as JSON body, with credentials that are supplied before the server asks for them. The JSON response is parsed, and duplicate keys are rejected:
Querylet $response := http:post(
'https://example.com/api/items',
{ 'name': 'Anna', 'tags': [ 'red', 'blue' ] },
{
'auth': { 'username': 'john', 'password': '****', 'preemptive': true() },
'parse-options': { 'json': { 'duplicates': 'reject' } }
}
)
return if($response?status = 201) then $response?body?id else error(
xs:QName('local:api'), 'Item not created: ' || $response?status
)
Query Parameters and Headers
Parameters are appended to the URI, and the response body is returned as string instead of being parsed. An empty sequence suppresses a header field that would otherwise be added:
Queryhttp:get('https://example.com/search', {
'query': { 'q': 'xml database', 'limit': 10 },
'headers': { 'Accept': 'text/csv', 'User-Agent': () },
'response-body': 'text',
'timeout': 2.5
})?body
Streaming
As the ZIP archive has a binary media type, the response body is returned as lazy item, and its contents are streamed to a file with constant memory consumption:
Queryfile:write-binary(
'output.zip',
http:get('https://files.basex.org/xml/xmark/111mb.zip')?body
)
With response-body set to binary, this behavior can be enforced for arbitrary requests.
Uploads work equally well with constant memory: The contents of the addressed file will be streamed to the target server:
Queryhttp:put('http://localhost:8080/rest/archive/huge.zip', file:read-binary('huge.zip'))
Cookies
With the cookies option, the cookies that a server assigns are attached to the subsequent requests of a query. As the cookies are also sent to redirected addresses, a login that ends with a redirect can be followed by requests to protected resources:
void(
http:post('https://example.com/login', { 'user': 'jack', 'password': '...' }, {
'cookies': true(),
'headers': { 'Content-Type': 'application/x-www-form-urlencoded' }
})
),
http:get('https://example.com/download', { 'cookies': true() })
Digest Authentication
If the server requests digest authentication, the credentials are supplied with the second request:
Queryhttp:get('https://example.com/protected', {
'auth': { 'username': 'jack', 'password': '...', 'method': 'digest' }
})
POST Request
POST request to the BaseX REST Service, specifying a username and password. The element is serialized as XML, and the query string is wrapped in a CDATA section, so that it is sent as text instead of being evaluated by the client:
Queryhttp:post(
'http://localhost:8080/rest',
<query xmlns='http://basex.org/rest'>
<text><![CDATA[
<html>{
for $i in 1 to 3
return <div>Section { $i }</div>
}</html>
]]></text>
</query>,
{ 'auth': { 'username': 'admin', 'password': '...' } }
)?body
Result
<html>
<div>Section 1</div>
<div>Section 2</div>
<div>Section 3</div>
</html>
File Upload
Performs an HTML file upload. In the RESTXQ code, the uploaded file is written to the temporary directory:
Querylet $path := 'file-to-be.uploaded'
return http:post('http://localhost:8080/write-to-temp',
{
'headers': {
'Content-Disposition': 'form-data; name="files"; filename="' || file:name($path) || '"'
},
'body': file:read-binary($path)
},
{ 'multipart': true() }
)
RESTXQ service
declare
%rest:POST
%rest:path('/write-to-temp')
%rest:form-param('files', '{ $files }')
function local:file-upload(
$files as map(xs:string, xs:base64Binary)
) as empty-sequence() {
for key $file value $content in $files
return file:write-binary(file:temp-dir() || $file, $content)
};
Response Conversion
CSV, JSON and HTML responses are automatically converted to an XML representation. The target format can be influenced with the parse-options option. With the format w3, the JSON response body is returned as map:
http:get('http://localhost:8080/json', {
'parse-options': { 'json': { 'format': 'w3' } }
})?body
Result
{ "abcde": 12345 }
Without the option, the response body is converted to the default XML representation:
<json type="object">
<abcde type="number">12345</abcde>
</json>
RESTXQ service
declare
%rest:path('/json')
%output:method('json')
function local:json() {
{ 'abcde': 12345 }
};
See the CSV Functions, JSON Functions and HTML Functions for a list of the available options.
Status Only
Simple GET request. As the attribute status-only is set to true, only the response element is returned.
http:send-request(<http:request method='get' status-only='true'/>, 'https://basex.org')
Result
<http:response status="200" message="OK" href="https://basex.org" version="HTTP/2">
...
<http:header name="content-type" value="text/html"/>
...
<http:header name="server" value="Apache"/>
...
<http:body media-type="text/html"/>
</http:response>
Extensions
BaseX provides the following extensions to the EXPath specification:
- The functions
http:get,http:post,http:put,http:patch,http:delete,http:head,http:options,http:queryandhttp:sendprovide a map-based interface (see Request Options and Response Record). - The
cookiesattribute of thehttp:requestelement enables cookie handling for the requests of a query. - The
xml,csv,jsonandhtmlattributes of thehttp:requestelement control how response bodies are converted (see Request 1.0 Attributes). - The
proxyandverifyattributes of thehttp:requestelement configure the connection of a single request. - Binary response bodies are returned as lazy items, and file-based request payloads are streamed.
- The
hrefandversionattributes of thehttp:responseelement contain the final URI and the protocol version of the response. - Compressed responses are requested by default: an
Accept-Encodingheader is added unless one is supplied, and if the addressed web server provides support for thegzipcompression algorithm, the response will automatically be decompressed. - Unless they are supplied with the request, an
Accept: */*header and aUser-Agentstring with product name, version, Java version and operating system (e.g.BaseX/13.0 (Java 25; Windows 11 amd64)) are added. The same user agent is used by all other functions that retrieve remote resources, such asfetch:binaryorfn:doc. - Response header names are returned in lower case: field names are case-insensitive, and HTTP/2 servers transmit them in lower case.
- Basic and digest authentication are supported. Digest challenges with the
MD5,SHA-256andSHA-512-256algorithms (including their-sessvariants) are answered. Credentials can also be supplied via the URI (http://user:password@host/). - Redirects are followed by the module itself:
AuthorizationandCookieheaders are not sent to a target with a different origin, and downgrades fromhttpstohttpare not followed.
Errors
| Code | Description |
|---|---|
HC0001 | An HTTP error occurred, or the target URI is invalid. |
HC0002 | The response body could not be converted to the resulting data type. |
HC0004 | No attribute is allowed besides src and media-type. |
HC0005 | The request element is not valid, or no URL was supplied. |
HC0006 | A timeout occurred waiting for the response. |
invalid-body | The request body has an invalid type. |
invalid-option | The value of an option or the method is not permitted or not supported. |
invalid-uri | The target URI is invalid, or its scheme is not supported. |
network | A network error occurred, including a failed TLS handshake. |
parse | A response body could not be parsed. |
redirect | More redirects were received than the redirects option permits. |
serialize | A request body could not be serialized. |
timeout | The server did not respond within the timeout period. |
Changelog
Version 13.0- Added:
http:get,http:head,http:delete,http:options,http:post,http:put,http:patch,http:query,http:send: map-based interface with typed options and record results. - Added:
http:send-request:proxy,verifyandxmlattributes. - Added:
http:send-request:cookiesattribute for collecting and resending cookies. - Added:
http:send-request:hrefandversionattributes in thehttp:responseelement; SHA-256 and SHA-512-256 digest authentication. - Updated:
http:send-request:follow-redirectaccepts a maximum number of redirects;auth-methodis case-insensitive;timeoutaccepts fractions of a second. - Updated: Compressed responses are requested by default; redirects are no longer forwarded to another origin with credentials, and downgrades from
httpstohttpare not followed. - Updated:
http:send-request: response header names are returned in lower case. - Updated:
http:send-request: binary response bodies are returned as lazy items; file-based request payloads are streamed.
- Updated:
http:send-request:csv,jsonandhtmlattributes added.
- Updated: Implementation based on the new Java HTTP Client.
- Updated: support for gzipped content encoding
- Added: digest authentication
- Updated:
http:send-request:HC0002is raised if the input cannot be parsed or converted to the final data type. - Updated: errors are using
text/plainas media-type.