I’ve been learning how to use the BaseX webapp, and below is one of the first test scripts for the REST interface I wrote. No problems with this script.
import module namespace request = "http://exquery.org/ns/request";
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization"; declare option output:omit-xml-declaration "no"; declare option output:method "xhtml"; (: http://docs.basex.org/wiki/XQuery_3.0#Serialization :)
(: declare variable $contains := try { request:parameter( 'contains' ) } catch basex:http { '' };
Simpler to use implicit assignment: http://docs.basex.org/wiki/REST#Assigning_Variables "All query parameters that have not been processed before will be treated as variable assignments" :)
declare variable $contains as xs:string external := ""; declare function local:f0line( $f ) as node() { (: build a list item with function name and function values :)I <li><b>{fn:function-name($f)}:</b> {$f()}</li> };
declare variable $CTX := try { . } catch err:XPDY0002 { () }; declare variable $DB := try { db:name( $CTX[1] ) } catch err:XPTY0004 { "" }; (: Could be, if (): [XPTY0004] node() expected, empty sequence found. but not sure if that's the only possible case. :)
<html><head><title>test</title></head><body> <div id="context"> <h3>Database: { $DB }</h3> <h3>Context documents (.)</h3> <ol> { for $doc in $CTX return <li><b>{base-uri($doc)}</b></li> } </ol> </div>
<div id="request"> <h3>HTTP Request</h3> <ul> { for $f in ( request:method#0, request:scheme#0, request:hostname#0, request:port#0, request:path#0, request:query#0, request:uri#0, request:context-path#0, request:address#0, request:remote-hostname#0, request:remote-address#0, request:remote-port#0 ) return local:f0line($f) } </ul> </div> <div id="params"> <h3>Request Parameters:</h3> <ul> { for $param in request:parameter-names() return <li><b>{$param}:</b> {request:parameter($param)}</li> } </ul> </div> <div id="headers"> <h3>Headers</h3> <ul> { for $header in request:header-names() return <li><b>{$header}:</b> {request:header($header)}</li> } </ul> </div> <div id="cookies" > <h3>Cookies</h3> <ul> { for $cookie in request:cookie-names() return <li><b>{$cookie}:</b> {request:cookie($cookie)}</li> } </ul> </div> <div id="xslt"> <h4>XSLT</h4> <ul> <li><b>xslt:processor: { xslt:processor()},   xslt:version: { xslt:version()}</b></li> </ul> </div> </body></html>
I’m now trying to learn RESTXQ programming, so I was trying to do the same sort of thing from a RESTXQ module.
I was getting an error from the line where (: request:query#0, :) is now commented out, and added the line:
<li>{ request:query( ), function-name(request:query#0)}</li>
And I see that what happens is that it’s the latter function-name(request:query#0) that is generating an error, but only when there is no query string in my request. An empty query string, i.e. “http://localhost/basex/test? http://localhost/basex/test?” , for example, works. But “http://localhost/basex/test http://localhost/basex/test returns:
Stopped at /usr/local/tomcat/webapps/basex/test.xqm, 33/66: [XPTY0004] Cannot convert empty-sequence() to xs:string: ().
I assume this has something to do with how RESTXQ processes form and request parameters, and I probably don’t actually need to do it this way, but I was wondering what exactly is the source of the problem with doing something like this or if there is an obvious work around. Maybe writing another local function to wrap around request:query and to use in that loop.
( One reason I chose that test to convert to RESTXQ was that it wasn’t obvious to be from the docs if I could mix those different access methods, and so what was surprising was that it mostly worked — only that one function failed (so far)).
module namespace test = 'http://localhost/test';
import module namespace request = "http://exquery.org/ns/request";
declare function test:f0line( $f ) as node() { (: build a list item with function name and function values :) <li><b>{fn:function-name($f)}:</b> {$f()}</li> };
(:~ : Generates a welcome page. : @return HTML page :) declare %rest:path("test") %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 test:test( ) as element(Q{http://www.w3.org/1999/xhtml%7Dhtml) { <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>BaseX HTTP Services</title> <link rel="stylesheet" type="text/css" href="static/style.css"/> </head> <body> <div class="right"><a href='/'><img src="static/basex.svg"/></a></div> <h1>TEST</h1> <div id="debug" > <ul> <li>{ request:query( ), function-name(request:query#0)}</li> </ul> </div> <div id="request"> <h3>HTTP Request</h3> <ul> { for $f in ( request:method#0, request:scheme#0, request:hostname#0, request:port#0, request:path#0, (: request:query#0, :) request:uri#0, request:context-path#0, request:address#0, request:remote-hostname#0, request:remote-address#0, request:remote-port#0 ) return test:f0line($f) } </ul> </div> </body> </html> };
Hi Steven,
<li>{ request:query( ), function-name(request:query#0)}</li>
And I see that what happens is that it’s the latter function-name(request:query#0) that is generating an error, but only when there is no query string in my request.
Thanks for the observation. This was due to a little bug in our function signatures (request:query was defined to always return a string). I have fixed this in the new snapshot [1].
It’s definitely a good idea to switch to RESTXQ. The usual way to access query parameters is to use the %rest:query-param annotation (see [2] for an example). If you don’t know the names of the parameters in advance, you’ll indeed need to access the query parameter string and process it manually.
Best, Christian
[1] http://files.basex.org/releases/latest/ [2] http://docs.basex.org/wiki/RESTXQ#Query_Parameters
basex-talk@mailman.uni-konstanz.de