rewrite
is an implementation of MarkLogic's URL Rewriter for HTTP Application Servers. rewrite
aims to provide an expressive language that allows you to specify REST applications. This is intended to make your routing logic simple and easy to maintain:
<routes>
<root> dashboard#show </root>
<resource name="inbox"> <!-- no users named inbox -->
<member action="sent"/>
</resource>
<resource name=":user">
<constraints>
<user type="string" match="^[a-z]([a-z]|[0-9]|_|-)*$"/>
</constraints>
<member action="followers"/> <!-- no repo named followers -->
<resource name=":repo">
<constraints>
<repo match="^[a-z]([a-z]|[0-9]|_|-|\.)*$"/>
</constraints>
<member action="commit/:commit">
<constraints>
<commit type="string" match="[a-zA-Z0-9]+"/>
</constraints>
</member>
<member action="tree/:tag" />
<member action="forks" />
<member action="pulls" />
<member action="graphs/impact" />
<member action="graphs/language" />
</resource>
</resource>
</routes>
Routes are matched in the order you specified and they can be nested. They are dispatched dispatched to a resource XQuery file providing the action as a request field.
rewrite
also enables you to hide specific routes from users given specific constraints.
rewrite
is designed to work with MarkLogic Server only. However it can easily be ported to another product that understands XQuery and has similar capabilities. rewrite
is heavily inspired in the Rails 3.0 routing.
In your HTTP Application Server configuration make rewrite.xqy
the default rewriter script.
This section doesn't cover how to set up an HTTP Application Server in MarkLogic. If you are a beginner I suggest you start by browsing the MarkLogic Developer Community site or sign up for training.
Place the lib
folder of rewrite
in your application root
. Still in the root
create a new file named rewrite.xqy
with the following contents:
xquery version "1.0-ml" ;
import module namespace r = "routes.xqy" at "/lib/routes.xqy" ;
declare variable $routesCfg :=
<routes>
<root> users#list </root>
<get path="users/:id">
<to> users#show </to>
</get>
</routes> ;
r:selectedRoute( $routesCfg )
With the rewrite
in place:
- Request
/
will be dispatched to/resource/users.xqy?action=list
- Request
/users/dscape
will be dispatched to/resource/users.xqy?action=show&id=dscape
You can customize the file path and/or store configurations in a file. If you are curious on how the translation from path to file is done refer to "Supported Features".
Here's an example of how your users.xqy
might look like:
xquery version "1.0-ml";
import module namespace u = "user.xqy" at "/lib/user.xqy";
import module namespace h = "helper.xqy" at "/lib/helper.xqy";
declare function local:list() { u:list() };
declare function local:get() { u:get( h:id() ) } ;
try { xdmp:apply( h:function() ) }
catch ( $e ) { h:error( $e ) }
A centralized error handler can also be used removing the need for a try catch
statement. Refer to the wiki section on using an error handler for instructions.
This assumes a hypothetical users.xqy
XQuery library that models users. It also contains a helper.xqy
module. The helper.xqy
module is contained in lib as an example but is not part of rewrite
, so you can/should modify it to fit your needs; or even create your fully fledged MVC framework.
Name | Type | Meaning | More Info |
---|---|---|---|
Root | Route | Responds to GET requests to the root of the application | Wiki |
Get | Route | Responds to GET requests for a given path | Wiki |
Put | Route | Responds to PUT requests for a given path | Wiki |
Delete | Route | Responds to DELETE requests for a given path | Wiki |
Post | Route | Responds to POST requests for a given path | Wiki |
Head | Route | Responds to HEAD requests for a given path | Wiki |
Resources | Multiple Routes | Creates a RESTful Resource addressable by :id | Wiki |
Resource | Multiple Routes | Creates a singleton RESTful Resource | Wiki |
Name | Type | Meaning | More Info |
---|---|---|---|
Static Files | Static | Serving static files | Wiki |
Constraints | Constraint | Makes rules invisible given constraints | Wiki |
Scopes | Scope | Propagates environment, e.g. constraints. | Wiki |
Route Globbing | Globbing | Allows wildcard routes | Wiki |
You can find a sample applications in the Samples wiki page. Just follow the instructions in the read me file to deploy. If you used rewrite and want to contribute a sample application just add it to the wiki page.
Think the documentation sucks? Think the performance is crap? Think rewrite
is cool but is missing feature X? This is your change to shine: contribute to the project.
- Message
dscape
on github talking about what you want to accomplish. - Fork rewrite in github
- Create a new branch -
git checkout -b my-branch
- Develop/fix the functionality
- Test your changes
- Commit your changes
- Push to your branch -
git push origin my-branch
- Create an pull request
To run the tests simply point an MarkLogic HTTP AppServer to the root of rewrite
You can run the tests by accessing: (assuming 127.0.0.1 is the host and 8090 is the port)
http://127.0.0.1:8090/test/
Make sure all the tests pass before sending in a pull request!
If you want to contribute with a test case please file a issue and attach the following information:
- Request method, request path, and other parts of the request that are relevant (e.g. request headers)
- routes.xml
- paths.xml (if relevant)
- Code:
git clone git://github.com/dscape/rewrite.git
- Home: http://github.com/dscape/rewrite
- Discussion: http://convore.com/marklogic
- Bugs: http://github.com/dscape/rewrite/issues
(oO)--',- in caos