XQuery [[XQUERY]] processors are now frequently provided as part of complete data application processing platforms, which typically incorporate amongst others, XML Data storage and Web serving capabilities.
XQuery has long been recognised as a good language for producing XHTML and HTML from complex data queries, however XQuery is almost completely ignorant of the Web. XQuery provides no native capabilities for either making Web requests or operating as a server-side scripting language and processing Web requests.
As of XQuery 3.0 [[XQUERY-30]], there is still no standard way to create Web Applications in XQuery. Many vendors provide extensions to their XQuery implementations which allow users to serve web requests using XQuery processing. Whilst vendors have borrowed ideas from each other, there is no standard for Web capabilities in XQuery, as such developers have to use proprietary extensions, which limits the portability of their XQuery code, ultimately fragmenting the XQuery community, limiting re-use and reducing peer-learning.
RESTXQ attempts to resolve these problem of interoperablility. RESTXQ defines a standard set of vendor agnostic XQuery Annotations and functions for XQuery. When implemented by vendors, these annotations provide a standard W3C XQuery compliant approach to delivering RESTful Web Services from XQuery, whilst the functions provide user convenience for interacting with implementations of RESTXQ.
The guiding goals for the RESTXQ specification are:
This specification is intended for both vendors and developers looking to implement RESTXQ in their products, XQuery developers looking to use the RESTXQ features defined in this specification, and individuals wishing to establish the correctness of implementations with respect to the requirements of this specification.
This document assumes that readers already have at least a basic understanding of XQuery, and an understanding of Web technologies and server side scripting.
The annotations and functions discussed in this document are contained in namespaces (see [[XML-NAMES]]) and referenced using an xs:QName:
http://exquery.org/ns/restxq
, associated with rest
.http://www.w3.org/2010/xslt-xquery-serialization
, associated with output
.http://expath.org/ns/http-client
, associated with http
.http://exquery.org/ns/restxq/error
, associated with rerr
.The namespace prefix used for the functions, datatypes and errors can vary, as long as the prefix is bound to the correct URI.
rerr
prefix is not expected to change from one version of this document to another. The contents of this namespace may be extended to allow additional errors to be returned.
RESTXQ is heavily influenced by [[?JAX-RS]]. However, we simplify and deviate from JAX-RS predominantly due to the language structure differences between Java and XQuery. Where JAX-RS describes Resource Classes and Resources Methods for Java, in XQuery we simply use the term Resource Function; for mapping HTTP calls to XQuery invocation, our unit of granularity is the XQuery function.
Through the use of annotations on functions in XQuery, we declaratively mark-up the HTTP capabilities of a function. To minimise refactoring by developers when adding annotations to existing code, two measures must be respected by implementations:
A Resource Function is an XQuery function which has been marked up with RESTXQ annotations. These annotations indicate to a processor that when presented with a RESTful web service request, that matches the constraints indicated by the annotations, that the function SHOULD be invoked and the result SHOULD be returned as the result of the service request.
There are two types of Resource Function Annotations described in RESTXQ:
Some of the RESTXQ Annotations make use of Templates, which allow for the substitution of parameters from the request into the query. The syntax of these templates is very simple and is designed to be familiar to existing XQuery developers, it is expressed in .
The Template appears inside a string literal within the annotation, but the meaning is that the value of the templated substitution MUST be used as the parameter to the named argument of the annotated function.
{$number-of-cats}
In the example above, a parameter given from the template substitution MUST be set for the function argument called 'number-of-cats' on the annotated function.
Constraints restrict the service requests that a Resource Function MAY process.
A Path Annotation maps the URI of a RESTful web service to a Resource Function and provides for path templates.
A Resource Function MUST contain a single path annotation. Additional annotations MAY be used to constrain or parameterize the Resource Function.
The path annotation is named %rest:path
and takes a single
mandatory literal string, which describes the URI path for this service.
The URI path is considered relative to an implementation-defined base URI
().
The path string MAY contain zero or more URI templates which denote path segments that MUST map to named function parameters. Parameters addressed by templates in the URI path must meet the following constraints:
Conversion from the URI segment string to the required type is performed at run-time, and an error MUST be raised if conversion is impossible.
declare %rest:path("/stock/widget/{$id}") function local:widget($id as xs:int) { fn:collection("/db/widgets")//widget[@id eq $id] };
In the above example, an HTTP GET on the following URI would cause the widget with the id
of '1981' to be retrieved: http://www.widget-factory.com/stock/widget/1981
.
Resource Functions MAY be constrained to zero or more HTTP methods by means of a method annotation. Unless otherwise constrained by a method annotation, the path annotation of a Resource Function applies to all HTTP methods.
Annotations are defined for all HTTP 1.1 methods except TRACE and CONNECT.
All methods MAY return resources except for HEAD, which must only return a
rest:response
element.
declare %rest:DELETE %rest:path("/widget/{$id}") function local:widget($id as xs:int) { delete node fn:collection("/db/widgets")//widget[@id eq $id] };
The method annotations POST
and PUT
may take an
optional string literal which maps the HTTP request body to a named function
parameter. The same syntax as that used for URI templates is applied.
For example
%rest:POST("{$request-body}")
would inject the request body into
the function through the function parameter named 'request-body'. The
function parameter for the request body must meet the following constraints:
Content-Type
header and may be
constrained by means of the %rest:consumes
annotation. The
interpretation of the request body is similar to that of the
EXPath HTTP Client:
Content-Type
header
matches text/*
(excluding text/xml
),
the function parameter type will be xs:string
.
Content-Type
header
is of an XML type, the request body is parsed as XML and
the function parameter type will be document-node()
.
At least the Media Types application/xml
and
text/xml
MUST be interpreted as XML types, although
implementations MAY support additional XML types.
xs:base64Binary
.
Resource Functions MAY be constrained to certain Media Type(s) by means
of a %rest:consumes
annotation. A function will only be invoked
if the HTTP Content-Type
header of the request matches one
of the given Media Types.
(: Will only be invoked if a user supplies one of the specified media types :) declare %rest:path("/widgets") %rest:consumes("application/xml", "application/atom+xml") function local:widgets() { fn:collection("/db/widgets")/widgets };
The %rest:consumes
annotation supports content negotiation in conjunction with the %rest:produces
annotation.
If the %rest:produces
annotation is specified, a function will
only be invoked if the HTTP Accept
header of the request
matches one of the given types.
(: Will only be invoked if a user accepts one of the specified media types :) declare %rest:path("/widgets") %rest:produces("application/xml") function local:widgets() { fn:collection("/db/widgets")/widgets };
The %rest:produces
annotation supports content negotiation in conjunction with the %rest:consumes
annotation.
Parameters to Resource Functions are extracted from the RESTful Web Service request and passed in as additional function parameters. Unlike constraints, parameters are always optional. Resource Function Parameters use the template syntax to map the request parameter onto a function parameter. They may also provide a default value should the parameter not be present in the request. Resource Function Parameters always place the following constraints on the function parameters that they map to:
Conversion from the parameter string to the required function parameter type is performed at run-time, and an error is raised if conversion is impossible.
The annotations in this section MUST have two or more arguments:
The annotation %rest:query-param
is provided for accessing
parameters in the Query string of the URL used for the RESTful Web Service
request.
declare %rest:GET %rest:path("/widget/{$id}") %rest:query-param("client", "{$client}", "unknown") function local:widget($id as xs:int, $client as xs:string*) { fn:collection("/db/widgets")//widget[@id eq $id][@client = $client] };
The annotation %rest:form-param
is provided for accessing
parameters from an HTML form submitted where the HTTP Content-Type
header matches the application/x-www-form-urlencoded
Media Type.
declare %rest:GET %rest:path("/widget/{$id}") %rest:form-param("client", "{$client}", "unknown") function local:widget($id as xs:int, $client as xs:string*) { fn:collection("/db/widgets")//widget[@id eq $id][@client = $client] };
The annotation %rest:header-param
is provided for accessing
HTTP Request headers. If a single header field value contains comma separated
values, an implementation MUST extract each value from the comma separated
list into an item in the sequence provided to the function parameter.
declare %rest:GET %rest:path("/widget/{$id}") %rest:header-param("X-Client-Type", "{$client-type}") function local:widget($id as xs:int, $client-type as xs:string*) { fn:collection("/db/widgets")//widget[@id eq $id][@client-type = $client-type] };
The results of a Resource Function may be serialized back to an HTTP response for the RESTful web service response. A Resource Function may return one of three response types:
%output:method("xml")
. These annotation output
declarations override any defaults from 1.
document-node(element())
or just element()
,
and XML Serialization should be applied to the result of the function.
The annotation %output:method
, if present,
MUST be set to xml
. This is known as the
Default Resource Response rule.
%output:method
annotation on
the Resource Function. The default serialization method is XML.
If the result type is not compatible with the serialization,
an implementation MUST throw an error. This is known as the
Typed Resource Response rule.
document-node(element(rest:response))
.
Any other annotations that effect the serialization of the result are ignored.
item()+
. The first item in the
result sequence is the HTTP headers i.e.
document-node(element(rest:response)
, the second item in the
result sequence is the resource itself; Subsequently both the
Default Resource Response rule and the
Typed Resource Response rule MUST be applied to the result sequence.
A REST Response document may be returned from a function either with or without a Resource. The purpose of this document is to control the REST (in this case HTTP) response sent back to the client of the RESTful web service.
<rest:response> (http:response?) </rest:response> <http:response status?="integer" message?="string"> (http:header*) </http:response> <http:header name="string" value="string"/>
Should the status be omitted for the response, or should a REST Response document not be returned from a Resource Function, then the status defaults to 200 OK. It is expected that implementations will make use of sane defaults for HTTP headers as part of their HTTP responses, however any default headers MUST be overridable by the values set in the REST Response document.
As an example, the following response can be returned to trigger a client-side redirection:
<rest:response> <http:response status="302" message="Temporary Redirect"> <http:header name="location" value="/new/location"/> </http:response> </rest:response>
The base URI of a Resource Function is implementation-defined. That is to say that an implementation is free to define either statically or dynamically the URI part that appears before the relative URI of any Path Annotation ().
Support for content negotiation ([[RFC7231]]) of formats is indirectly provided by the %rest:consumes
and %rest:produces
annotations.
(: Combining consumes and produces provides content negotation support :) declare %rest:path("/widgets") %rest:consumes("application/xml", "application/atom+xml") %rest:produces("application/xml", "application/json") function local:widgets() { fn:collection("/db/widgets")/widgets };
In many cases, there is more than one Resource Function that could service an incoming HTTP Request. This chapter defines how the best matching Resource Function is selected. The specificity of a Resource Function is governed by the following rules, which MUST be applied in order.
Resource Functions that impose the most specific constraints MUST first be selected as candidates to process the HTTP Request.
Most specific constraints first:
The following Resource Function: declare function %rest:GET %rest:path("/a/b/c") %rest:consumes("application/xml") local:function-1() { <fn>1</fn> }; is more specific than: declare function %rest:GET %rest:path("/a/b/c") local:function-2() { <fn>2</fn> };
More than one Path from a Resource Function Path Annotations MAY appear to satisfy a request. Often, these can be disambiguated by specificity of application to the HTTP Request URI. The most specific paths are selected as candidates to process the HTTP Request.
The rules determining Path specificity to a request are:
Path X is more specific than path Y if it has more segments.
/a/b
is more specific than/a
.
If more than one Path has the same number of segments, the segments of the paths are compared from left to right.
Path X is more specific than Path Y if the current segment of Y is a template, while the respective segment of X is not.
/a/b
is more specific than/a/{$x}
./a/{$x}
is more specific than/{$x}/y
.
The following example contains six paths sorted by their specificity:
/person/elisabeth /person/{$name} /{$type}/elisabeth /{$type}/{$name} /person /{$type}
More than one Media Type from Resource Function Consumes or Produces Annotations MAY appear to satisfy a request. Often, these can be disambiguated by specificity. The most specific media types MUST be selected as candidates to process the HTTP Request.
The rules determining media type specificity are:
Absolute Media Types are considered more specific than Media Ranges (Media Types with wildcard subtypes)
application/xml
is more specific thanapplication/*
.
RESTXQ offers a few simple functions to assist with the construction of RESTful Web Services.
Functions to assist in managing the RESTXQ Registry.
rest:resource-functions
() asdocument-node(element(rest:resource-functions))
Summary: This function returns an XML document describing the Resource Functions registered with the RESTXQ Registry.
The XML document root element rest:resource-functions
structure:
<rest:resource-functions> rest:resource-function* </rest:resource-functions>
The rest:resource
XML element has the following structure:
<rest:resource-function xquery-uri = xs:anyURI> <rest:identity namespace = xs:anyURI local-name = xs:NCName arity = xs:int/> </rest:resource-function>
URI functions assist in the construction and selection of URIs.
rest:base-uri
() asxs:anyURI
Summary: This function returns the implementation-defined base URI () of the Resource Function.
rest:uri
() asxs:anyURI
Summary: This function returns the complete URI that addresses the Resource Function. Typically
this is the rest:base-uri()
appended with the path from the Path Annotation (if present) of the Resource Function.
rest:build-absolute-uri($path-segments as
asxs:anyAtomicType+
)xs:anyURI
Summary: This function returns an absolute URI by concatenating the base URI as returned by rest:base-uri() with each path segment in the parameter $path-segments, separating each by a '/' character. The result of this function should be stable across invocations within an implementation.
This section defines the conformance criteria for a RESTXQ 1.0 implementation. An implementation that claims to conform to this specification MUST include a claim of Minimal Conformance as defined in .
An implementation that claims Minimal Conformance to this specification MUST provide all of the following items:
An implementation of everything specified in this document.
A definition of every item specified to be implementation-defined.
If you plan to implement RESTXQ, there is already a set of common abstraction libraries written in Java which should significantly reduce the amount of effort involved and avoid re-inventing more wheels. You need just implement a few interfaces and adapters. For more information see the EXQuery GitHub page.
The grammar used for RESTXQ Templates is expressed in EBNF and re-uses the EQName from the XQuery grammar
[1] | Template | ::= | "{" "$" EQName "}" |
Many thanks to: