简体   繁体   中英

How does MarkLogic Rewriter uri pattern matching actually work?

I'm looking at this example from: https://docs.marklogic.com/10.0/rest:matching-request

Specifically, this code:

  xquery version "1.0-ml"; 
 
  import module namespace rest="http://marklogic.com/appservices/rest"
  at "/MarkLogic/appservices/utils/rest.xqy";

  declare option xdmp:mapping "false";

  let $options :=
    <options xmlns="http://marklogic.com/appservices/rest">
      <request uri="^/shakespeare/(.+)/(.+)" endpoint="/redirect.xqy">
        <uri-param name="__ml_redirect__">/$1/$2</uri-param>
      </request>
      <request uri="^/shakespeare/(.+)" endpoint="/redirect.xqy">
        <uri-param name="__ml_redirect__">/$1</uri-param>
      </request>
      <request uri="^/(.+)/act(\d+)" endpoint="/endpoint.xqy">
        <uri-param name="play">$1.xml</uri-param>
        <uri-param name="act" as="integer">$2</uri-param>
        <param name="scene" as="integer" values="1|2|3" default="1"/>
      </request>
      <request uri="^/(.+)$" endpoint="/endpoint.xqy">
        <uri-param name="play">$1.xml</uri-param>
      </request>
      <request uri="^/(.+)$" endpoint="/delete.xqy">
        <http method="DELETE"/>
        <param name="reason" required="true"/>
      </request>
      <request uri="^(.+)$" endpoint="/options.xqy" user-params="allow">
        <uri-param name="__ml_options__">$1</uri-param>
        <http method="OPTIONS"/>
      </request>
    </options>

  let $uri     := "/shakespeare/hamlet"
  let $accept  := xdmp:get-request-header("Accept") 
  let $params  := map:map()

  return rest:matching-request($options, ("uri","method"))

Now, I would have thought that the match would be:

  <request uri="^/shakespeare/(.+)" endpoint="/redirect.xqy">
    <uri-param name="__ml_redirect__">/$1</uri-param>
  </request>

But, instead, the match is:

  <request uri="^/(.+)$" endpoint="/endpoint.xqy">
    <uri-param name="play">$1.xml</uri-param>
  </request>

The reason that I'm asking is that I would like to come up with a rule for this expression, which is actually good regex: ^(\/openapi\/.+.yml)$

However, for 1) that regex is invalid according to MarkLogic, but ^(/openapi/.+.yml)$ is valid, and 2) if /shakespeare/hamlet doesn't match ^/shakespeare/(.+)/(.+) , then I don't understand what the regex is supposed to be that would match it.

I believe the issue is that when you are executing the code to test in Query Console, it is using the URI of your Query Console request: /qconsole/endpoints/evaler.xqy .

The code example is a little confusing, because it has let $uri:= "/shakespeare/hamlet" , but that $uri is not used. I believe the intent was to show you what the request URI would be, and then demonstrate how the rest:matching-request() function would behave.

You can verify that the URI is indeed /qconsole/endpoints/evaler.xqy by executing this:

import module namespace rest="http://marklogic.com/appservices/rest"
  at "/MarkLogic/appservices/utils/rest.xqy";
let $options :=
  <options xmlns="http://marklogic.com/appservices/rest">
    <request uri="/qconsole/endpoints/evaler.xqy" endpoint="/redirect.xqy">
      <uri-param name="__ml_redirect__">/QUERY-CONSOLE-TEST</uri-param>
    </request>
  </options>
return rest:matching-request($options, "uri")

Also, if you configure an invalid regex, the error message for the matches() will reveal what the actual URL is:

import module namespace rest="http://marklogic.com/appservices/rest"
  at "/MarkLogic/appservices/utils/rest.xqy";
let $options :=
  <options xmlns="http://marklogic.com/appservices/rest">
    <request uri="\/" endpoint="/redirect.xqy">
      <uri-param name="__ml_redirect__">INVALID-REGEX-TEST</uri-param>
    </request>
  </options>
return rest:matching-request($options, "uri")

returns:

[1.0-ml] XDMP-REGEX: (err:FORX0002) fn:matches("/qconsole/endpoints/evaler.xqy", attribute{fn:QName("","uri")}{"/"}) -- Invalid regular expression

You can look under the covers and see how the rest module calls rest-impl.xqy methods and perform tests using the implementation functions:

declare namespace rest="http://marklogic.com/appservices/rest"; 
import module namespace rest-impl="http://marklogic.com/appservices/rest-impl"
  at  "/MarkLogic/appservices/utils/rest-impl.xqy";
let $options :=
  <options xmlns="http://marklogic.com/appservices/rest">
    <request uri="^(/openapi/.+.yml)$" endpoint="/redirect.xqy"/>
  </options>
  
let $reqenv := rest-impl:request-environment()
let $_ := map:put($reqenv, "uri", "/openapi/foo.yml") 
return
  rest-impl:matching-request-wrapper($options/rest:request, $reqenv, "uri")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM