<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Wtr (wtr.Wtr)</title><link rel="stylesheet" href="../../odoc.css"/><meta charset="utf-8"/><meta name="generator" content="odoc 91f631096"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><script src="../../highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body class="odoc"><nav class="odoc-nav"><a href="../index.html">Up</a> – <a href="../index.html">wtr</a> &#x00BB; Wtr</nav><header class="odoc-preamble"><h1>Module <code><span>Wtr</span></code></h1><p><i>Well Typed Router</i> - is a HTTP request routing library for OCaml web applications.</p><p>Given a HTTP <i>request_target</i> and a HTTP <i>method</i>, <code>Wtr</code> attempts to match the two properties to a pre-defined set of <i>route</i>s. If a match is found then the corresponding <i>route handler</i> function of the matched route is executed.</p><p>The route matching algorithm is <i>radix trie</i>.</p><p>The <i>well typed</i> part in <code>Wtr</code> means that the <i>route handler</i> functions can capture and receive arguments which are typed in a variety of OCaml types.</p><p>There are two ways to specify <i>route</i> and <i>request target</i>s:</p><ul><li><a href="#request_target_dsl">Request Target Combinators</a> - combinators based</li><li><code>[%routes &quot;&quot;]</code> - ppx based which is provided by a separate opam package <code>wtr-ppx</code>.</li></ul></header><nav class="odoc-toc"><ul><li><a href="#types">Types</a></li><li><a href="#arg_func">Arg</a></li><li><a href="#request_target_dsl">Request Target Combinators</a><ul><li><a href="#illustration-1:-request_target-consisting-of-path-only">Illustration 1: request_target consisting of path only</a></li><li><a href="#illustration-2:-request_target-consisting-of-path-and-query">Illustration 2: request_target consisting of path and query</a></li><li><a href="#general-components">General Components</a></li><li><a href="#arg-components">Arg Components</a><ul><li><a href="#path_arg">Path</a></li><li><a href="#query">Query</a></li></ul></li><li><a href="#last-path-component">Last Path Component</a></li></ul></li><li><a href="#routes-and-router">Routes and Router</a></li><li><a href="#http-method">HTTP Method</a></li><li><a href="#pp">Pretty Printers and Debugging</a></li><li><a href="#references">References</a></li></ul></nav><div class="odoc-content"><h2 id="types"><a href="#types" class="anchor"></a>Types</h2><div class="odoc-spec"><div class="spec type" id="type-router" class="anchored"><a href="#type-router" class="anchor"></a><code><span><span class="keyword">type</span> <span>'a router</span></span></code></div><div class="spec-doc"><p>A <a href="#type-router"><code>router</code></a> consists of one or many HTTP request <a href="#type-route"><code>route</code></a>s which are used to match a given HTTP request target.</p><p><code>'a</code> is a value which is returned by a <i>route handler</i> of the matched <i>route</i>.</p></div></div><div class="odoc-spec"><div class="spec type" id="type-route" class="anchored"><a href="#type-route" class="anchor"></a><code><span><span class="keyword">and</span> <span>'a route</span></span></code></div><div class="spec-doc"><p><a href="#type-route"><code>route</code></a> is a HTTP request route. A route encapsulates a HTTP <a href="#type-method'"><code>method'</code></a>, a <a href="#type-request_target"><code>request_target</code></a> and a <i>route handler</i>. A <i>route handler</i> is either of the following:</p><ul><li>a value of type <code>'a</code></li><li>or a function which returns a value of type <code>'a</code>.</li></ul></div></div><div class="odoc-spec"><div class="spec type" id="type-routes" class="anchored"><a href="#type-routes" class="anchor"></a><code><span><span class="keyword">and</span> <span>'a routes</span></span><span> = <span><span><span class="type-var">'a</span> <a href="#type-route">route</a></span> list</span></span></code></div></div><div class="odoc-spec"><div class="spec type" id="type-request_target" class="anchored"><a href="#type-request_target" class="anchor"></a><code><span><span class="keyword">and</span> <span>('a, 'b) request_target</span></span></code></div><div class="spec-doc"><p><a href="#type-request_target"><code>request_target</code></a> is a HTTP request target value to be matched. It consists of either just a <a href="#type-path"><code>path</code></a> value or a combination of <a href="#type-path"><code>path</code></a> and <a href="#type-query"><code>query</code></a> values.</p><p>Example <i>request_target</i> values:</p><ul><li><code>/home/about/</code> - path only</li><li><code>/home/contact</code> - path only</li><li><code>/home/contact?name=a&amp;no=123</code> - path (<code>/home/contact</code>) and query (<code>name=a&amp;no=123</code>). Path and query are delimited by <code>?</code> character token if both are specified.</li></ul><p>Consult <a href="#request_target_dsl">Request Target DSL</a> for creating values of this type.</p><p>See <a href="https://datatracker.ietf.org/doc/html/rfc7230#section-5.3">HTTP RFC 7230 - request target</a>.</p></div></div><div class="odoc-spec"><div class="spec type" id="type-path" class="anchored"><a href="#type-path" class="anchor"></a><code><span><span class="keyword">and</span> <span>('a, 'b) path</span></span></code></div><div class="spec-doc"><p><a href="#type-path"><code>path</code></a> is a part of <a href="#type-request_target"><code>request_target</code></a>. It consists of one or more <b>path component</b>s. <b>path component</b>s are tokens which are delimited by a <code>/</code> character token.</p><p>Example of <i>path</i> and <i>path component</i>s:</p><ul><li><code>/</code> has path a component <code>/</code></li><li><code>/home/about</code> has path components <code>home, about</code></li><li><code>/home/contact/</code> has path components <code>home</code>, <code>contact</code> and <code>/</code></li></ul><p>Consult <a href="#request_target_dsl">Request Target DSL</a> for creating values of this type.</p></div></div><div class="odoc-spec"><div class="spec type" id="type-rest" class="anchored"><a href="#type-rest" class="anchor"></a><code><span><span class="keyword">and</span> rest</span></code></div><div class="spec-doc"><p><a href="#type-rest"><code>rest</code></a> represents a part of <i>request target</i> from a given path component to the rest of a <i>request_target</i>.</p><p>Use <a href="#val-rest_to_string"><code>rest_to_string</code></a> to convert to string representation.</p></div></div><div class="odoc-spec"><div class="spec type" id="type-query" class="anchored"><a href="#type-query" class="anchor"></a><code><span><span class="keyword">and</span> <span>('a, 'b) query</span></span></code></div><div class="spec-doc"><p><a href="#type-query"><code>query</code></a> is a part of <a href="#type-request_target"><code>request_target</code></a>. It consists of one of more <b>query component</b>s which are delimited by a <code>&amp;</code> character token. A <b>query component</b> further consists of a pair of values called <code>name</code> and <code>value</code>. <code>name</code> and <code>value</code> tokens are delimited by a <code>=</code> character token. A <b>query component</b> is represented syntactically as <code>(name,value)</code>.</p><p>Given a <i>request_target</i> <code>/home/about?a=2&amp;b=3</code>, the <b>query component</b>s are <code>(a,2)</code> and <code>(b,3)</code>.</p><p>Consult <a href="#request_target_dsl">Request Target DSL</a> for creating values of this type.</p></div></div><div class="odoc-spec"><div class="spec type" id="type-method'" class="anchored"><a href="#type-method'" class="anchor"></a><code><span><span class="keyword">and</span> method'</span><span> = </span><span>[ </span></code><table><tr id="type-method'.GET" class="anchored"><td class="def constructor"><a href="#type-method'.GET" class="anchor"></a><code><span>| </span></code><code><span>`GET</span></code></td></tr><tr id="type-method'.HEAD" class="anchored"><td class="def constructor"><a href="#type-method'.HEAD" class="anchor"></a><code><span>| </span></code><code><span>`HEAD</span></code></td></tr><tr id="type-method'.POST" class="anchored"><td class="def constructor"><a href="#type-method'.POST" class="anchor"></a><code><span>| </span></code><code><span>`POST</span></code></td></tr><tr id="type-method'.PUT" class="anchored"><td class="def constructor"><a href="#type-method'.PUT" class="anchor"></a><code><span>| </span></code><code><span>`PUT</span></code></td></tr><tr id="type-method'.DELETE" class="anchored"><td class="def constructor"><a href="#type-method'.DELETE" class="anchor"></a><code><span>| </span></code><code><span>`DELETE</span></code></td></tr><tr id="type-method'.CONNECT" class="anchored"><td class="def constructor"><a href="#type-method'.CONNECT" class="anchor"></a><code><span>| </span></code><code><span>`CONNECT</span></code></td></tr><tr id="type-method'.OPTIONS" class="anchored"><td class="def constructor"><a href="#type-method'.OPTIONS" class="anchor"></a><code><span>| </span></code><code><span>`OPTIONS</span></code></td></tr><tr id="type-method'.TRACE" class="anchored"><td class="def constructor"><a href="#type-method'.TRACE" class="anchor"></a><code><span>| </span></code><code><span>`TRACE</span></code></td></tr><tr id="type-method'.Method" class="anchored"><td class="def constructor"><a href="#type-method'.Method" class="anchor"></a><code><span>| </span></code><code><span>`Method <span class="keyword">of</span> string</span></code></td></tr></table><code><span> ]</span></code></div><div class="spec-doc"><p><a href="#type-method'"><code>method'</code></a> is a HTTP request method. See <a href="https://datatracker.ietf.org/doc/html/rfc7231#section-4">HTTP RFC 7231 - HTTP Methods</a></p></div></div><div class="odoc-spec"><div class="spec type" id="type-arg" class="anchored"><a href="#type-arg" class="anchor"></a><code><span><span class="keyword">and</span> <span>'a arg</span></span></code></div><div class="spec-doc"><p><a href="#type-arg"><code>arg</code></a> is a component which can convert a <b>path component</b> or a <b>query component</b> <code>value</code> token into an OCaml typed value represented by <code>'a</code>. The successfully converted value is then fed to a <i>route handler</i> function as an argument.</p></div></div><h2 id="arg_func"><a href="#arg_func" class="anchor"></a>Arg</h2><div class="odoc-spec"><div class="spec value" id="val-arg" class="anchored"><a href="#val-arg" class="anchor"></a><code><span><span class="keyword">val</span> arg : <span>string <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>string <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> option</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <a href="#type-arg">arg</a></span></span></code></div><div class="spec-doc"><p><code>arg name convert</code> is <a href="#type-arg"><code>arg</code></a> with name <code>name</code> and <code>convert</code> as the function which will convert/decode a string value to an OCaml value of type <code>'a</code>.</p><p><code>name</code> is used during the pretty-printing of <i>request_target</i> by <a href="#val-pp_request_target"><code>pp_request_target</code></a>.</p><p><code>convert v</code> is <code>Some a</code> if <code>convert</code> can successfully convert <code>v</code> to <code>a</code>. Otherwise it is <code>None</code>.</p><p>Although not strictly necessary if we are only working with <i>Request Target DSL</i>, it is recommended to adhere to the following convention when creating a custom arg. Such an <code>'a arg</code> value can be used with both <i>Request Target DSL</i> and <code>wtr-ppx</code> ppxes. The convention is as follows:</p><ol><li>Arg value be encapsulated in a module</li><li>The module define a type called <code>t</code></li><li>The module define a value called <code>t</code> which is of type <code>t Wtr.arg</code></li><li>The <code>name</code> value of the <i>arg</i> match the name of the module.</li></ol><p>An example of such an <code>'a arg</code> component - <code>Fruit.t arg</code> is as below:</p><pre><code>module Fruit = struct
  type t = Apple | Orange | Pineapple

  let t : t Wtr.arg =
    Wtr.arg &quot;Fruit&quot; (function
      | &quot;apple&quot; -&gt; Some Apple
      | &quot;orange&quot; -&gt; Some Orange
      | &quot;pineapple&quot; -&gt; Some Pineapple
      | _ -&gt; None )
