This page presents one of the [[Web Application]] services. It describes how to use the RESTXQ API of BaseX.
RESTXQ, introduced by [http://www.adamretter.org.uk/ Adam Retter], is an API that facilitates the use of XQueryas a server-side processing language for the Web. RESTXQ It has been inspired by Java’sthe Java [httphttps://en.wikipedia.org/wiki/Java_API_for_RESTful_Web_Services JAX-RS API]: it defines It provides a pre-defined set ofXQuery 3.0 annotations for mapping HTTP requests to XQuery functions, which in turn generate and returnHTTP responses.
Please note that BaseX provides various extensions to the original draft of the specification:
* Multipart types are supported, including {{Code|multipart/form-data}}
* Support for server-side quality factors in the [[#Content Negotiation|<code>%rest:produces</code>]] annotation
* Better support for the OPTIONS and HEAD methods
<br />
=Introduction=
==Preliminaries==
The RESTXQ service is accessible via {{Code|http://localhost:89848080/}}.
All RESTXQ [[XQuery 3.0#Annotations|annotations]] are assigned to the <code><nowiki>http://exquery.org/ns/restxq</nowiki></code> namespace, which is statically bound to the {{Code|rest}} prefix. A ''Resource Function'' is an XQuery function that has been marked up with RESTXQ annotations. When an HTTP request comes in, a resource function will be invoked that matches the constraints indicated by its annotations.
If a RESTXQ URL is requested, the {{Option|RESTXQPATH}} module directory and its sub-directories subdirectories will be traversed, and all [[XQuery Extensions#Suffixes|XQuery files]] will be parsed for functions with RESTXQ annotations. Sub-directories Subdirectories that include an {{Code|.ignore}} file will be skipped. In addition, XQuery modules that cannot be parsed will be ignored if {{Option|RESTXQERRORS}} is enabled.
To speed up processing, the functions of the existing XQuery modules are automatically cached in main memory:
* Functions will be invalidated and parsed again if the timestamp of their module changes.
* File monitoring can be adjusted via the {{Option|PARSERESTXQ}} option. In productive environments with a high load, it may be recommendable to change the timeout, or completely disable monitoring.
* If files are replaced while the web server is running, the RESTXQ module cache should be explicitly invalidated by calling the static root path {{Code|/.init}} or by calling the [[{{Function|RESTXQ Module#rest:init|rest:init]] }} function.
==Examples==
A first RESTXQ function is shown below:
<syntaxhighlight pre lang="'xquery"'>
module namespace page = 'http://basex.org/examples/web-page';
<title>Hello { $who }!</title>
</response>
};</syntaxhighlightpre>
If the URI http://localhost:89848080/hello/World is accessed, the result will be:
<syntaxhighlight pre lang="xml"><<response>> <<title>>Hello World!<</title>><</response>></syntaxhighlightpre>
The next function demonstrates a POST request:
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:path("/form")
%rest:header-param("User-Agent", "{$agent}")
function page:hello-postman(
$message as xs:string, $agent as xs:string*
) as element(response) {
<<response type='form'>> <<message>>{ $message }<</message>> <<user-agent>>{ $agent }<</user-agent>> <</response>>
};
</syntaxhighlightpre>
If you post something (e.g. using curl or the embedded form at http://localhost:89848080/)...
<syntaxhighlight pre lang="shell">curl -i -X POST --data "message='CONTENT'" http://localhost:89848080/form</syntaxhighlightpre>
...you will receive something similar to the following result:
<syntaxhighlight pre lang="shell">
HTTP/1.1 200 OK
Content-Type: application/xml; charset=UTF-8
Content-Length: 107
Server: Jetty(8.1.11.v20130520)
</syntaxhighlightpre>
<syntaxhighlight pre lang="xml">
<response type="form">
<message>'CONTENT'</message>
<user-agent>curl/7.31.0</user-agent>
</response>
</syntaxhighlightpre>
=Request=
The following example contains a path annotation with three segments and two templates. One of the function arguments is further specified with a data type, which means that the value for <code>$variable</code> will be cast to an <code>xs:integer</code> before being bound:
<syntaxhighlight pre lang="'xquery"'>
declare %rest:path("/a/path/{$with}/some/{$variable}")
function page:test($with, $variable as xs:integer) { ... };
</syntaxhighlightpre>
<!-- TODO how matching works -->
Variables can be enhanced by regular expressions:
<syntaxhighlight pre lang="'xquery"'>
(: Matches all paths with "app" as first, a number as second, and "order" as third segment :)
declare %rest:path("app/{$code=[0-9]+}/order")
declare %rest:path("app/{$path=.+}")
function page:others($path) { ... };
</syntaxhighlightpre>
<!-- TODO how matching works -->
A function will only be taken into consideration if the HTTP {{Code|Content-Type}} header of the request matches one of the given types:
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:POST("{$body}")
%rest:consumes("text/xml")
function page:xml($body) { $body };
</syntaxhighlightpre>
====Producing Data====
A function will only be chosen if the HTTP {{Code|Accept}} header of the request matches one of the given types:
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:path("/xml")
%rest:produces("application/xml", "text/xml")
function page:xml() { <xml/> };
</syntaxhighlightpre>
Note that the annotations will ''not'' affect the type of the actual response: You will need to supply an additional <code>[[#Output|%output:media-type]]</code> annotation or (if a single function may produce results of different types) generate an apt [[#Custom_Response|Custom Response]].
A client can supply quality factors to influence the server-side function selection process. If a client sends the following HTTP header with quality factors…
<syntaxhighlightpre>
Accept: */*;q=0.5,text/html;q=1.0
</syntaxhighlightpre>
…and if two RESTXQ functions exist for the addressed path with two different annotations for producing data…
<syntaxhighlight pre lang="'xquery"'>
declare function %rest:produces("text/html") ...
...
declare function %rest:produces("*/*") ...
</syntaxhighlightpre>
…the first of these function will be chosen, as the quality factor for <code>text/html</code> documents is highest.
As we cannot ensure that the client may supply quality factors, the selection process can also be controlled server-side. The <code>qs</code> parameter can be attached server-side to the Media Type. If multiple functions are left in the selection process, the one with the highest quality factor will be favored:
<syntaxhighlight pre lang="'xquery"'>
declare function %rest:produces("application/json;qs=1") ...
...
declare function %rest:produces("*/*;qs=0.5") ...
</syntaxhighlightpre>
===HTTP Methods===
====Default Methods====
The HTTP method annotations are equivalent to all [httphttps://en.wikipedia.org/wiki/HTTP#Request_methods HTTP request methods] except TRACE and CONNECT. Zero or more methods may be used on a function; if none is specified, the function will be invoked for each method.
The following function will be called if GET or POST is used as request method:
<syntaxhighlight pre lang="'xquery"'>
declare %rest:GET %rest:POST %rest:path("/post")
function page:post() { "This was a GET or POST request" };
</syntaxhighlightpre>
The POST and PUT annotations may optionally take a string literal in order to map the HTTP request body to a [[#Parameters|function argument]]. Once again, the target variable must be embraced by curly brackets:
<syntaxhighlight pre lang="'xquery"'>
declare %rest:PUT("{$body}") %rest:path("/put")
function page:put($body) { "Request body: " || $body };
</syntaxhighlightpre>
====Custom Methods====
Custom HTTP methods can be specified with the {{Code|%rest:method}} annotation. An optional body variable can be supplied as second argument:
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:path("binary-size")
"Size of body: " || bin:length($body)
};
</syntaxhighlightpre> {{Mark|Updated with Version 9.3:}}
If an OPTIONS request is received, and if no function is defined, an automatic response will be generated, which includes an <code>Allow</code> header with all supported methods.
by specifying additional content-type parameters:
{| class="wikitable" width="100%"
|- valign="top"
! Content-Type
! Parameters (<code>;name=value</code>)
! Type of resulting XQuery item
|-valign="top"
| {{Code|text/xml}}, {{Code|application/xml}}
|
| {{Code|document-node()}}
|-valign="top"
| {{Code|text/*}}
|
| {{Code|xs:string}}
|-valign="top"
| {{Code|application/json}}
| [[JSON Module#Options|JSON Options]]
| {{Code|document-node()}} or {{Code|map(*)}}
|-valign="top"
| {{Code|text/html}}
| [[HTML Module#Options|HTML Options]]
| {{Code|document-node()}}
|-valign="top"
| {{Code|text/comma-separated-values}}
| [[CSV Module#Options|CSV Options]]
| {{Code|document-node()}} or {{Code|map(*)}}
|-valign="top"
| ''others''
|
| {{Code|xs:base64Binary}}
|-valign="top"
| {{Code|multipart/*}}
|
Conversion options for {{Option|JSON}}, {{Option|CSV}} and {{Option|HTML}} can also be specified via annotations with the <code>input</code> prefix. The following function interprets the input as text with the CP1252 encoding and treats the first line as header:
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:path("/store.csv")
"Number of rows: " || count($csv/csv/record)
};
</syntaxhighlightpre>
===Multipart Types===
A function that is capable of handling multipart types is identical to other RESTXQ functions:
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:path("/multipart")
"Number of items: " || count($data)
};
</syntaxhighlightpre>
==Parameters==
The value of the ''first parameter'', if found in the [[Request_Module#Conventions|query component]], will be assigned to the variable specified as ''second parameter''. If no value is specified in the HTTP request, all additional parameters will be bound to the variable (if no additional parameter is given, an empty sequence will be bound):
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:path("/params")
<result id="{ $id }" sum="{ sum($add) }"/>
};
</syntaxhighlightpre>
===HTML Form Fields===
Form parameters are specified the same way as [[#Query Parameters|query parameters]]. Their values are the result of HTML forms submitted with the content type <code>application/x-www-form-urlencoded</code>.:
<syntaxhighlight pre lang="'xquery"'>%rest:form-param("parametercity", "{$valuecity}", "no-city-specified")</pre> The values are the result of HTML forms submitted with the (default) content type <code>application/x-www-form-urlencoded</code>: <pre lang="xml"><form action="/process" method="POST" enctype=")application/x-www-form-urlencoded"> <input type="text" name="city"/> <input type="submit"/></form></syntaxhighlightpre>
====File Uploads====
Files can be uploaded to the server by using the content type {{Code|multipart/form-data}} (the HTML5 {{Code|multiple}} attribute enables the upload of multiple files):
<syntaxhighlight pre lang="xml">
<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="files" multiple="multiple"/>
<input type="submit"/>
</form>
</syntaxhighlightpre>
The file contents are placed in a [[Map Module|map]], with the filename serving as key. The following example shows how uploaded files can be stored in a temporary directory:
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:POST
)
};
</syntaxhighlightpre>
===HTTP Headers===
Header parameters are specified the same way as [[#Query Parameters|query parameters]]:
<syntaxhighlight pre lang="'xquery"'>
%rest:header-param("User-Agent", "{$user-agent}")
%rest:header-param("Referer", "{$referer}", "none")
</syntaxhighlightpre>
===Cookies===
Cookie parameters are specified the same way as [[#Query Parameters|query parameters]]:
<syntaxhighlight pre lang="'xquery"'>
%rest:cookie-param("username", "{$user}")
%rest:cookie-param("authentication", "{$auth}", "no_auth")
</syntaxhighlightpre>
==Query Execution==
In many RESTXQ web search scenarios, user input from browser forms is processed and search results are returned. User experience Such operations can generally be made more interactive if an updated by sending a new search request is triggered to the server with each key click. However, this may lead to many expensive parallel server-side requests, from which only the result of the last request will be relevant for the client.
With the <code>%rest:single</code> annotation, it can be enforced that only one instance of a function will be executed run at the same time and for the same client. If the same function will be called for the second time, the already running a currently executed query will be stopped, and the HTTP error code {{Code|460}} will be returned instead:
<syntaxhighlight pre lang="'xquery"'>
(: If fast enough, returns the result. Otherwise, if called again, raises 460 :)
declare
function page:search($term as xs:string) {
<ul>{
for $result in db:openget('large-db')//*[text() = $term]
return <li>{ $result }</li>
}</ul>
};
</syntaxhighlightpre> By specifying a string along with the annotation, functions can be bundled together, and one request can be canceled by calling another one.
By adding a string value to with the annotation, functions can be bundled together, and a running query can be canceled by calling another one that has the same annotation value. This is shown by another example, in which the first function can be interrupted by the second one. If you call both functions in separate browser tabs, you will note that the first tab will return <code>460</code>, and the second one will return <xml>stopped</xml>.
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:path("/compute")
<xml>stopped</xml>
};
</syntaxhighlightpre>
The following things should be noted:
* If a query will be canceled, there will be no undesirable side-effects. For example, it won’t be possible to kill abort a query if it is currenly currently updating the database or perfoming performing any other I/O operations. As a result, the termination of a running query can take some more time as expected.
* The currently executed function is bound to the current session. This way, a client will not be able to cancel requests from other clients. As a result, functions can only be stopped if there was at least one previous successful response, in which initial session data was returned to the client.
By default, a successful request is answered with the HTTP status code {{Code|200}} (OK) and is followed by the given content. An erroneous request leads to an error code and an optional error message (e.g. {{Code|404}} for “resource not found”).
A {{Code|Server-Timing}} HTTP header is attached to each response. It indicates how much time was spent for parsing, compiling, evaluating and serializing the query. The last value will not necessarily reflect the full time for serializing the result, as the header is generated before the result is sent to the client. Server-side serialization can be enforced by annotating a function with the <code>[[#Query Execution|%rest:single]]</code> annotation.
==Custom Response==
Custom responses can be generated in XQuery by returning an <code>rest:response</code> element, an <code>http:response</code> child node that matches the syntax of the [http://expath.org/spec/http-client EXPath HTTP Client Module] specification, and optional child nodes that will be serialized as usual. A function that yields a response on an unknown resource may look as follows:
<syntaxhighlight pre lang="'xquery"'>
declare %output:method("text") %rest:path("") function page:error404() {
<rest:response>
"The requested resource is not available."
};
</syntaxhighlightpre> For the time being, it is not possible to create multipart responses.
==Forwards and Redirects==
===Redirects===
{{Mark|Removed with Version 9.3:}} {{Code|rest:redirect}} element.
The server can invite the client (e.g., the web browser) to make a second request to another URL by sending a 302 response:
<syntaxhighlight pre lang="xml">
<rest:response>
<http:response status="302">
</http:response>
</rest:response>
</syntaxhighlightpre>
The convenience function {{Function|Web|web:redirect}} can be called to create such a response.
In the XQuery context, redirects are particularly helpful if [[XQuery Update|Updates]] are performed. An updating request may send a redirect to a second function that generates a success message, or evaluates an updated database:
<syntaxhighlight pre lang="'xquery"'>
declare %updating %rest:path('/app/init') function local:create() {
db:create('app', <root/>, 'root.xml'),
declare %rest:path('/app/ok') function local:ok() {
'Stored documents: ' || count(db:openget('app'))
};
</syntaxhighlightpre>
===Forwards===
A server-side redirect is called forwarding. It reduces traffic among client and server, and the forwarding will not change the URL seen from the client’s perspective:
<syntaxhighlight pre lang="xml">
<rest:forward>new-location</rest:forward>
</syntaxhighlightpre>
The fragment response can also be created with the convenience function {{Function|Web|web:forward}}. With {{Announce|Version 11}}, a log entry with the status code {{Code|204}} will be output before the forwarding takes place.
==Output==
In main modules, serialization parameters may be specified in the query prolog. These parameters will then apply to all functions in a module. In the following example, the content type of the response is overwritten with the {{Code|media-type}} parameter:
<syntaxhighlight pre lang="'xquery"'>
declare option output:media-type 'text/plain';
'Keep it simple, stupid'
};
</syntaxhighlightpre>
===Annotations===
Global serialization parameters can be overwritten via <code>%output</code> annotations. The following example serializes XML nodes as JSON, using the [[JSON Module|JsonML]] format:
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:path("cities")
function page:cities() {
element cities {
db:openget('factbook')//city/name
}
};
</syntaxhighlightpre>
The next function, when called, generates XHTML headers, and {{Code|text/html}} will be set as content type:
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:path("done")
</html>
};
</syntaxhighlightpre>
===Response Element===
Serialization parameters can also be specified in a REST reponse element in a query. Serialization parameters will be overwritten:
<syntaxhighlight pre lang="'xquery"'>
declare %rest:path("version3") function page:version3() {
<rest:response>
'Not that simple anymore'
};
</syntaxhighlightpre>
=Error Handling=
==Raise Errors==If an error is raised when RESTXQ code is parsed, compiled or evaluated, an HTTP response with the status code 500 is generated.
By default, all server-side errors will be passed on to the client. This is particularly helpful during the development process. In a productive environment, however, it is advisable not to expose errors to the client. This can be realized via the {{MarkOption|Updated with Version 9.3RESTXQERRORS}}:option. If disabled,
If an * XQuery modules that cannot be parsed will be ignored and* full error is raised during messages and stack traces will be suppressed and not included in the evaluation of a RESTXQ function, an HTTP response with the status code 400 is generated. The response body contains the full error message and stack trace.
With the {{Function|Web|web:The full error}} function, you information can abort query evaluation and enforce a premature HTTP response with still be looked up in the supplied status code and response body text:database logs.
==Raise Errors== With {{Function|Web|web:error}}, you can abort query evaluation, enforce a premature HTTP response and report errors back to the client: <syntaxhighlight pre lang="'xquery"'>
declare
%rest:path("/teapot")
web:error(418, "I'm a pretty teapot")
};
</syntaxhighlightpre>
The XQuery In contrast to the standard <code>fn:error </code> function, a status code can be supplied, and the response body will only contain the specified error message and no stack trace will be suppressed in the body of the HTTP response.
==Catch XQuery Errors==
XQuery runtime errors can be processed via ''error annotations''.Error annotations have one or more arguments, which represent the error codes to be caught.The codes equal the names of the XQuery 3.0 [[XQuery 3.0#Try.2FCatch|try/catch]] construct:
{| class="wikitable"
! Syntax
! Example
|-valign="top"
| 1
| <code>prefix:name</code><br/><code>Q{uri}name</code>
| <code>err:FORG0001</code><br/><code><nowiki>Q{http://www.w3.org/2005/xqt-errors}FORG0001</nowiki></code>
|-valign="top"
| 2
| <code>prefix:*</code><br/><code>Q{uri}*</code>
| <code>err:*</code><br/><code><nowiki>Q{http://www.w3.org/2005/xqt-errors}*</nowiki></code>
|-valign="top"
| 3
| <code>*:name</code>
| <code>*:FORG0001</code>
|-valign="top"
| 4
| <code>*</code>
Errors may occur unexpectedly. However, they can also be triggered by a query, as demonstrated by the following example:
<syntaxhighlight pre lang="'xquery"'>
declare
%rest:path("/check/{$user}")
'User "' || $user || '" is unknown'
};
</syntaxhighlightpre>
==Catch HTTP Errors==
Errors that occur outside RESTXQ can be caught by adding {{Code|error-page}} elements with an error code and a target location to the {{Code|web.xml}} configuration file (find more details in the [http://www.eclipse.org/jetty/documentation/current/custom-error-pages.html Jetty Documentation]):
<syntaxhighlight pre lang="xml">
<error-page>
<error-code>404</error-code>
<location>/error404</location>
</error-page>
</syntaxhighlightpre>
The target location may be another RESTXQ function. The [[{{Function|Request Module#request:attribute|request:attribute]] }} function can be used to request details on the caught error:
<syntaxhighlight pre lang="'xquery"'>
declare %rest:path("/error404") function page:error404() {
"URL: " || request:attribute("javax.servlet.error.request_uri") || ", " ||
"Error message: " || request:attribute("javax.servlet.error.message")
};
</syntaxhighlightpre>
=User Authentication=
The following example returns the current host name:
<syntaxhighlight pre lang="'xquery"'>
import module namespace request = "http://exquery.org/ns/request";
'Remote host name: ' || request:remote-hostname()
};
</syntaxhighlightpre>
=References=
* [http://www.adamretter.org.uk/papers/restful-xquery_january-2012.pdf RESTful XQuery, Standardised XQuery 3.0 Annotations for REST]. Paper, XMLPrague, 2012
* [http://www.adamretter.org.uk/presentations/restxq_mugl_20120308.pdf RESTXQ]. Slides, MarkLogic User Group London, 2012
* [httphttps://files.basex.org/publications/xmlprague/2013/Develop-RESTXQ-WebApps-with-BaseX.pdf Web Application Development]. Slides from XMLPrague 2013
Examples:
* Sample code combining XQuery and JavaScript: [httphttps://www.balisage.net/Proceedings/vol17/author-pkg/Galtman01/BalisageVol17-Galtman01.html Materials] and [httphttps://www.balisage.net/Proceedings/vol17/html/Galtman01/BalisageVol17-Galtman01.html paper] from Amanda Galtman, Balisage 2016.
* [[DBA]]: The Database Administration interface, bundled with the full distributions of BaseX.
=Changelog=
;Version 11.0
* Updated: [[#Forwards|Forwards]]: A log entry with the status code {{Code|204}} will be output.
;Version 9.6
* Updated: [[#Response|Response]]: {{Code|Server-Timing}} HTTP header.
;Version 9.5
* Updated: [[#Raise Errors|Raise Errors]]: Status code {{Code|400}} changed to {{Code|500}}, omit stack trace.
;Version 9.3
* Updated: [[#Custom Methods|Custom Methods]]: Better support for the OPTIONS and HEAD methods.
* Updated: [[#Catch XQuery Errors|XQuery Errors]]: Suppress stack trace and error code in the HTTP response.
;Version 9.2
* Updated: Ignore XQuery modules that cannot be parsed
;Version 9.0
* Added: Support for server-side quality factors in the [[#Content Negotiation|<code>%rest:produces</code>]] annotation
* Updated: Status code {{Code|410}} was replaced with {{Code|460}}
;Version 8.4
* Added: <code>%rest:single</code> annotation
;Version 8.1
* Added: support for input-specific content-type parameters
* Added: <code>%input</code> annotations
;Version 8.0
* Added: Support for regular expresssions in the [[#Paths|Path Annotation]]
* Added: Evaluation of quality factors that are supplied in the [[#Content Negotiation|Accept header]]
;Version 7.9
* Updated: [[#Catch XQuery Errors|XQuery Errors]], extended error annotations
* Added: {{Code|%rest:method}}
;Version 7.7
* Added: [[#Error Handling|Error Handling]], [[#File Uploads|File Uploads]], [[#Multipart Types|Multipart Types]]
* Updated: RESTXQ function may now also be specified in main modules (suffix: {{Code|*.xq}}).
* Updated: the RESTXQ prefix has been changed from {{Code|restxq}} to {{Code|rest}}.
* Updated: parameters are implicitly cast to the type of the function argument
* Updated: the RESTXQ root url has been changed to {{Code|http://localhost:89848080/}}
;Version 7.5
* Added: new XML elements {{Code|<rest:redirect/>}} and {{Code|<rest:forward/>}}