Main Page » XQuery » Functions » HTTP Client Functions

HTTP Client Functions

This module contains a single function to send HTTP requests and handle HTTP responses. The function send-request is based on the EXPath HTTP Client Module. It gives full control over the available request and response parameters. 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.

Please note that BaseX provides extensions to the specification:

  • The cookies attribute of the http:request element enables cookie handling for the requests of a query.
  • The csv, json and html attributes of the http:request element control how response bodies are converted (see Request Attributes).
  • Binary response bodies of GET requests are returned as lazy items, and file-based request payloads are streamed.
  • If <http:header name="Accept-Encoding" value="gzip"/> is specified and if the addressed web server provides support for the gzip compression algorithm, the response will automatically be decompressed.

Since BaseX 10, the module is based on the Java HTTP Client, which provides a better overall performance, uses internal connection pools and follows redirects across different protocols (http, https).

Conventions

All functions are in the http://expath.org/ns/http-client namespace, to which the http prefix is statically bound.

All errors are in the http://expath.org/ns/error namespace, to which the experr prefix is statically bound.

Request Attributes

The following attributes can be attached to the http:request element. All of them are defined by the EXPath specification, except for cookies, 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
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

Functions

http:send-request

Updated: Binary response bodies of GET requests are returned as lazy items; file-based request payloads are streamed; new cookies attribute.

Signature
http:send-request(  $request  as element(http:request)?,  $href     as xs:string?  := (),  $bodies   as item()*  := ()) as item()+create
SummarySends an HTTP request and interprets the corresponding response:
  • $request contains an <http:request/> element with a method attribute, an href attribute with the target URI, and optional header and body elements.
  • The request is either sent to the URI of the $href argument or (if empty) to the URI supplied via the href attribute.
  • See Request Attributes for the attributes that can be attached to the http:request element.

Notes:

  • If the request method is GET and if the response body has a binary media type (i.e., one that is not converted to XML, JSON, CSV, HTML or plain text), the body will be returned as lazy item (see the Lazy Functions for more details): Its contents will only be retrieved when processed, and they can be streamed to a target without being cached. If the contents are requested repeatedly, the request will be sent again.
  • Request payloads that are backed by files – contents linked via the src attribute, or lazy items resulting from functions such as file:read-binary or db:get-binary – are streamed to the target server without being materialized in memory.
  • Both basic and digest authentication are supported.
  • While the contents of the request can be supplied as child of the http:body element, it is faster and safer to pass them on via the third argument.
  • Certificate verification can be globally disabled via the IGNORECERT option.
  • For further information, please check out the EXPath specification.
Errors
HC0001An HTTP error occurred, or the target URI is invalid.
HC0002The response body could not be converted to the resulting data type.
HC0004No attribute is allowed besides src and media-type.
HC0005The request element is not valid, or no URL was supplied.
HC0006A timeout occurred waiting for the response.

Examples

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:

Query
let $response := http:send-request(
  <http:request method='get'/>,
  'https://files.basex.org/xml/xmark111mb.zip'
)
return file:write-binary('output.zip', $response[2])

With the override-media-type attribute set to application/octet-stream, this behavior can be enforced for arbitrary GET requests.

Uploads work equally well with constant memory: The contents of the addressed file will be streamed to the target server:

Query
http:send-request(
  <http:request method='put'>
    <http:body media-type='application/octet-stream'/>
  </http:request>,
  'http://localhost:8080/rest/archive/huge.zip',
  file:read-binary('huge.zip')
)

Status Only

Simple GET request. As the attribute status-only is set to true, only the response element is returned.

Query
http:send-request(<http:request method='get' status-only='true'/>, 'http://basex.org')
Result
<http:response status="200" message="OK">
  <http:header name="Date" value="Mon, 14 Mar 2011 20:55:53 GMT"/>
  <http:header name="Content-Length" value="12671"/>
  <http:header name="Expires" value="Mon, 14 Mar 2011 20:57:23 GMT"/>
  <http:header name="Set-Cookie" value="fe_typo_user=d10c955; path=/"/>
  <http:header name="Connection" value="close"/>
  <http:header name="Content-Type" value="text/html; charset=utf-8"/>
  <http:header name="Server" value="Apache/2.2.16"/>
  <http:header name="X-Powered-By" value="PHP/5.3.5"/>
  <http:header name="Cache-Control" value="max-age=90"/>
  <http:body media-type="text/html; charset=utf-8"/>
</http:response>

Cookies

With the cookies attribute, 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:

Query
void(
  http:send-request(
    <http:request method='post' cookies='true' href='https://example.com/login'>
      <http:body media-type='application/x-www-form-urlencoded'/>
    </http:request>,
    (),
    'user=jack&password=...'
  )
),
http:send-request(
  <http:request method='get' cookies='true'/>,
  'https://example.com/download'
)

Google Homepage

Retrieve the Google search home page with a timeout of 10 seconds. In order to parse HTML, the HTML parser must be contained in the class path.

