Skip to content

Instantly share code, notes, and snippets.

@line-o
Last active February 19, 2021 19:47
Show Gist options
  • Save line-o/f520ac94d2a02578b6ad84de53b2dbf5 to your computer and use it in GitHub Desktop.
Save line-o/f520ac94d2a02578b6ad84de53b2dbf5 to your computer and use it in GitHub Desktop.
Questions and wishes for RestXQ implementation in existdb

Tests:

url test status
/resources pass 200
/resources/ fail 405
/resources?query=a pass 200
/resources/?query=a fail 405
/resources/a pass 200
/resources/d pass 404

Questions

  • Are query-parameters implicitly cast to the type specified in the handler (xs:integer, array())?
  • How does one get the list of registered endpoints? The documented function rest:resource-functions() does not seem to work.
  • Which registered function wins when in one db instance multiple modules register '/resource'. Do the specificity rules apply?

Feature request 1:

Enable error handlers by annotation (see routes:detail and routes:not-found).

Feature request 2:

Improve logging/tooling: it is sometimes hard to know if a handler was registered and if not why.

Feature request 3:

Having to juggle all n parameters is cumbersome when output can happen in multiple formats. Generally I do prefer one map passed to the handler with all interesting (processed) request data

  $request := map {
    'parameters': map { 'id': ... }
    'query-parameters': map { 'query': ...,  }
    'headers': map { 'e-tag': ..., 'If-None-Match': ..., ...  }
  }
xquery version "3.1";
module namespace routes="http://line-o.de/restxq/routes";
declare namespace rest="http://exquery.org/ns/restxq";
declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";
declare namespace http="http://expath.org/ns/http-client";
declare variable $routes:data := (
map {'id':'a'},
map {'id':'b'},
map {'id':'c'}
);
(:~
list handler with basic querying
:)
declare
%rest:GET
%rest:path("/resources")
%rest:produces("application/json")
%output:media-type("application/json")
%output:method("json")
%rest:query-param('query', '{$query}', '')
%rest:query-param('offset', '{$offset}', '0')
%rest:query-param('limit', '{$limit}', '100')
function routes:list($query, $offset, $limit) {
let $list :=
if ($query)
then (filter($routes:data, function ($element) { $element?id = $query }))
else ($routes:data)
return array { $list }
};
(:~
: Retrieve a name by id.
:)
declare
%rest:GET
%rest:path("/resources/{$id}")
%rest:produces("application/json")
%output:media-type("application/json")
%output:method("json")
function routes:detail($id as xs:string) {
let $element := filter($routes:data, function ($element) { $element?id = $id })
return
if (not(exists($element)))
then (routes:not-found(map { 'error': 'Resource with id:"' || $id || '" could not be found.' }))
(: throwing an error could be done here but unsure what is possible :)
(: then (error('err:404', map { 'error': $id || ' Not Found' })) :)
else ($element)
};
(:~
: rest error handler (annotation not supported yet)
%rest:GET
%rest:error("err:404")
:)
declare
function routes:not-found ($data as item()) {
<rest:response>
<http:response status="404" message="Not Found"/>
</rest:response>,
$data
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment