Difference between revisions of "RESTXQ"

From BaseX Documentation
Jump to navigation Jump to search
Line 264: Line 264:
 
</pre>
 
</pre>
  
The client decides whether to follow this redirect. Browsers usually will, tools like [http://curl.haxx.se/ curl] won’t unless {{Code|-L}} is specified.
+
The client decides whether to follow this redirection. Browsers usually will, tools like [http://curl.haxx.se/ curl] won’t unless {{Code|-L}} is specified.
  
 
=References=
 
=References=

Revision as of 18:31, 19 February 2013

This page is part of the Developer Section and belongs to the Web Application stack. 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.

Usage

By default, the RESTXQ service is activated and 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 %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 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 %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 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:
%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. If no value is specified in the HTTP request, all additional parameters, if available, will be bound to the variable:

%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 request additional data related to HTTP requests. The following example returns the current session id:

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

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

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).

Response

Since RESTXQ runs on a fully equipped Web-server, one can change all and specify more HTTP header informations that are returned to the client. By default, a successful request is answered with HTTP status code "200 OK" followed by the given content, an erroneous request (due to errors in a script) with "404 Not Found" followed by the error message.

The first behavior can be changed by returning an restxq:response element, following the EXPath HTTP Client Module specification. E.g. one may return to the client

    <restxq:response>
        <http:response status="418" message="I'm a teapot">
            <http:header name="Content-Language" value="en"/>
            <http:header name="Content-Type" value="text/html; charset=utf-8"/>
        </http:response>
    </restxq:response>
    <html>
        <body>My Message</body>
    </html>

Compare List of HTTP status codes to see what status code fits. It is mandatory to first place restxq:response followed by the content (of any kind) if any. In case of an updating function, use db:output() to return the element and the content.

Forward and Redirect

The two XML elements restxq:forward and restxq: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.

restxq:forward

Usage: wrap the location as follows

<restxq:forward>{ $location }</restxq: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

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

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

restxq:redirect

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

…is basically 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 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.5
  • Added: new XML elements <restxq:redirect/> and <restxq:forward/>