Query
http:send-request(<http:request method='get' href='http://www.google.com' timeout='10'/>)
Result
<http:response status="200" message="OK">
  <http:header name="Date" value="Mon, 14 Mar 2011 22:03:25 GMT"/>
  <http:header name="Transfer-Encoding" value="chunked"/>
  <http:header name="Expires" value="-1"/>
  <http:header name="X-XSS-Protection" value="1; mode=block"/>
  <http:header name="Set-Cookie" value="...; expires=Tue, 13-Sep-2011 22:03:25 GMT; ..."/>
  <http:header name="Content-Type" value="text/html; charset=ISO-8859-1"/>
  <http:header name="Server" value="gws"/>
  <http:header name="Cache-Control" value="private, max-age=0"/>
  <http:body media-type="text/html; charset=ISO-8859-1"/>
</http:response>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>Google</title>
    ...
  </head>
  <body>
    ...
  </body>
</html>

The response content type can also be overwritten in order to retrieve HTML pages and other textual data as plain string (using text/plain) or in its binary representation (using application/octet-stream). With the http:header element, a custom user agent can be set. See the following example:

Query
let $response := http:send-request(
  <http:request method='get'
     override-media-type='application/octet-stream'
     href='http://www.google.com'>
    <http:header name='User-Agent' value='Opera'/>
  </http:request>
)
let $body := tail($response)
return try {
  html:parse($body)
} catch * {
  'Conversion to XML failed: ' || $err:description
}

SVG Data

Content-type ending with +xml, e.g. image/svg+xml.

Query
http:send-request(
  <http:request method='get'/>,
  'http://upload.wikimedia.org/wikipedia/commons/6/6b/Bitmap_VS_SVG.svg'
)
Result
<http:response status="200" message="OK">
  <http:header name="ETag" value="W/&quot;11b6d-4ba15ed4&quot;"/>
  <http:header name="Age" value="9260"/>
  <http:header name="Date" value="Mon, 14 Mar 2011 19:17:10 GMT"/>
  <http:header name="Content-Length" value="72557"/>
  <http:header name="Last-Modified" value="Wed, 17 Mar 2010 22:59:32 GMT"/>
  <http:header name="Content-Type" value="image/svg+xml"/>
  <http:header name="X-Cache-Lookup" value="MISS from knsq22.knams.wikimedia.org:80"/>
  <http:header name="Connection" value="keep-alive"/>
  <http:header name="Server" value="Sun-Java-System-Web-Server/7.0"/>
  <http:header name="X-Cache" value="MISS from knsq22.knams.wikimedia.org"/>
  <http:body media-type="image/svg+xml"/>
</http:response>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
    version="1.1" height="638">
  <defs>
    <linearGradient id="lg0">
      <stop stop-color="#3333ff" offset="0"/>
      <stop stop-color="#3f3fff" stop-opacity="0" offset="1"/>
    </linearGradient>
    ...
</svg>

POST Request

POST request to the BaseX REST Service, specifying a username and password.

Query
http:send-request(
  <http:request method='post' username='admin' password='...'>
    <http:body media-type='application/xml'/>
  </http:request>,
  'http://localhost:8080/rest',
  <query>
    <text>
      <html>{
        for $i in 1 to 3
        return 'Section ' || $i
      }</html>
    </text>
  </query>
)
Result
<http:response xmlns:http="http://expath.org/ns/http-client" status="200" message="OK">
  <http:header name="Content-Length" value="135"/>
  <http:header name="Content-Type" value="application/xml"/>
  <http:header name="Server" value="Jetty(11.0.20)"/>
  <http:body media-type="application/xml"/>
</http:response>
<html>
  Section 1
  Section 2
  Section 3
</html>

File Upload

Performs an HTML file upload. In the RESTXQ code, the uploaded file is written to the temporary directory:

Query
let $path := 'file-to-be.uploaded'
return http:send-request(
  <http:request method='POST'>
    <http:multipart media-type='multipart/form-data'>
      <http:header name='content-disposition'
        value='form-data; name="files"; filename="{ file:name($path) }"'/>
      <http:body media-type='application/octet-stream'/>
    </http:multipart>
  </http:request>,
  'http://localhost:8080/write-to-temp',
  file:read-binary($path)
)
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() {
  map:for-each($files, fn($file, $content) {
    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 by supplying csv, json and html attributes:

Query
http:send-request(
  <http:request method='GET' json='format=w3,lax=true'/>,
  'http://localhost:8080/json'
)
Result
{ "abcde": 12345 }

Without the json attribute, the response body is converted to the default XML representation:

<json type="object">
  <abcde>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.

Errors

CodeDescription
HC0001An HTTP error occurred, or the target URI is invalid.
HC0002The response body could not be converted to the resulting data type.
HC0004No attribute is allowed besides src and media-type.
HC0005The request element is not valid, or no URL was supplied.
HC0006A timeout occurred waiting for the response.

Changelog

Version 13.0
  • Added: http:send-request: cookies attribute for collecting and resending cookies.
  • Updated: http:send-request: binary response bodies of GET requests are returned as lazy items; file-based request payloads are streamed.
Version 11.0Version 10.0Version 9.0
  • Updated: support for gzipped content encoding
Version 8.0
  • Added: digest authentication
Version 7.6
  • Updated: http:send-request: HC0002 is raised if the input cannot be parsed or converted to the final data type.
  • Updated: errors are using text/plain as media-type.

⚡Generated with XQuery