end</code></pre><p>See <a href="#val-parg"><code>parg</code></a> and <a href="#val-qarg"><code>qarg</code></a> for usage in <i>path</i> and <i>query</i> components.</p></div></div><h2 id="request_target_dsl"><a href="#request_target_dsl" class="anchor"></a>Request Target Combinators</h2><p>Request Target combinators implement a DSL(domain specific language) to specify <a href="#type-request_target"><code>request_target</code></a>, <b>path component</b> and <b>query component</b> values.</p><h5 id="illustration-1:-request_target-consisting-of-path-only"><a href="#illustration-1:-request_target-consisting-of-path-only" class="anchor"></a>Illustration 1: request_target consisting of path only</h5><p>Let's assume that we want to specify a HTTP route which matches a request target value as such:</p><ol><li>match a string literal &quot;home&quot; exactly</li><li>followed by a valid OCaml <code>int</code> value</li><li>and then finally followed by an OCaml <code>string</code> value</li></ol><p>The <i>request target</i> is implemented as such:</p><pre><code>let target1 = Wtr.(exact &quot;hello&quot; / int / string /. pend) </code></pre><p><code>target1</code> above matches the following instances of HTTP request target:</p><ul><li><code>/home/2/str1</code></li><li><code>/home/-10/str3</code></li></ul><h5 id="illustration-2:-request_target-consisting-of-path-and-query"><a href="#illustration-2:-request_target-consisting-of-path-and-query" class="anchor"></a>Illustration 2: request_target consisting of path and query</h5><p>Let's assume that we want to specify a HTTP route which matches a request target value which consists of both path and query as such:</p><ol><li>match a string literal &quot;hello&quot; exactly</li><li>followed by a valid OCaml <code>bool</code> value</li><li>followed by a query component where the field name is &quot;i&quot; and the query value is a valid OCaml <code>int</code> value.</li><li>and then finally a query component where the field name is &quot;s&quot; and the query value is an OCaml <code>string</code> value.</li></ol><p>The <i>request_target</i> is implemented as such:</p><pre><code>let target2 = Wtr.(exact &quot;hello&quot; / bool /? qint &quot;i&quot; / qstring &quot;s&quot; /?. ())</code></pre><p><code>target2</code> above matches the following instances of HTTP request target:</p><ul><li><code>/hello/true?i=233&amp;s=str1</code></li><li><code>/hello/false?i=-1234&amp;s=str2</code></li></ul><h3 id="general-components"><a href="#general-components" class="anchor"></a>General Components</h3><div class="odoc-spec"><div class="spec value" id="val-(/)" class="anchored"><a href="#val-(/)" class="anchor"></a><code><span><span class="keyword">val</span> (/) : <span><span>(<span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'c</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span class="type-var">'d</span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'d</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'c</span></span></code></div><div class="spec-doc"><p><code> p1 / p2</code> is a closure that <i>combines</i> <code>p1</code> and <code>p2</code>. <code>p1</code> and <code>p2</code> are closures which encapsulate <a href="#type-path"><code>path</code></a> value.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-(/&amp;)" class="anchored"><a href="#val-(/&amp;)" class="anchor"></a><code><span><span class="keyword">val</span> (/&amp;) : <span><span>(<span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'c</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span class="type-var">'d</span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'d</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'c</span></span></code></div><div class="spec-doc"><p><code>q1 /&amp; q1</code> is a closure that <i>combines</i> <code>q1</code> and <code>q2</code>. <code>q1</code> and <code>q2</code> are closures which encapsulate <a href="#type-query"><code>query</code></a> value.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-(/?)" class="anchored"><a href="#val-(/?)" class="anchor"></a><code><span><span class="keyword">val</span> (/?) : <span><span>(<span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'c</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span class="type-var">'d</span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'d</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'c</span></span></code></div><div class="spec-doc"><p><code> p /? q</code> is a closure which <i>combines</i> <code>p</code> and <code>q</code>. <code>p</code> is a closure which encapsulates <a href="#type-path"><code>path</code></a> value and <code>q</code> is a closure which encapsulates <a href="#type-query"><code>query</code></a> value.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-(//.)" class="anchored"><a href="#val-(//.)" class="anchor"></a><code><span><span class="keyword">val</span> (//.) : <span><span>(<span><span><span>(<span class="type-var">'d</span>, <span class="type-var">'e</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'b</span>, <span class="type-var">'c</span>)</span> <a href="#type-path">path</a></span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'d</span>, <span class="type-var">'e</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'b</span>, <span class="type-var">'c</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code> p //. pe</code> is <a href="#type-path"><code>path</code></a> that consists of only path components <code>p</code> and <code>pe</code>. <code>pe</code> is a path value that matches the last path component.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-(/.)" class="anchored"><a href="#val-(/.)" class="anchor"></a><code><span><span class="keyword">val</span> (/.) : <span><span>(<span><span><span>(<span class="type-var">'d</span>, <span class="type-var">'e</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'b</span>, <span class="type-var">'c</span>)</span> <a href="#type-path">path</a></span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'d</span>, <span class="type-var">'e</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'b</span>, <span class="type-var">'c</span>)</span> <a href="#type-request_target">request_target</a></span></span></code></div><div class="spec-doc"><p><code> p /. pe</code> is a <a href="#type-request_target"><code>request_target</code></a> value that consists of only path components <code>p</code> and <code>pe</code>. <code>pe</code> is a path value that matches the last path component. It is equivalent to the following:</p><pre><code>let p = Wtr.(exact &quot;hello&quot; / exact &quot;about&quot; //. pend) |&gt; Wtr.of_path </code></pre></div></div><div class="odoc-spec"><div class="spec value" id="val-(/?.)" class="anchored"><a href="#val-(/?.)" class="anchor"></a><code><span><span class="keyword">val</span> (/?.) : <span><span>(<span><span><span>(<span class="type-var">'b</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'c</span>, <span class="type-var">'d</span>)</span> <a href="#type-path">path</a></span>)</span> <span class="arrow">&#45;&gt;</span></span> <span>unit <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'c</span>, <span class="type-var">'d</span>)</span> <a href="#type-request_target">request_target</a></span></span></code></div><div class="spec-doc"><p><code> pq /?. ()</code> is <a href="#type-request_target"><code>request_target</code></a>. <code>pq</code> is a closure which encapulates both <a href="#type-path"><code>path</code></a> and <a href="#type-query"><code>query</code></a> components.</p><pre><code>let request_target1 =
  Wtr.(
    exact &quot;hello&quot;
    / bool
    /? qint &quot;hello&quot;
    /&amp; qstring &quot;hh&quot;
    /&amp; qbool &quot;b&quot;
    /?. ())</code></pre></div></div><div class="odoc-spec"><div class="spec value" id="val-of_path" class="anchored"><a href="#val-of_path" class="anchor"></a><code><span><span class="keyword">val</span> of_path : <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-request_target">request_target</a></span></span></code></div><div class="spec-doc"><p><code>of_path path</code> converts <code>path</code> to <a href="#type-request_target"><code>request_target</code></a></p></div></div><div class="odoc-spec"><div class="spec value" id="val-exact" class="anchored"><a href="#val-exact" class="anchor"></a><code><span><span class="keyword">val</span> exact : <span>string <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code>exact e p</code> matches a path component to <code>e</code> exactly.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-qexact" class="anchored"><a href="#val-qexact" class="anchor"></a><code><span><span class="keyword">val</span> qexact : <span><span>(string * string)</span> <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span></span></code></div><div class="spec-doc"><p><code>qexact (field, e)</code> matches a query component to <code>e</code> exactly. The query component token <code>name</code> value is <code>field</code>.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-to_request_target" class="anchored"><a href="#val-to_request_target" class="anchor"></a><code><span><span class="keyword">val</span> to_request_target : <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-request_target">request_target</a></span></span></code></div><div class="spec-doc"><p><code>to_request_target p</code> is <a href="#type-request_target"><code>request_target</code></a> consisting of only path <code>p</code>.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-root" class="anchored"><a href="#val-root" class="anchor"></a><code><span><span class="keyword">val</span> root : <span><span>(<span class="type-var">'a</span>, <span class="type-var">'a</span>)</span> <a href="#type-request_target">request_target</a></span></span></code></div><div class="spec-doc"><p><code>root</code> is a <i>request_target</i> with <code>/</code> as the only component, i.e. it matches exactly the root HTTP request.</p></div></div><h3 id="arg-components"><a href="#arg-components" class="anchor"></a>Arg Components</h3><p>Path/Query arg components encapsulate <a href="#type-arg"><code>arg</code></a> value which are then fed to a <i>route handler</i> function as an argument.</p><h4 id="path_arg"><a href="#path_arg" class="anchor"></a>Path</h4><div class="odoc-spec"><div class="spec value" id="val-int" class="anchored"><a href="#val-int" class="anchor"></a><code><span><span class="keyword">val</span> int : <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>int <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code>int</code> matches valid OCaml <code>int</code> values.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-int32" class="anchored"><a href="#val-int32" class="anchor"></a><code><span><span class="keyword">val</span> int32 : <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>int32 <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code>int32</code> matches valid OCaml <code>int32</code> values.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-int64" class="anchored"><a href="#val-int64" class="anchor"></a><code><span><span class="keyword">val</span> int64 : <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>int64 <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code>int64</code> matches valid OCaml <code>int64</code> values.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-float" class="anchored"><a href="#val-float" class="anchor"></a><code><span><span class="keyword">val</span> float : <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>float <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code>float</code> matches valid OCaml <code>float</code> and <code>int</code> values.</p><p><b>Note</b> In addition to OCaml <code>float</code> values, the combinator can also match OCaml <code>int</code> values. Therefore:</p><p>Given, <code>p</code> is</p><pre><code>let p = Wtr.(float /. pend) </code></pre><p>then, it can match the following instances of HTTP request targets:</p><ul><li><code>/123</code></li><li><code>/-234</code></li><li><code>/123.</code></li><li><code>/123.02</code></li><li><code>/-123.</code></li><li><code>/-123.22</code></li></ul></div></div><div class="odoc-spec"><div class="spec value" id="val-bool" class="anchored"><a href="#val-bool" class="anchor"></a><code><span><span class="keyword">val</span> bool : <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>bool <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code>bool</code> matches a path component if it is equal to either <code>&quot;true&quot;</code> or <code>&quot;false&quot;</code> and converts them to valid OCaml <code>bool</code> values.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-string" class="anchored"><a href="#val-string" class="anchor"></a><code><span><span class="keyword">val</span> string : <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>string <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code>string</code> matches valid OCaml <code>string</code> values.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-parg" class="anchored"><a href="#val-parg" class="anchor"></a><code><span><span class="keyword">val</span> parg : <span><span><span class="type-var">'c</span> <a href="#type-arg">arg</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span class="type-var">'c</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code>parg d p</code> matches a path component if <code>d</code> can successfully convert path component to a value of type <code>'c</code>.</p><p>The example below uses the <code>Fruit.t arg</code> defined <a href="#arg_func">above</a>:</p><pre><code>let p = Wtr.(parg Fruit.t /. pend) </code></pre><p><code>p</code> matchs the following instances of HTTP request target values:</p><ul><li><code>/pineapple</code></li><li><code>/apple</code></li><li><code>/orange</code></li></ul></div></div><h4 id="query"><a href="#query" class="anchor"></a>Query</h4><div class="odoc-spec"><div class="spec value" id="val-qint" class="anchored"><a href="#val-qint" class="anchor"></a><code><span><span class="keyword">val</span> qint : <span>string <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>int <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span></span></code></div><div class="spec-doc"><p><code>qint field</code> matches a valid OCaml <code>int</code> value. <code>field</code> is the <code>name</code> token of <i>query component</i>.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-qint32" class="anchored"><a href="#val-qint32" class="anchor"></a><code><span><span class="keyword">val</span> qint32 : <span>string <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>int32 <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span></span></code></div><div class="spec-doc"><p><code>qint32 field</code> matches a valid OCaml <code>int32</code> value. <code>field</code> is the <code>name</code> token of <i>query component</i>.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-qint64" class="anchored"><a href="#val-qint64" class="anchor"></a><code><span><span class="keyword">val</span> qint64 : <span>string <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>int64 <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span></span></code></div><div class="spec-doc"><p><code>qint64 field</code> matches a valid OCaml <code>int64</code> value. <code>field</code> is the <code>name</code> token of <i>query component</i>.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-qfloat" class="anchored"><a href="#val-qfloat" class="anchor"></a><code><span><span class="keyword">val</span> qfloat : <span>string <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>float <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span></span></code></div><div class="spec-doc"><p><code>qfloat field</code> matches a valid OCaml <code>float</code> value. <code>field</code> is the <code>name</code> token of <i>query component</i>.</p><p>The values matched by this combinator is the same as the <a href="#val-float"><code>float</code></a> combinator.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-qbool" class="anchored"><a href="#val-qbool" class="anchor"></a><code><span><span class="keyword">val</span> qbool : <span>string <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>bool <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span></span></code></div><div class="spec-doc"><p><code>qbool field</code> matches query component if <code>value</code> token is equal to either <code>&quot;true&quot;</code> or <code>&quot;false&quot;</code>. The <code>value</code> token is then converted to a valid OCaml <code>bool</code> value. <code>field</code> is the <code>name</code> token of <i>query component</i>.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-qstring" class="anchored"><a href="#val-qstring" class="anchor"></a><code><span><span class="keyword">val</span> qstring : <span>string <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>string <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span></span></code></div><div class="spec-doc"><p><code>qstring field</code> matches a valid OCaml <code>string</code> value. <code>field</code> is the <code>name</code> token of <i>query component</i>.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-qarg" class="anchored"><a href="#val-qarg" class="anchor"></a><code><span><span class="keyword">val</span> qarg : <span><span>(string * <span><span class="type-var">'c</span> <a href="#type-arg">arg</a></span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span class="type-var">'c</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-query">query</a></span></span></code></div><div class="spec-doc"><p><code>qarg (field, d)</code> matches a query component if <code>d</code> can successfully convert path component to a value of type <code>'c</code>. <code>field</code> is the <code>name</code> token of <i>query component</i>.</p><p>The example below uses the <code>Fruit.t arg</code> defined <a href="#arg_func">above</a>:</p><pre><code>let p = Wtr.(exact &quot;hello&quot; /? qarg (&quot;fruit&quot;, Fruit.t) /?. ()) </code></pre><p><code>p</code> matchs the following instances of HTTP request target values:</p><ul><li><code>/hello?fruit=pineapple</code></li><li><code>/hello?fruit=apple</code></li><li><code>/hello?fruit=orange</code></li></ul></div></div><h3 id="last-path-component"><a href="#last-path-component" class="anchor"></a>Last Path Component</h3><p>These combinators match the last - <i>end</i> - path component. They are used with <a href="#val-(/.)"><code>(/.)</code></a> function.</p><div class="odoc-spec"><div class="spec value" id="val-pend" class="anchored"><a href="#val-pend" class="anchor"></a><code><span><span class="keyword">val</span> pend : <span><span>(<span class="type-var">'a</span>, <span class="type-var">'a</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code>pend</code> matches the end of <a href="#type-path"><code>path</code></a> value.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-rest" class="anchored"><a href="#val-rest" class="anchor"></a><code><span><span class="keyword">val</span> rest : <span><span>(<span><a href="#type-rest">rest</a> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>, <span class="type-var">'a</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code>rest</code> matches and captures all of the remaining path and query components. The captured value is then fed to a <i>route handler</i>.</p><pre><code>let%expect_test &quot;rest: comb&quot; =
  ( Wtr.(router [routes [`GET] (exact &quot;public&quot; /. rest) rest_to_string])
  |&gt; Wtr.match' `GET &quot;/public/styles/style.css&quot;
  |&gt; function Some s -&gt; print_string s | None -&gt; () ) ;
  [%expect {| styles/style.css |}]</code></pre></div></div><div class="odoc-spec"><div class="spec value" id="val-slash" class="anchored"><a href="#val-slash" class="anchor"></a><code><span><span class="keyword">val</span> slash : <span><span>(<span class="type-var">'a</span>, <span class="type-var">'a</span>)</span> <a href="#type-path">path</a></span></span></code></div><div class="spec-doc"><p><code>slash</code> matches path component <code>/</code> first and then matches the end of the <a href="#type-path"><code>path</code></a> value.</p><pre><code>let%expect_test &quot;slash matched&quot; =
  ( Wtr.(router [routes [`GET] (exact &quot;public&quot; /. slash) &quot;slash&quot;])
  |&gt; Wtr.match' `GET &quot;/public/&quot;
  |&gt; function Some s -&gt; print_string s | None -&gt; () ) ;
  [%expect {| slash |}]

let%expect_test &quot;slash not matched&quot; =
  ( Wtr.(router [routes [`GET] (exact &quot;public&quot; /. slash) &quot;slash&quot;])
  |&gt; Wtr.match' `GET &quot;/public&quot;
  |&gt; function Some s -&gt; print_string s | None -&gt; () ) ;
  [%expect {| |}]</code></pre></div></div><div class="odoc-spec"><div class="spec value" id="val-rest_to_string" class="anchored"><a href="#val-rest_to_string" class="anchor"></a><code><span><span class="keyword">val</span> rest_to_string : <span><a href="#type-rest">rest</a> <span class="arrow">&#45;&gt;</span></span> string</span></code></div><div class="spec-doc"><p><code>rest_to_string rest</code> converts <code>rest</code> to string.</p></div></div><h2 id="routes-and-router"><a href="#routes-and-router" class="anchor"></a>Routes and Router</h2><div class="odoc-spec"><div class="spec value" id="val-route" class="anchored"><a href="#val-route" class="anchor"></a><code><span><span class="keyword">val</span> route : <span><a href="#type-method'">method'</a> <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-request_target">request_target</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'b</span> <a href="#type-route">route</a></span></span></code></div><div class="spec-doc"><p><code>route method' request_target handler</code> is a <a href="#type-route"><code>route</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-routes" class="anchored"><a href="#val-routes" class="anchor"></a><code><span><span class="keyword">val</span> routes : <span><span><a href="#type-method'">method'</a> list</span> <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-request_target">request_target</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'b</span> <a href="#type-routes">routes</a></span></span></code></div><div class="spec-doc"><p><code>routes methods request_target route_handler</code> is a product of <code>methods X request_target X route_handler</code>. This is equivalent to calling <a href="#val-route"><code>route</code></a> like so:</p><pre><code>List.map (fun m -&gt; route ~method:m request_target route_handler) [meth1; meth2; meth3]</code></pre></div></div><div class="odoc-spec"><div class="spec value" id="val-router" class="anchored"><a href="#val-router" class="anchor"></a><code><span><span class="keyword">val</span> router : <span><span><span><span class="type-var">'a</span> <a href="#type-routes">routes</a></span> list</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <a href="#type-router">router</a></span></span></code></div><div class="spec-doc"><p><code>router routes</code> is a <a href="#type-router"><code>router</code></a> that is composed of <code>routes</code>.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-match'" class="anchored"><a href="#val-match'" class="anchor"></a><code><span><span class="keyword">val</span> match' : <span><a href="#type-method'">method'</a> <span class="arrow">&#45;&gt;</span></span> <span>string <span class="arrow">&#45;&gt;</span></span> <span><span><span class="type-var">'a</span> <a href="#type-router">router</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> option</span></span></code></div><div class="spec-doc"><p><code>match' method' request_target router</code> is <code>Some a</code> if <code>method'</code> and <code>request_target</code> together matches one of the routes defined in <code>router</code>. Otherwise it is None. The value <code>Some a</code> is returned by the <i>route handler</i> of the matched <i>route</i>.</p><p>The routes are matched based on the lexical order of the routes. This means they are matched from <i>top to bottom</i>, <i>left to right</i> and to the <i>longest match</i>. See <a href="#val-pp"><code>pp</code></a> to visualize the router and the route matching mechanism.</p></div></div><h2 id="http-method"><a href="#http-method" class="anchor"></a>HTTP Method</h2><div class="odoc-spec"><div class="spec value" id="val-method_equal" class="anchored"><a href="#val-method_equal" class="anchor"></a><code><span><span class="keyword">val</span> method_equal : <span><a href="#type-method'">method'</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="#type-method'">method'</a> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>method_equal m1 m2</code> is <code>true</code> if <code>m1</code> and <code>m2</code> is the same value. Otherwise it is <code>false</code>.</p><p><i>Note</i> if both <code>m1</code> and <code>m2</code> are <code>`Method m</code> then the string comparison is case insensitive.</p><pre><code>Wtr.method_equal `GET `GET = true;;
Wtr.method_equal `POST `GET = false;;
Wtr.method_equal (`Method &quot;meth&quot;) (`Method &quot;METH&quot;) = true</code></pre></div></div><div class="odoc-spec"><div class="spec value" id="val-method'" class="anchored"><a href="#val-method'" class="anchor"></a><code><span><span class="keyword">val</span> method' : <span>string <span class="arrow">&#45;&gt;</span></span> <a href="#type-method'">method'</a></span></code></div><div class="spec-doc"><p><code>method' m</code> is <a href="#type-method'"><code>method'</code></a> where string value <code>m</code> is converted to <a href="#type-method'"><code>method'</code></a> as follows:</p><ul><li><code>&quot;GET&quot;</code> to <code>`GET</code></li><li><code>&quot;HEAD&quot;</code> to <code>`HEAD</code></li><li><code>&quot;POST&quot;</code> to <code>`POST</code></li><li><code>&quot;PUT&quot;</code> to <code>`PUT</code></li><li><code>&quot;DELETE&quot;</code> to <code>`DELETE</code></li><li><code>&quot;CONNECT&quot;</code> to <code>`CONNECT</code></li><li><code>&quot;OPTIONS&quot;</code> to <code>`OPTIONS</code></li><li><code>&quot;TRACE&quot;</code> to <code>`TRACE</code></li><li>Any other value <code>m</code> to <code>`Method m</code></li></ul><p><i>Note</i> String comparison is case insensitive.</p><pre><code>Wtr.method' &quot;GET&quot; = `GET;;
Wtr.method' &quot;get&quot; = `GET;;
Wtr.method' &quot;method&quot; = `Method &quot;method&quot;</code></pre></div></div><h2 id="pp"><a href="#pp" class="anchor"></a>Pretty Printers and Debugging</h2><p>Pretty printers can be useful during debugging of routing and/or route related issues.</p><div class="odoc-spec"><div class="spec value" id="val-pp_request_target" class="anchored"><a href="#val-pp_request_target" class="anchor"></a><code><span><span class="keyword">val</span> pp_request_target : <span><span class="xref-unresolved">Stdlib</span>.Format.formatter <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-request_target">request_target</a></span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>pp_request_target fmt target</code> pretty prints <code>target</code> onto <code>fmt</code>.</p><p><b>Path components</b></p><p><i>arg components</i> - name of the combinator prefixed by <code>:</code> token, eg. <a href="#val-int"><code>int</code></a> is printed as <code>:int</code>, <a href="#val-float"><code>float</code></a> is printed as <code>:float</code>. <a href="#path_arg">Path Arg Components</a></p><p><i><a href="#val-parg"><code>parg</code></a> component</i> - name of the arg followed by <code>:</code> token e.g. <code>parg Fruit.t</code> is printed as <code>:Fruit</code>.</p><p><i><a href="#val-exact"><code>exact</code></a> component</i> - the string literal given to <code>exact</code> is printed, e.g. <code>exact &quot;hello&quot;</code> is printed as <code>hello</code>.</p><p><i><a href="#val-slash"><code>slash</code></a></i> - printed as <code>/</code></p><p><i><a href="#val-rest"><code>rest</code></a></i> - printed as <code>**</code></p><p>A <code>/</code> character is inserted in between the components when printing a sequence of <i>path components</i>, e.g.</p><pre><code>let p = Wtr.(exact &quot;hello&quot; / int / bool /. rest) </code></pre><p>is printed as <code>/hello/:int/:bool/**</code>.</p><p><b>Query components</b></p><p><i>arg components</i> - query arg components are printed similar to <i>path arg components</i>; with the addition of <code>name</code> token, e.g. <code>qint &quot;h&quot;</code> is printed as <code>h=:int</code>, <code>qbool &quot;b&quot;</code> is printed as <code>b=:bool</code>.</p><p><i>qarg component</i> - is printed similar to <a href="#val-parg"><code>parg</code></a>; with the addition of field name, e.g. <code>qarg (&quot;h&quot;, Fruit.t)</code> is printed as <code>h=:fruit</code>.</p><p><i>qexact component</i> - is printed similar to <a href="#val-exact"><code>exact</code></a>; with the addition of field name, e.g. <code>qexact (&quot;h&quot;, &quot;hello&quot;)</code> is printed as <code>h=hello</code>.</p><p>A <code>&amp;</code> character is inserted in between the components when printing a sequence of <i>query components</i>. Additionally, a <code>?</code> character is printed in between <i>path components</i> and <i>query components</i>, e.g.</p><pre><code>let target1 =
  Wtr.(
    exact &quot;hello&quot;
    / bool
    / int
    / string
    /? qexact (&quot;h&quot;, &quot;hello&quot;)
    /&amp; qbool &quot;b&quot;
    /?. ())
in
Wtr.pp_request_target Format.std_formatter target1</code></pre><p>will print the following: <code>/hello/:bool/:int/:string?h=hello&amp;b=:bool</code></p></div></div><div class="odoc-spec"><div class="spec value" id="val-pp_method" class="anchored"><a href="#val-pp_method" class="anchor"></a><code><span><span class="keyword">val</span> pp_method : <span><span class="xref-unresolved">Stdlib</span>.Format.formatter <span class="arrow">&#45;&gt;</span></span> <span><a href="#type-method'">method'</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>pp_method fmt m</code> pretty prints <code>m</code> onto <code>fmt</code>. It does the inverse of <a href="#val-method'"><code>method'</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value" id="val-pp_route" class="anchored"><a href="#val-pp_route" class="anchor"></a><code><span><span class="keyword">val</span> pp_route : <span><span class="xref-unresolved">Stdlib</span>.Format.formatter <span class="arrow">&#45;&gt;</span></span> <span><span><span class="type-var">'b</span> <a href="#type-route">route</a></span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>pp_route fmt route</code> first pretty prints the <code>method</code> followed by the <code>request_target</code> of a <code>route</code>, e.g.</p><pre><code>let route1 =
  Wtr.(route ~method':`GET (exact &quot;hello&quot; / bool /. slash)) (fun _ -&gt; ())</code></pre><p><code>route1</code> is pretty printed as <code>GET/hello/:bool/</code></p><p>The <code>route2</code> contains both path and query components:</p><pre><code>let route2 =
  Wtr.(
    route ~method':`GET
      (exact &quot;hello&quot; / bool /? qexact (&quot;h&quot;, &quot;hello&quot;) /&amp; qbool &quot;b&quot; /?. ()))
    (fun _ _ -&gt; ())
in
Wtr.pp_route Format.std_formatter route2</code></pre><p>It is printed as follows: <code>GET/hello/:bool?h=hello?b=:bool</code></p></div></div><div class="odoc-spec"><div class="spec value" id="val-pp" class="anchored"><a href="#val-pp" class="anchor"></a><code><span><span class="keyword">val</span> pp : <span><span class="xref-unresolved">Stdlib</span>.Format.formatter <span class="arrow">&#45;&gt;</span></span> <span><span><span class="type-var">'a</span> <a href="#type-router">router</a></span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>pp fmt router</code> pretty prints <code>router</code> onto <code>fmt</code>. It follows the same mechanism as <a href="#val-pp_route"><code>pp_route</code></a> and <a href="#val-pp_request_target"><code>pp_request_target</code></a>. However, unlike the two functions, it prints each component - <i>path</i> and <i>query</i> - onto a separate line. The component in each line is indented.</p><p>The indentation and line printing is meant to convey the order of a route component evaluation. The evaluation is from top to bottom and left to right. This gives some indication of how the routes are evaluated and thus can be used to aid in debugging routing issues.</p><p>For example, <code>router1</code> which is defined as:</p><pre><code>let router1 =
  Wtr.(
    router'
      [ routes
          [`GET; `POST; `HEAD; `DELETE]
          (exact &quot;home&quot; / exact &quot;about&quot; /. slash)
          about_page
      ; routes
          [`GET]
          (exact &quot;contact&quot; / string / int /. pend)
          contact_page
      ; routes
          [`GET]
          (exact &quot;product&quot; / string /? qint &quot;section&quot; /&amp; qbool &quot;q&quot; /?. ())
          product1
      ; routes
          [`GET]
          ( exact &quot;product&quot;
          / string
          /? qint &quot;section&quot;
          /&amp; qexact (&quot;q1&quot;, &quot;yes&quot;)
          /?. () )
          product2
      ; routes [`GET] (exact &quot;fruit&quot; / parg Fruit.t /. pend) fruit_page ])</code></pre><p>is pretty printed as below:</p><pre>GET
  /home
    /about
      /
  /contact
    /:string
      /:int
  /product
    /:string
      ?section=:int
        &amp;q=:bool
        &amp;q1=yes
  /fruit
    /:Fruit
POST
  /home
    /about
      /
HEAD
  /home
    /about
      /
DELETE
  /home
    /about
      /</pre></div></div><h2 id="references"><a href="#references" class="anchor"></a>References</h2><ul><li><a href="https://datatracker.ietf.org/doc/html/rfc7230#section-5.3">RFC 7230 - HTTP Request Target</a></li><li><a href="https://datatracker.ietf.org/doc/html/rfc7231#section-4">RFC 7231 - HTTP Methods</a></li></ul></div></body></html>