RESTXQ

From BaseX Documentation
Revision as of 15:11, 10 November 2012 by Arve (talk | contribs) (added restxq:forward and restxq:redirect)
Jump to navigation Jump to search

This page is part of the Developer Section. It describes how to use the RESTXQ API of BaseX.

RESTXQ, introduced by Adam Retter, is a new API that facilitates the use of XQuery as a Server Side processing language for the Web. RESTXQ has been inspired by Java’s JAX-RS API: it defines a pre-defined set of XQuery 3.0 annotations for mapping HTTP requests to XQuery functions, which in turn generate and return HTTP responses.

Note that various details of the specification may be subject to change due to the early state of the API.

Getting started

First of all, launch the BaseX as Web Application. By default, Jetty is used as web server. All HTTP services will be available on port 8984, and the RESTXQ service is accessible at http://localhost:8984/restxq/. If the server is started as servlet, all Main Options (such as the path to the database) can be configured in the web.xml file. If run as a standalone application, the settings are stored in the .basex configuration file.

Module Declarations

All RESTXQ Annotations are assigned to the http://exquery.org/ns/restxq namespace, which is statically bound to the restxq 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.

By default, all files files in the webapp directory with the extension *.xqm will be parsed for RESTXQ annotations and cached. If the timestamp of a module changes, it will be parsed again. The RESTXQ module directory can be changed via the RESTXQPATH option (see HTTP Server Configuration for more)

A simple RESTXQ module is shown below, it is part of a clean installation and available at http://localhost:8984/restxq/ .

(:~ derived version of the function found in http/restxq.xqm :)
module namespace page = 'http://basex.org/examples/web-page';

declare %restxq:path("hello/{$world}")
        %restxq:GET
        %restxq:header-param("User-Agent", "{$agent}")
        function page:hello($world as xs:string, $agent as xs:string*) {
  <response>
    <title>Hello { $world }!</title>
    <info>You requested this page with { $agent }.</info>
  </response>
};

If the URI http://localhost:8984/restxq/hello/world is accessed, the result will be kind of

<response>
	<title>Hello world!</title>
	<info>You requested this page with Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13.</info>
</response>

We added another method within that module:

declare %restxq:path("form/")
        %restxq:POST
        %restxq:form-param("content","{$message}", "'no message delivered'")
        function page:hello-postman($message as xs:string) {
  <response>
    <title>Hello!</title>
    <info>It seems you posted a message: { $message }</info>
  </response>
};

