Difference between revisions of "RESTXQ"

From BaseX Documentation
Jump to navigation Jump to search
Line 226: Line 226:
 
==Error Handling==
 
==Error Handling==
  
Since {{Version|7.7}}, errors outside RESTXQ can be handled by adding {{Code|error-page}} elements to the {{Code|web.xml}} configuration file. An example:
+
{{Mark|Introduced with Version 7.7:}}
 +
 
 +
Errors outside RESTXQ can be handled by adding {{Code|error-page}} elements to the {{Code|web.xml}} configuration file. An example:
  
 
<pre class="brush:xml">
 
<pre class="brush:xml">

Revision as of 18:57, 21 June 2013

This page presents one of the Web Application services. 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. Next, with Version 7.7, the RESTXQ prefix has been changed from restxq to rest.

Usage

By default, the RESTXQ service is available at http://localhost:8984/restxq/.

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.

All 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 Web Application: Configuration for more details).

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 %rest:path("hello/{$world}")
        %rest:GET
        %rest: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 %rest:path("form/")
        %rest:POST
        %rest: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 with a single string as argument. The function will be called if a URL matches the path segments and templates of the argument. Path templates contain variables in curly brackets, and map the corresponding segments of the request path to the arguments of the resource function.

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 %rest: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 %rest:GET %rest:POST %rest: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 %rest:PUT("{$data}") %rest:path("")
  function page:put($data) { "Data: " || $data };

Content Negotiation

Two following 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:
%rest: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:
%rest: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. If no value is specified in the HTTP request, all additional parameters, if available, will be bound to the variable:

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

HTML Form Fields

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

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

HTTP Headers

Header parameters are specified the same way as query parameters:

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

Cookies

Cookie parameters are specified the same way as query parameters:

%rest:cookie-param("username","{$user}")
%rest: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") %rest: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
  %rest: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 Request Module contains functions for accessing data related to the current HTTP request. Two additional modules exist for setting and retrieving server-side session data of the current user (Session Module) and all users known to the HTTP server (Sessions Module). With Version 7.7, a RESTXQ Module was added that provides functions for requesting RESTXQ base URIs and generating a WADL description of all services. Please note that the namespaces of all of these modules must be explicitly specified via module imports in the query prolog.

The following example returns the current host name:

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

declare %rest:path("/host-name") function test:host() {
  'Remote host name: ' || request:remote-hostname()
};

Response

By default, a successful request is answered with the HTTP status 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. 404 for “resource not found”).

Custom responses can be built from within XQuery by returning an rest:response, an http:response child node that matches the syntax of the EXPath HTTP Client Module specification, and more optional child nodes that will be serialized as usual. E.g. one may return to the client

<rest:response>
  <http:response status="404" message="I was not found.">
    <http:header name="Content-Language" value="en"/>
    <http:header name="Content-Type" value="text/html; charset=utf-8"/>
  </http:response>
</rest:response>

Error Handling

Template:Mark

Errors outside RESTXQ can be handled by adding error-page elements to the web.xml configuration file. An example:

<!-- Error handling -->
<error-page>
  <error-code>404</error-code>
  <location>/error404</location>
</error-page>

An additional RESTXQ can then be defined to handle the caught error:

module namespace test = 'http://basex.org/examples/test';

declare %output:method("html") %rest:path("/error404")
  function test:error404()
{
  <html>
    <body>
      The URL <code>{ request:attribute("javax.servlet.error.request_uri") }</code> was not found.<br/>
      The error message was: { request:attribute("javax.servlet.error.message") }.
    </body>
  </html>
};

Forward and Redirect

The two XML elements rest:forward and rest:redirect can be used 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 a URL to a RESTXQ path. The wrapped URL should be properly encoded via fn:encode-for-uri().

Note that, currently, these elements are not part of RESTXQ specification.

rest:forward

Usage: wrap the location as follows

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

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

As an example, returning

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

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

rest:redirect

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

…is basically an abbreviation for…

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

The client decides whether to follow this redirection. Browsers usually will, tools like curl won’t unless -L is specified.

References

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

Changelog

Version 7.7
  • Updated: the RESTXQ prefix has been changed from restxq to rest.
  • Added: handle errors in web.xml.
Version 7.5
  • Added: new XML elements <rest:redirect/> and <rest:forward/>