RXQ provides a set of annotations to be used on functions in XQuery that expose RESTful services in MarkLogic.
You may use RXQ to build MVC/RESTful apps with MarkLogic XQuery.
RXQ goals are:
- make it easy to build REST endpoints with XQuery
- easy to understand and maintain
- fast, small and simple in design
Feel free to ask questions on hipchat,XQuery mailing list or at IRC channel #rxq on freenode.
Until RXQ has a release version, we list significant changes here
Since MarkLogic 6 XQuery annotations have been supported (XQuery 3.0).
Annotations provide the opportunity to implement Adam Retter's RESTXQ draft (introduced at XML Prague 2012).
RESTXQ is based on the annotations defined within JSR-311.
RXQ is an implementation of a subset of RESTXQ for the MarkLogic server.
MarkLogic 6.0-3 or higher is required version for use with RXQ.
The quickest way to see RXQ in action is to setup the example application under src/example-simple.
First, you need to download and install MarkLogic. Second, create an appserver, providing the following details;
- root: provide directory where example-simple resides on your filesystem
- error handler:
/rxq-rewriter.xqy?mode=error
- rewrite handler:
/rxq-rewriter.xqy?mode=rewrite
Which you can do via MarkLogic Admin GUI or using REST Management API with curl example provided below:
curl -i -X PUT --anyauth --user admin:admin -H "Content-Type:application/json" -d'{"root":"/home/jfuller/projects/rxq/src/example-simple","error-handler":"/rxq-rewriter.xqy?mode=error","url-rewriter":"/rxq-rewriter.xqy?mode=rewrite"}' "http://node1:8002/manage/v2/servers/test8/properties?group-id=Default"
You may now browse with your web browser to the created app (e.g. http://<host>:<port>/) and you should see an html page which is the example-simple application.
- README.md - This document
- rxq-rewriter.xqy - rxq rewriter
- lib/rxq.xqy - rxq library
- src/example-simple - contains example site which demonstrates how to use RXQ
- src/example-dashML - non trivial dashML application (dashboard metrics) using RXQ.
- src/xray - RXQ uses Rob Whitby's excellent XRAY for xquery unit testing
- src/tests - used for testing
To use RXQ in your own application emulate how the example-simple is structured.
Essentially, you will need these files in your project.
- rxq-rewriter.xqy - simple rewriter and entry point where you import modules which include RESTXQ annotations
- lib/rxq.xqy - the RXQ library
Then you will need to setup a MarkLogic appserver (follow example simple instructions), edit rxq-rewriter.xqy to import the library modules containing your RESTXQ annotations.
All the following code examples are included in the example application.
The following xquery module illustrates how to annotate your modules functions using RESTXQ, which in turn will map them to a URL so they can be invoked via an HTTP Request.
xquery version "1.0-ml";
module namespace addr="http://example.org/address";
declare namespace rxq="http://exquery.org/ns/restxq";
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare
%rxq:GET
%rxq:path('/address/id/(.*)')
%rxq:produces('text/html')
%output:method('html')
function addr:get-address($id){
....
};
The addr:get-address($id)
function has defined 4 RESTXQ annotations;
- %rxq:GET: indicates to select when HTTP REQUEST uses GET method
- %rxq:path('/address/id/(.*)'): maps the url /address/id/(.*) to this function, note the usage of regex matching group to capture
$id
- %rxq:produces('text/html'): the output of this function, when returned by HTTP RESPONSE will have a content type of 'text/html'.
- %output:method('html'): makes sure that MarkLogic serializes a HTML document and not an "HTML unaware" XML document.
The addr:get-address()
function is invoked when there is an HTTP GET Request on URL /address/id/(.*).
The routing 'magic' is taken care of by src/xquery/rxq-rewriter.xqy (which you attach to MarkLogic appserver). The %rxq:GET
annotation specifies the HTTP method and the %rxq:path
annotation value specifies the concrete URL.
The value for the addr:get-address
function's $id
variable is taken from the first regex capture group in the url as specified by %rxq:path. This $id value can then be used by some search to lookup the address.
RXQ supports the following RESTXQ annotations at this time;
- HTTP method annotation -
%rxq:GET
|%rxq:PUT
|%rxq:DELETE
|%rxq:POST
- Path annotation (maping url path) -
%rxq:path('/some/path/(.*)')
- Produces annotation (output content-type) -
%rxq:produces('text/html')
- Consumes annotation (ACCEPT) -
- XSLT and XQuery Serialization 3.0 annotations, e.g.
%output:method
,%output:byte-order-mark
,%output:indent
etc - Custom GZIP annotation to compress the response -
%xdmp:gzip
When you deploy these modules in a MarkLogic appserver you must then import those modules into the rxq-rewriter.xqy. for example if you wanted to use the addr:get-address() function, you would import the module in the rxq-rewriter.xqy
(:~ STEP1 - import modules that contain annotation (controllers) here :)
import module namespace addr="http://example.org/addr at "modules/addr.xqy";
This allows the RXQ implementation to scan for annotated functions and generate the neccessary url rewriting and evaluation.
Please review the src/example-simple/rxq-rewriter.xqy to see how to setup your own.
To continue with our address example, lets add a function which inserts an address.
declare
%rxq:PUT
%rxq:path('/address/id/(.*)')
%rxq:produces('text/html')
%rxq:consumes('application/xml')
function addr:insert-address($id){
....
};
we are not interested in the actual implementation details of inserting the address (which could even be delegated to another xquery module, reinforcing the M in MVC). The addr:insert-address
function would be invoked when an HTTP PUT Request is received.
Lastly, if we wanted to remove an address we need to support the HTTP DELETE method.
declare
%rxq:DELETE
%rxq:path('/address/id/(.*)')
%rxq:produces('text/html')
function addr:remove-address($id){
....
};
This function could return some kind of success or failure text/html.
It is the responsibility of your modules to return the correct HTTP status codes and the address library module provides some guidance of how to do this.
These helper functions can be useful to introspect the current RXQ enviroment.
rxq:resource-functions() - returns all functions with RESTXQ annotations and their endpoint
rxq:raw-params() as map:map - returns all in scope url params.
https://github.com/xquery/rxq/wiki/FAQ
The RESTXQ spec is still in draft form; where things are currently unclear or in flux I made my own implementation decisions for the time being;
- no
xdmp:eval
were hurt (or used) in the creation of RXQ ... all execution is done by first class function invokation available using XQuery 3.0 - annotations are mapped onto MarkLogic existing REST library functionality ( rest functions)
- RXQ is not pure XQuery 3.0 due to usage of xdmp: functions, such as xdmp:annotation().
RXQ is released under Apache License v2.0
Copyright 2012-2017 Jim Fuller
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions.
- RXQ github repository.
- EXQuery RESTXQ Draft Specification.
- Adam Retter's RESTXQ.
- JSR-311.