If you posted something (e.g. using curl or the embedded form at http://localhost:8984/restxq/ )

curl -i -X POST --data "content='Here comes the post'" http://admin:admin@localhost:8984/restxq/form

You would recieve

<response>
  <title>Hello!</title>
  <info>It seems you posted a message: 'Here comes the post'</info>
</response>

Annotations

This section lists all annotations provided by RESTXQ.

Constraints

Constraints restrict the HTTP requests that a resource function may process.

Paths

A resource function must have a single Path Annotation. It will be called if a URL matches the path segments and templates specified as argument. Path templates contain variables in curly brackets, and map the values of the actual request path to the function arguments.

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 $variable will be cast to an xs:integer before being bound:

declare %restxq:path("/a/path/{$with}/some/{$variable}")
  function page:test($with, $variable as xs:integer) { ... };

HTTP Methods

The HTTP method annotations are equivalent to all HTTP request methods except for 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:

declare %restxq:GET %restxq:POST %restxq:path("")
  function page:root() { <html/> };

The POST and PUT annotations may optionally take a string literal, which will be mapped to a named function parameter. Once again, the target variable must be embraced by curly brackets:

declare %restxq:PUT("{$data}") %restxq:path("")
  function page:put($data) { "Data: " || $data };

Content Negotiation

Two additional annotations can be used to restrict functions to specific content types:

  • HTTP Content Types: a function will only be invoked if the HTTP Content-Type header of the request matches one of the given mime types. Example:
%restxq:consumes("application/xml", "text/xml")
  • HTTP Accept: a function will only be invoked if the HTTP Accept header of the request matches one of the defined mime types. Example:
%restxq:produces("application/atom+xml")

By default, both mime types are */*. Note that this annotation will not affect the content-type of the HTTP response. Instead, you will need to add a %output:media-type annotation.

Parameters

Parameters are optional annotations that can be used to bind additional values to function arguments:

Query Parameters

The value of the first parameter, if found in the Query String, will be assigned to the variable specified as second parameter. Optionally, a third parameter may be specified as default:

%restxq:query-param("parameter", "{$value}", "default")
%restxq:query-param("answer", "{$answer}", 42, 43, 44)
%restxq:query-param("search", "{$search-param}")

HTML Form Fields

Form parameters are specified the same way as query strings. Their values are extracted from GET or POST requests.

%restxq:form-param("parameter", "{$value}", "default")

HTTP Headers

Header parameters are specified the same way as query strings:

%restxq:header-param("User-Agent","{$user-agent}")
%restxq:header-param("Referer","{$referer}", "none")

Cookies

Cookie parameters are specified the same way as query strings:

%restxq:cookie-param("username","{$user}")
%restxq:cookie-param("authentication","{$auth}", "no_auth")

Output

By default, all results will be returned with content type application/xml. Similar to our REST interface, result serialization can be modified via XQuery 3.0 serialization parameters. In RESTXQ, all parameters are specified within annotations.

The content type can be overwritten with the media-type annotation:

declare %output:media-type("text/plain") %restxq:path("")
  function page:kiss() { 'keep it simple, stupid' };

Next, the content type can also be overwritten by specifying an output method. The following method mappings are available:

  • xmlapplication/xml
  • xhtmltext/html
  • htmltext/html
  • texttext/plain
  • rawapplication/octet-stream
  • json or jsonmlapplication/json

The following example will use text/html as content type:

declare
  %restxq:path("")
  %output:method("xhtml")
  %output:omit-xml-declaration("no")
  %output:doctype-public("-//W3C//DTD XHTML 1.0 Transitional//EN")  
  %output:doctype-system("http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd")
  function page:start()
{
  <html xmlns="http://www.w3.org/1999/xhtml">
    <body>done</body>
  </html>
};

Functions

The BaseX-specific Request Module provides additional functions to retrieve session data, query parameters and other request-related data. The following example returns the current session id:

module namespace test = 'http://basex.org/examples/test';
import module namespace request = "http://exquery.org/ns/restxq/request";

declare %restxq:path("/id") function test:id() {
  'ID: ' || request:session-id()
};


Forward and Redirect

With Version 7.5 we introduce two XML elements: restxq:forward and restxq:response. They are not part of RESTXQ-spec and can be returned in the context of Web Applications, precisely in the context of RESTXQ. These nodes allow e.g. multiple XQuery Updates in a row by redirecting to the RESTXQ path of updating functions. Both wrap an URL to a RESTXQ path.

Remember to encode the wrapped URL, e.g. using fn:encode-for-uri().

restxq:forward

Usage: wrap the location as follows

<restxq:forward>{ $location }</restxq:forward>

This results in a serverside forwarding, which as well reduces traffic among client and server. A forward of this kind will not change the URL seen from the clients perspective.

As an example, returning

<restxq:forward>/restxq/hello/universe</restxq:forward>

would internally forward to http://localhost:8984/restxq/hello/universe

restxq:redirect

<restxq:redirect>{ $location }</restxq:redirect>

which is an abbreviation for

<restxq:response>
  <http:response status="302" message="Temporary Redirect">
    <http:header name="location" value="{ $location }"/>
  </http:response>
</restxq:response>

The client decides wether to follow this redirect, Browsers usually will, curl will not.


References

RESTXQ has been proposed by Adam Retter. More information on all specifics can be found in the following two documents: