Compare commits

...

6 commits

Author SHA1 Message Date
Domen Kožar
0c48e188f3
Delete CNAME 2022-06-09 23:36:30 +01:00
Domen Kožar
4d347edd0e
Create CNAME 2022-06-09 23:31:29 +01:00
Alp Mestanogullari
2c30a11e0a Built from 501dafaeba 2014-12-08 12:28:32 +01:00
Alp Mestanogullari
63563ca665 Built from 55eb020d10 2014-12-08 10:57:31 +01:00
Alp Mestanogullari
84b9ea271e Built from 1defab0d2f 2014-12-02 18:34:48 +01:00
Alp Mestanogullari
cec89c1cd0 Built from d9d94e6f4e 2014-12-02 17:42:06 +01:00
97 changed files with 3629 additions and 2052 deletions
.ghci.travis.ymlLICENSEServant-API-Alternative.htmlServant-API-Capture.htmlServant-API-Delete.htmlServant-API-Get.htmlServant-API-Header.htmlServant-API-Post.htmlServant-API-Put.htmlServant-API-QueryParam.htmlServant-API-Raw.htmlServant-API-ReqBody.htmlServant-API-Sub.htmlServant-API.htmlServant-Common-Text.htmlServant-QQ.htmlServant-Server.htmlServant-Utils-Links.htmlServant-Utils-StaticFiles.htmlServant.htmlSetup.hsdoc-index.html
example
frames.htmlhaddock-util.jshslogo-16.pngindex-frames.htmlindex.htmlmini_Servant-API-Alternative.htmlmini_Servant-API-Capture.htmlmini_Servant-API-Delete.htmlmini_Servant-API-Get.htmlmini_Servant-API-Header.htmlmini_Servant-API-Post.htmlmini_Servant-API-Put.htmlmini_Servant-API-QueryParam.htmlmini_Servant-API-Raw.htmlmini_Servant-API-ReqBody.htmlmini_Servant-API-Sub.htmlmini_Servant-API.htmlmini_Servant-Common-Text.htmlmini_Servant-QQ.htmlmini_Servant-Server.htmlmini_Servant-Utils-Links.htmlmini_Servant-Utils-StaticFiles.htmlmini_Servant.htmlminus.gifocean.cssplus.gifservant.cabalservant.haddockservant.txt
src
synopsis.png
test

1
.ghci
View file

@ -1 +0,0 @@
:set -itest -isrc -packagehspec2

View file

@ -1,12 +0,0 @@
language: haskell
notifications:
irc:
channels:
- "irc.freenode.org#servant"
template:
- "%{repository}#%{build_number} - %{commit} on %{branch} by %{author}: %{message}"
- "Build details: %{build_url} - Change view: %{compare_url}"
skip_join: true
on_success: change
on_failure: always

30
LICENSE
View file

@ -1,30 +0,0 @@
Copyright (c) 2014, Zalora South East Asia Pte Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Zalora South East Asia Pte Ltd nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,13 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Alternative</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-API-Alternative.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-API-Alternative.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.API.Alternative</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">data</span> a <a href="#t::-60--124--62-">:&lt;|&gt;</a> b = a <a href="#v::-60--124--62-">:&lt;|&gt;</a> b</li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">data</span> a <a name="t::-60--124--62-" class="def">:&lt;|&gt;</a> b <span class="fixity">infixr 8</span><span class="rightedge"></span> <a href="src/Servant-API-Alternative.html#%3A%3C%7C%3E" class="link">Source</a></p><div class="doc"><p>Union of two APIs, first takes precedence in case of overlap.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; Get [Book] -- GET /books
:&lt;|&gt; &quot;books&quot; :&gt; ReqBody Book :&gt; Post Book -- POST /books</pre></div><div class="subs constructors"><p class="caption">Constructors</p><table><tr><td class="src">a <a name="v::-60--124--62-" class="def">:&lt;|&gt;</a> b <span class="fixity">infixr 8</span><span class="rightedge"></span></td><td class="doc empty">&nbsp;</td></tr></table></div><div class="subs instances"><p id="control.i::-60--124--62-" class="caption collapser" onclick="toggleSection('i::-60--124--62-')">Instances</p><div id="section.i::-60--124--62-" class="show"><table><tr><td class="src">(<a href="Servant-Server.html#t:HasServer">HasServer</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> b) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Alternative.html#t::-60--124--62-">(:&lt;|&gt;)</a> a b)</td><td class="doc"><p>A server for <code>a <code><a href="Servant-API-Alternative.html#t::-60--124--62-">:&lt;|&gt;</a></code> b</code> first tries to match the request again the route
represented by <code>a</code> and if it fails tries <code>b</code>. You must provide a request
handler for each route.</p><pre>type MyApi = &quot;books&quot; :&gt; Get [Book] -- GET /books
:&lt;|&gt; &quot;books&quot; :&gt; ReqBody Book :&gt; Post Book -- POST /books
server :: Server MyApi
server = listAllBooks :&lt;|&gt; postBook
where listAllBooks = ...
postBook book = ...</pre></td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Alternative.html#t::-60--124--62-">(:&lt;|&gt;)</a> a b) = <a href="Servant-API-Alternative.html#t::-60--124--62-">(:&lt;|&gt;)</a> (<a href="Servant-Server.html#t:Server">Server</a> a) (<a href="Servant-Server.html#t:Server">Server</a> b)</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

15
Servant-API-Capture.html Normal file
View file

@ -0,0 +1,15 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Capture</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-API-Capture.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-API-Capture.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.API.Capture</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">data</span> <a href="#t:Capture">Capture</a> sym a</li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:Capture" class="def">Capture</a> sym a <a href="src/Servant-API-Capture.html#Capture" class="link">Source</a></p><div class="doc"><p>Capture a value from the request path under a certain type <code>a</code>.</p><p>Example:</p><pre> -- GET /books/:isbn
type MyApi = &quot;books&quot; :&gt; Capture &quot;isbn&quot; Text :&gt; Get Book</pre></div><div class="subs instances"><p id="control.i:Capture" class="caption collapser" onclick="toggleSection('i:Capture')">Instances</p><div id="section.i:Capture" class="show"><table><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> capture, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-Capture.html#t:Capture">Capture</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * capture a) sublayout)</td><td class="doc"><p>If you use <code><a href="Servant-API-Capture.html#t:Capture">Capture</a></code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of the type specified by the <code><a href="Servant-API-Capture.html#t:Capture">Capture</a></code>.
This lets servant worry about getting it from the URL and turning
it into a value of the type you specify.</p><p>You can control how it'll be converted from <code><a href="https://hackage.haskell.org/package/text-1.2.0.0/docs/Data-Text.html#t:Text">Text</a></code> to your type
by simply providing an instance of <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> for your type.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; Capture &quot;isbn&quot; Text :&gt; Get Book
server :: Server MyApi
server = getBook
where getBook :: Text -&gt; EitherT (Int, String) IO Book
getBook isbn = ...</pre></td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-Capture.html#t:Capture">Capture</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * capture a) sublayout) = a -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

13
Servant-API-Delete.html Normal file
View file

@ -0,0 +1,13 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Delete</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-API-Delete.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-API-Delete.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.API.Delete</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">data</span> <a href="#t:Delete">Delete</a></li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:Delete" class="def">Delete</a> <a href="src/Servant-API-Delete.html#Delete" class="link">Source</a></p><div class="doc"><p>Combinator for DELETE requests.</p><p>Example:</p><pre> -- DELETE /books/:isbn
type MyApi = &quot;books&quot; :&gt; Capture &quot;isbn&quot; Text :&gt; Delete</pre></div><div class="subs instances"><p id="control.i:Delete" class="caption collapser" onclick="toggleSection('i:Delete')">Instances</p><div id="section.i:Delete" class="show"><table><tr><td class="src"><a href="Servant-Server.html#t:HasServer">HasServer</a> <a href="Servant-API-Delete.html#t:Delete">Delete</a></td><td class="doc"><p>If you have a <code><a href="Servant-API-Delete.html#t:Delete">Delete</a></code> endpoint in your API,
the handler for this endpoint is meant to delete
a resource.</p><p>The code of the handler will, just like
for <code><a href="Servant-API-Get.html#t:Get">Get</a></code>, <code><a href="Servant-API-Post.html#t:Post">Post</a></code> and
<code><a href="Servant-API-Put.html#t:Put">Put</a></code>, run in <code>EitherT (Int, String) IO ()</code>.
The <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a></code> represents the status code and the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a></code> a message
to be returned. You can use <code><a href="https://hackage.haskell.org/package/either-4.3.2/docs/Control-Monad-Trans-Either.html#v:left">left</a></code> to
painlessly error out if the conditions for a successful deletion
are not met.</p></td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Typeable-Internal.html#t:Typeable">Typeable</a> * <a href="Servant-API-Delete.html#t:Delete">Delete</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> <a href="Servant-API-Delete.html#t:Delete">Delete</a> = <a href="https://hackage.haskell.org/package/either-4.3.2/docs/Control-Monad-Trans-Either.html#t:EitherT">EitherT</a> (<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a>, <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a>) <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/System-IO.html#t:IO">IO</a> ()</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

12
Servant-API-Get.html Normal file
View file

@ -0,0 +1,12 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Get</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-API-Get.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-API-Get.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.API.Get</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">data</span> <a href="#t:Get">Get</a> a</li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:Get" class="def">Get</a> a <a href="src/Servant-API-Get.html#Get" class="link">Source</a></p><div class="doc"><p>Endpoint for simple GET requests. Serves the result as JSON.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; Get [Book]</pre></div><div class="subs instances"><p id="control.i:Get" class="caption collapser" onclick="toggleSection('i:Get')">Instances</p><div id="section.i:Get" class="show"><table><tr><td class="src"><a href="Servant-Utils-Links.html#t:VLinkHelper">VLinkHelper</a> * (<a href="Servant-API-Get.html#t:Get">Get</a> x)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a> result =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Get.html#t:Get">Get</a> result)</td><td class="doc"><p>When implementing the handler for a <code><a href="Servant-API-Get.html#t:Get">Get</a></code> endpoint,
just like for <code><a href="Servant-API-Delete.html#t:Delete">Delete</a></code>, <code><a href="Servant-API-Post.html#t:Post">Post</a></code>
and <code><a href="Servant-API-Put.html#t:Put">Put</a></code>, the handler code runs in the
<code>EitherT (Int, String) IO</code> monad, where the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a></code> represents
the status code and the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a></code> a message, returned in case of
failure. You can quite handily use <code><a href="Control-Monad-Trans-EitherT.html#v:left">left</a></code>
to quickly fail if some conditions are not met.</p><p>If successfully returning a value, we just require that its type has
a <code><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a></code> instance and servant takes care of encoding it for you,
yielding status code 200 along the way.</p></td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Typeable-Internal.html#t:Typeable">Typeable</a> (* -&gt; *) <a href="Servant-API-Get.html#t:Get">Get</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Get.html#t:Get">Get</a> result) = <a href="https://hackage.haskell.org/package/either-4.3.2/docs/Control-Monad-Trans-Either.html#t:EitherT">EitherT</a> (<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a>, <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a>) <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/System-IO.html#t:IO">IO</a> result</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

21
Servant-API-Header.html Normal file
View file

@ -0,0 +1,21 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Header</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-API-Header.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-API-Header.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.API.Header</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">data</span> <a href="#t:Header">Header</a> sym a</li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:Header" class="def">Header</a> sym a <a href="src/Servant-API-Header.html#Header" class="link">Source</a></p><div class="doc"><p>Extract the given header's value as a value of type <code>a</code>.</p><p>Example:</p><pre>newtype Referer = Referer Text
deriving (Eq, Show, FromText, ToText)
-- GET /view-my-referer
type MyApi = &quot;view-my-referer&quot; :&gt; Header &quot;from&quot; Referer :&gt; Get Referer</pre></div><div class="subs instances"><p id="control.i:Header" class="caption collapser" onclick="toggleSection('i:Header')">Instances</p><div id="section.i:Header" class="show"><table><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-Header.html#t:Header">Header</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout)</td><td class="doc"><p>If you use <code><a href="Servant-API-Header.html#t:Header">Header</a></code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of the type specified by <code><a href="Servant-API-Header.html#t:Header">Header</a></code>.
This lets servant worry about extracting it from the request and turning
it into a value of the type you specify.</p><p>All it asks is for a <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> instance.</p><p>Example:</p><pre>newtype Referer = Referer Text
deriving (Eq, Show, FromText, ToText)
-- GET /view-my-referer
type MyApi = &quot;view-my-referer&quot; :&gt; Header &quot;Referer&quot; Referer :&gt; Get Referer
server :: Server MyApi
server = viewReferer
where viewReferer :: Referer -&gt; EitherT (Int, String) IO referer
viewReferer referer = return referer</pre></td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-Header.html#t:Header">Header</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout) = <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a> a -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

17
Servant-API-Post.html Normal file
View file

@ -0,0 +1,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Post</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-API-Post.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-API-Post.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.API.Post</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">data</span> <a href="#t:Post">Post</a> a</li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:Post" class="def">Post</a> a <a href="src/Servant-API-Post.html#Post" class="link">Source</a></p><div class="doc"><p>Endpoint for POST requests. The type variable represents the type of the
response body (not the request body, use <code><a href="Servant-API-RQBody.html#t:RQBody">RQBody</a></code> for
that).</p><p>Example:</p><pre> -- POST /books
-- with a JSON encoded Book as the request body
-- returning the just-created Book
type MyApi = &quot;books&quot; :&gt; ReqBody Book :&gt; Post Book</pre></div><div class="subs instances"><p id="control.i:Post" class="caption collapser" onclick="toggleSection('i:Post')">Instances</p><div id="section.i:Post" class="show"><table><tr><td class="src"><a href="Servant-Utils-Links.html#t:VLinkHelper">VLinkHelper</a> * (<a href="Servant-API-Post.html#t:Post">Post</a> x)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a> a =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Post.html#t:Post">Post</a> a)</td><td class="doc"><p>When implementing the handler for a <code><a href="Servant-API-Post.html#t:Post">Post</a></code> endpoint,
just like for <code><a href="Servant-API-Delete.html#t:Delete">Delete</a></code>, <code><a href="Servant-API-Get.html#t:Get">Get</a></code>
and <code><a href="Servant-API-Put.html#t:Put">Put</a></code>, the handler code runs in the
<code>EitherT (Int, String) IO</code> monad, where the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a></code> represents
the status code and the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a></code> a message, returned in case of
failure. You can quite handily use <code><a href="Control-Monad-Trans-EitherT.html#v:left">left</a></code>
to quickly fail if some conditions are not met.</p><p>If successfully returning a value, we just require that its type has
a <code><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a></code> instance and servant takes care of encoding it for you,
yielding status code 201 along the way.</p></td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Typeable-Internal.html#t:Typeable">Typeable</a> (* -&gt; *) <a href="Servant-API-Post.html#t:Post">Post</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Post.html#t:Post">Post</a> a) = <a href="https://hackage.haskell.org/package/either-4.3.2/docs/Control-Monad-Trans-Either.html#t:EitherT">EitherT</a> (<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a>, <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a>) <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/System-IO.html#t:IO">IO</a> a</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

15
Servant-API-Put.html Normal file
View file

@ -0,0 +1,15 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Put</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-API-Put.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-API-Put.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.API.Put</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">data</span> <a href="#t:Put">Put</a> a</li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:Put" class="def">Put</a> a <a href="src/Servant-API-Put.html#Put" class="link">Source</a></p><div class="doc"><p>Endpoint for PUT requests, usually used to update a ressource.
The type <code>a</code> is the type of the response body that's returned.</p><p>Example:</p><pre>-- PUT /books/:isbn
-- with a Book as request body, returning the updated Book
type MyApi = &quot;books&quot; :&gt; Capture &quot;isbn&quot; Text :&gt; ReqBody Book :&gt; Put Book</pre></div><div class="subs instances"><p id="control.i:Put" class="caption collapser" onclick="toggleSection('i:Put')">Instances</p><div id="section.i:Put" class="show"><table><tr><td class="src"><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a> a =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Put.html#t:Put">Put</a> a)</td><td class="doc"><p>When implementing the handler for a <code><a href="Servant-API-Put.html#t:Put">Put</a></code> endpoint,
just like for <code><a href="Servant-API-Delete.html#t:Delete">Delete</a></code>, <code><a href="Servant-API-Get.html#t:Get">Get</a></code>
and <code><a href="Servant-API-Post.html#t:Post">Post</a></code>, the handler code runs in the
<code>EitherT (Int, String) IO</code> monad, where the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a></code> represents
the status code and the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a></code> a message, returned in case of
failure. You can quite handily use <code><a href="Control-Monad-Trans-EitherT.html#v:left">left</a></code>
to quickly fail if some conditions are not met.</p><p>If successfully returning a value, we just require that its type has
a <code><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a></code> instance and servant takes care of encoding it for you,
yielding status code 200 along the way.</p></td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Typeable-Internal.html#t:Typeable">Typeable</a> (* -&gt; *) <a href="Servant-API-Put.html#t:Put">Put</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Put.html#t:Put">Put</a> a) = <a href="https://hackage.haskell.org/package/either-4.3.2/docs/Control-Monad-Trans-Either.html#t:EitherT">EitherT</a> (<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a>, <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a>) <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/System-IO.html#t:IO">IO</a> a</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

View file

@ -0,0 +1,45 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.QueryParam</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-API-QueryParam.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-API-QueryParam.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.API.QueryParam</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">data</span> <a href="#t:QueryParam">QueryParam</a> sym a</li><li class="src short"><span class="keyword">data</span> <a href="#t:QueryParams">QueryParams</a> sym a</li><li class="src short"><span class="keyword">data</span> <a href="#t:QueryFlag">QueryFlag</a> sym</li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:QueryParam" class="def">QueryParam</a> sym a <a href="src/Servant-API-QueryParam.html#QueryParam" class="link">Source</a></p><div class="doc"><p>Lookup the value associated to the <code>sym</code> query string parameter
and try to extract it as a value of type <code>a</code>.</p><p>Example:</p><pre>-- /books?author=&lt;author name&gt;
type MyApi = &quot;books&quot; :&gt; QueryParam &quot;author&quot; Text :&gt; Get [Book]</pre></div><div class="subs instances"><p id="control.i:QueryParam" class="caption collapser" onclick="toggleSection('i:QueryParam')">Instances</p><div id="section.i:QueryParam" class="show"><table><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryParam">QueryParam</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout)</td><td class="doc"><p>If you use <code><code><a href="Servant-API-QueryParam.html#t:QueryParam">QueryParam</a></code> &quot;author&quot; Text</code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of type <code><code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a></code> <code>Text</code></code>.</p><p>This lets servant worry about looking it up in the query string
and turning it into a value of the type you specify, enclosed
in <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a></code>, because it may not be there and servant would then
hand you <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#v:Nothing">Nothing</a></code>.</p><p>You can control how it'll be converted from <code>Text</code> to your type
by simply providing an instance of <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> for your type.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; QueryParam &quot;author&quot; Text :&gt; Get [Book]
server :: Server MyApi
server = getBooksBy
where getBooksBy :: Maybe Text -&gt; EitherT (Int, String) IO [Book]
getBooksBy Nothing = ...return all books...
getBooksBy (Just author) = ...return books by the given author...</pre></td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryParam">QueryParam</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout) = <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a> a -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:QueryParams" class="def">QueryParams</a> sym a <a href="src/Servant-API-QueryParam.html#QueryParams" class="link">Source</a></p><div class="doc"><p>Lookup the values associated to the <code>sym</code> query string parameter
and try to extract it as a value of type <code>[a]</code>. This is typically
meant to support query string parameters of the form
<code>param[]=val1&amp;param[]=val2</code> and so on. Note that servant doesn't actually
require the <code>[]</code>s and will fetch the values just fine with
<code>param=val1&amp;param=val2</code>, too.</p><p>Example:</p><pre>-- /books?authors[]=&lt;author1&gt;&amp;authors[]=&lt;author2&gt;&amp;...
type MyApi = &quot;books&quot; :&gt; QueryParams &quot;authors&quot; Text :&gt; Get [Book]</pre></div><div class="subs instances"><p id="control.i:QueryParams" class="caption collapser" onclick="toggleSection('i:QueryParams')">Instances</p><div id="section.i:QueryParams" class="show"><table><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryParams">QueryParams</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout)</td><td class="doc"><p>If you use <code><code><a href="Servant-API-QueryParam.html#t:QueryParams">QueryParams</a></code> &quot;authors&quot; Text</code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of type <code>[<code>Text</code>]</code>.</p><p>This lets servant worry about looking up 0 or more values in the query string
associated to <code>authors</code> and turning each of them into a value of
the type you specify.</p><p>You can control how the individual values are converted from <code>Text</code> to your type
by simply providing an instance of <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> for your type.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; QueryParams &quot;authors&quot; Text :&gt; Get [Book]
server :: Server MyApi
server = getBooksBy
where getBooksBy :: [Text] -&gt; EitherT (Int, String) IO [Book]
getBooksBy authors = ...return all books by these authors...</pre></td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryParams">QueryParams</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout) = [a] -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:QueryFlag" class="def">QueryFlag</a> sym <a href="src/Servant-API-QueryParam.html#QueryFlag" class="link">Source</a></p><div class="doc"><p>Lookup a potentially value-less query string parameter
with boolean semantics. If the param <code>sym</code> is there without any value,
or if it's there with value &quot;true&quot; or &quot;1&quot;, it's interpreted as <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Bool.html#v:True">True</a></code>.
Otherwise, it's interpreted as <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Bool.html#v:False">False</a></code>.</p><p>Example:</p><pre>-- /books?published
type MyApi = &quot;books&quot; :&gt; QueryFlag &quot;published&quot; :&gt; Get [Book]</pre></div><div class="subs instances"><p id="control.i:QueryFlag" class="caption collapser" onclick="toggleSection('i:QueryFlag')">Instances</p><div id="section.i:QueryFlag" class="show"><table><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryFlag">QueryFlag</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> sym) sublayout)</td><td class="doc"><p>If you use <code><code><a href="Servant-API-QueryParam.html#t:QueryFlag">QueryFlag</a></code> &quot;published&quot;</code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of type <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Bool.html#t:Bool">Bool</a></code>.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; QueryFlag &quot;published&quot; :&gt; Get [Book]
server :: Server MyApi
server = getBooks
where getBooks :: Bool -&gt; EitherT (Int, String) IO [Book]
getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument...</pre></td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryFlag">QueryFlag</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> sym) sublayout) = <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Bool.html#t:Bool">Bool</a> -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

11
Servant-API-Raw.html Normal file
View file

@ -0,0 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Raw</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-API-Raw.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-API-Raw.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.API.Raw</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">data</span> <a href="#t:Raw">Raw</a></li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:Raw" class="def">Raw</a> <a href="src/Servant-API-Raw.html#Raw" class="link">Source</a></p><div class="doc"><p>Endpoint for plugging in your own Wai <code><a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Application">Application</a></code>s.</p><p>The given <code><a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Application">Application</a></code> will get the request as received by the server, potentially with
a modified (stripped) <code><a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#v:pathInfo">pathInfo</a></code> if the <code><a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Application">Application</a></code> is being routed with <code><a href="Servant-API-Sub.html#t::-62-">:&gt;</a></code>.</p><p>In addition to just letting you plug in your existing WAI <code><a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Application">Application</a></code>s,
this can also be used with <code><a href="Servant-Utils-StaticFiles.html#v:serveDirectory">serveDirectory</a></code> to serve
static files stored in a particular directory on your filesystem, or to serve
your API's documentation with <code><a href="Servant-Utils-StaticFiles.html#v:serveDocumentation">serveDocumentation</a></code>.</p></div><div class="subs instances"><p id="control.i:Raw" class="caption collapser" onclick="toggleSection('i:Raw')">Instances</p><div id="section.i:Raw" class="show"><table><tr><td class="src"><a href="Servant-Server.html#t:HasServer">HasServer</a> <a href="Servant-API-Raw.html#t:Raw">Raw</a></td><td class="doc"><p>Just pass the request to the underlying application and serve its response.</p><p>Example:</p><pre>type MyApi = &quot;images&quot; :&gt; Raw
server :: Server MyApi
server = serveDirectory &quot;/var/www/images&quot;</pre></td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> <a href="Servant-API-Raw.html#t:Raw">Raw</a> = <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Application">Application</a></td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

14
Servant-API-ReqBody.html Normal file
View file

@ -0,0 +1,14 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.ReqBody</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-API-ReqBody.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-API-ReqBody.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.API.ReqBody</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">data</span> <a href="#t:ReqBody">ReqBody</a> a</li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:ReqBody" class="def">ReqBody</a> a <a href="src/Servant-API-ReqBody.html#ReqBody" class="link">Source</a></p><div class="doc"><p>Extract the request body as a value of type <code>a</code>.</p><p>Example:</p><pre> -- POST /books
type MyApi = &quot;books&quot; :&gt; ReqBody Book :&gt; Post Book</pre></div><div class="subs instances"><p id="control.i:ReqBody" class="caption collapser" onclick="toggleSection('i:ReqBody')">Instances</p><div id="section.i:ReqBody" class="show"><table><tr><td class="src">(<a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:FromJSON">FromJSON</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-ReqBody.html#t:ReqBody">ReqBody</a> * a) sublayout)</td><td class="doc"><p>If you use <code><a href="Servant-API-ReqBody.html#t:ReqBody">ReqBody</a></code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of the type specified by <code><a href="Servant-API-ReqBody.html#t:ReqBody">ReqBody</a></code>.
This lets servant worry about extracting it from the request and turning
it into a value of the type you specify.</p><p>All it asks is for a <code><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:FromJSON">FromJSON</a></code> instance.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; ReqBody Book :&gt; Post Book
server :: Server MyApi
server = postBook
where postBook :: Book -&gt; EitherT (Int, String) IO Book
postBook book = ...insert into your db...</pre></td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-ReqBody.html#t:ReqBody">ReqBody</a> * a) sublayout) = a -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

69
Servant-API-Sub.html Normal file
View file

@ -0,0 +1,69 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Sub</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-API-Sub.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-API-Sub.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.API.Sub</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">data</span> path <a href="#t::-62-">:&gt;</a> a = (<a href="Servant.html#t:Proxy">Proxy</a> path) <a href="#v::-62-">:&gt;</a> a</li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">data</span> path <a name="t::-62-" class="def">:&gt;</a> a <span class="fixity">infixr 9</span><span class="rightedge"></span> <a href="src/Servant-API-Sub.html#%3A%3E" class="link">Source</a></p><div class="doc"><p>The contained API (second argument) can be found under <code>(&quot;/&quot; ++ path)</code>
(path being the first argument).</p><p>Example:</p><pre>-- GET /hello/world
-- returning a JSON encoded World value
type MyApi = &quot;hello&quot; :&gt; &quot;world&quot; :&gt; Get World</pre></div><div class="subs constructors"><p class="caption">Constructors</p><table><tr><td class="src">(<a href="Servant.html#t:Proxy">Proxy</a> path) <a name="v::-62-" class="def">:&gt;</a> a <span class="fixity">infixr 9</span><span class="rightedge"></span></td><td class="doc empty">&nbsp;</td></tr></table></div><div class="subs instances"><p id="control.i::-62-" class="caption collapser" onclick="toggleSection('i::-62-')">Instances</p><div id="section.i::-62-" class="show"><table><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> s, <a href="Servant-Utils-Links.html#t:VLinkHelper">VLinkHelper</a> * e) =&gt; <a href="Servant-Utils-Links.html#t:VLinkHelper">VLinkHelper</a> * (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> s e)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> capture, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-Capture.html#t:Capture">Capture</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * capture a) sublayout)</td><td class="doc"><p>If you use <code><a href="Servant-API-Capture.html#t:Capture">Capture</a></code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of the type specified by the <code><a href="Servant-API-Capture.html#t:Capture">Capture</a></code>.
This lets servant worry about getting it from the URL and turning
it into a value of the type you specify.</p><p>You can control how it'll be converted from <code><a href="https://hackage.haskell.org/package/text-1.2.0.0/docs/Data-Text.html#t:Text">Text</a></code> to your type
by simply providing an instance of <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> for your type.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; Capture &quot;isbn&quot; Text :&gt; Get Book
server :: Server MyApi
server = getBook
where getBook :: Text -&gt; EitherT (Int, String) IO Book
getBook isbn = ...</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-Header.html#t:Header">Header</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout)</td><td class="doc"><p>If you use <code><a href="Servant-API-Header.html#t:Header">Header</a></code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of the type specified by <code><a href="Servant-API-Header.html#t:Header">Header</a></code>.
This lets servant worry about extracting it from the request and turning
it into a value of the type you specify.</p><p>All it asks is for a <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> instance.</p><p>Example:</p><pre>newtype Referer = Referer Text
deriving (Eq, Show, FromText, ToText)
-- GET /view-my-referer
type MyApi = &quot;view-my-referer&quot; :&gt; Header &quot;Referer&quot; Referer :&gt; Get Referer
server :: Server MyApi
server = viewReferer
where viewReferer :: Referer -&gt; EitherT (Int, String) IO referer
viewReferer referer = return referer</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryFlag">QueryFlag</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> sym) sublayout)</td><td class="doc"><p>If you use <code><code><a href="Servant-API-QueryParam.html#t:QueryFlag">QueryFlag</a></code> &quot;published&quot;</code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of type <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Bool.html#t:Bool">Bool</a></code>.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; QueryFlag &quot;published&quot; :&gt; Get [Book]
server :: Server MyApi
server = getBooks
where getBooks :: Bool -&gt; EitherT (Int, String) IO [Book]
getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument...</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryParams">QueryParams</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout)</td><td class="doc"><p>If you use <code><code><a href="Servant-API-QueryParam.html#t:QueryParams">QueryParams</a></code> &quot;authors&quot; Text</code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of type <code>[<code>Text</code>]</code>.</p><p>This lets servant worry about looking up 0 or more values in the query string
associated to <code>authors</code> and turning each of them into a value of
the type you specify.</p><p>You can control how the individual values are converted from <code>Text</code> to your type
by simply providing an instance of <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> for your type.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; QueryParams &quot;authors&quot; Text :&gt; Get [Book]
server :: Server MyApi
server = getBooksBy
where getBooksBy :: [Text] -&gt; EitherT (Int, String) IO [Book]
getBooksBy authors = ...return all books by these authors...</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryParam">QueryParam</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout)</td><td class="doc"><p>If you use <code><code><a href="Servant-API-QueryParam.html#t:QueryParam">QueryParam</a></code> &quot;author&quot; Text</code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of type <code><code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a></code> <code>Text</code></code>.</p><p>This lets servant worry about looking it up in the query string
and turning it into a value of the type you specify, enclosed
in <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a></code>, because it may not be there and servant would then
hand you <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#v:Nothing">Nothing</a></code>.</p><p>You can control how it'll be converted from <code>Text</code> to your type
by simply providing an instance of <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> for your type.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; QueryParam &quot;author&quot; Text :&gt; Get [Book]
server :: Server MyApi
server = getBooksBy
where getBooksBy :: Maybe Text -&gt; EitherT (Int, String) IO [Book]
getBooksBy Nothing = ...return all books...
getBooksBy (Just author) = ...return books by the given author...</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:FromJSON">FromJSON</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-ReqBody.html#t:ReqBody">ReqBody</a> * a) sublayout)</td><td class="doc"><p>If you use <code><a href="Servant-API-ReqBody.html#t:ReqBody">ReqBody</a></code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of the type specified by <code><a href="Servant-API-ReqBody.html#t:ReqBody">ReqBody</a></code>.
This lets servant worry about extracting it from the request and turning
it into a value of the type you specify.</p><p>All it asks is for a <code><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:FromJSON">FromJSON</a></code> instance.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; ReqBody Book :&gt; Post Book
server :: Server MyApi
server = postBook
where postBook :: Book -&gt; EitherT (Int, String) IO Book
postBook book = ...insert into your db...</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> path, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> path sublayout)</td><td class="doc"><p>Make sure the incoming request starts with <code>&quot;/path&quot;</code>, strip it and
pass the rest of the request path to <code>sublayout</code>.</p></td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-Capture.html#t:Capture">Capture</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * capture a) sublayout) = a -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-Header.html#t:Header">Header</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout) = <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a> a -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryFlag">QueryFlag</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> sym) sublayout) = <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Bool.html#t:Bool">Bool</a> -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryParams">QueryParams</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout) = [a] -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryParam">QueryParam</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout) = <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a> a -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-ReqBody.html#t:ReqBody">ReqBody</a> * a) sublayout) = a -&gt; <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:Server">Server</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> path sublayout) = <a href="Servant-Server.html#t:Server">Server</a> sublayout</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

4
Servant-API.html Normal file

File diff suppressed because one or more lines are too long

7
Servant-Common-Text.html Normal file
View file

@ -0,0 +1,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.Common.Text</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-Common-Text.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-Common-Text.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>Safe-Inferred</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.Common.Text</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><span class="keyword">class</span> <a href="#t:FromText">FromText</a> a <span class="keyword">where</span><ul class="subs"><li><a href="#v:fromText">fromText</a> :: <a href="https://hackage.haskell.org/package/text-1.2.0.0/docs/Data-Text.html#t:Text">Text</a> -&gt; <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a> a</li></ul></li><li class="src short"><span class="keyword">class</span> <a href="#t:ToText">ToText</a> a <span class="keyword">where</span><ul class="subs"><li><a href="#v:toText">toText</a> :: a -&gt; <a href="https://hackage.haskell.org/package/text-1.2.0.0/docs/Data-Text.html#t:Text">Text</a></li></ul></li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><span class="keyword">class</span> <a name="t:FromText" class="def">FromText</a> a <span class="keyword">where</span> <a href="src/Servant-Common-Text.html#FromText" class="link">Source</a></p><div class="doc"><p>For getting values from url captures and query string parameters</p></div><div class="subs methods"><p class="caption">Methods</p><p class="src"><a name="v:fromText" class="def">fromText</a> :: <a href="https://hackage.haskell.org/package/text-1.2.0.0/docs/Data-Text.html#t:Text">Text</a> -&gt; <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a> a <a href="src/Servant-Common-Text.html#fromText" class="link">Source</a></p></div><div class="subs instances"><p id="control.i:FromText" class="caption collapser" onclick="toggleSection('i:FromText')">Instances</p><div id="section.i:FromText" class="show"><table><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Bool.html#t:Bool">Bool</a></td><td class="doc"><pre>fromText &quot;true&quot; = Just True
fromText &quot;false&quot; = Just False
fromText _ = Nothing</pre></td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Prelude.html#t:Double">Double</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Prelude.html#t:Float">Float</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int8">Int8</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int16">Int16</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int32">Int32</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int64">Int64</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Prelude.html#t:Integer">Integer</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Word.html#t:Word">Word</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Word.html#t:Word8">Word8</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Word.html#t:Word16">Word16</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Word.html#t:Word32">Word32</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Word.html#t:Word64">Word64</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:FromText">FromText</a> <a href="https://hackage.haskell.org/package/text-1.2.0.0/docs/Data-Text.html#t:Text">Text</a></td><td class="doc empty">&nbsp;</td></tr></table></div></div></div><div class="top"><p class="src"><span class="keyword">class</span> <a name="t:ToText" class="def">ToText</a> a <span class="keyword">where</span> <a href="src/Servant-Common-Text.html#ToText" class="link">Source</a></p><div class="doc"><p>For putting values in paths and query string parameters</p></div><div class="subs methods"><p class="caption">Methods</p><p class="src"><a name="v:toText" class="def">toText</a> :: a -&gt; <a href="https://hackage.haskell.org/package/text-1.2.0.0/docs/Data-Text.html#t:Text">Text</a> <a href="src/Servant-Common-Text.html#toText" class="link">Source</a></p></div><div class="subs instances"><p id="control.i:ToText" class="caption collapser" onclick="toggleSection('i:ToText')">Instances</p><div id="section.i:ToText" class="show"><table><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Bool.html#t:Bool">Bool</a></td><td class="doc"><pre>toText True = &quot;true&quot;
toText False = &quot;false&quot;</pre></td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Prelude.html#t:Double">Double</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Prelude.html#t:Float">Float</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int8">Int8</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int16">Int16</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int32">Int32</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int64">Int64</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Prelude.html#t:Integer">Integer</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Word.html#t:Word">Word</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Word.html#t:Word8">Word8</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Word.html#t:Word16">Word16</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Word.html#t:Word32">Word32</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Word.html#t:Word64">Word64</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="Servant-Common-Text.html#t:ToText">ToText</a> <a href="https://hackage.haskell.org/package/text-1.2.0.0/docs/Data-Text.html#t:Text">Text</a></td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

17
Servant-QQ.html Normal file

File diff suppressed because one or more lines are too long

129
Servant-Server.html Normal file
View file

@ -0,0 +1,129 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.Server</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-Server.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-Server.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.Server</p></div><div id="table-of-contents"><p class="caption">Contents</p><ul><li><a href="#g:1">Implementing Servers</a></li><li><a href="#g:2">Route mismatch</a></li></ul></div><div id="description"><p class="caption">Description</p><div class="doc"><p>This module lets you implement <code><a href="Servant-Server.html#t:Server">Server</a></code>s for defined APIs. You'll
most likely just need <code><a href="Servant-Server.html#v:serve">serve</a></code>.</p></div></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><a href="#v:serve">serve</a> :: <a href="Servant-Server.html#t:HasServer">HasServer</a> layout =&gt; <a href="Servant.html#t:Proxy">Proxy</a> layout -&gt; <a href="Servant-Server.html#t:Server">Server</a> layout -&gt; <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Application">Application</a></li><li class="src short"><a href="#v:toApplication">toApplication</a> :: <a href="Servant-Server.html#t:RoutingApplication">RoutingApplication</a> -&gt; <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Application">Application</a></li><li class="src short"><span class="keyword">data</span> <a href="#t:RouteMismatch">RouteMismatch</a><ul class="subs"><li>= <a href="#v:NotFound">NotFound</a></li><li>| <a href="#v:WrongMethod">WrongMethod</a></li><li>| <a href="#v:InvalidBody">InvalidBody</a></li></ul></li><li class="src short"><span class="keyword">newtype</span> <a href="#t:RouteResult">RouteResult</a> a = <a href="#v:RR">RR</a> {<ul class="subs"><li><a href="#v:routeResult">routeResult</a> :: <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Either.html#t:Either">Either</a> <a href="Servant-Server.html#t:RouteMismatch">RouteMismatch</a> a</li></ul>}</li><li class="src short"><a href="#v:failWith">failWith</a> :: <a href="Servant-Server.html#t:RouteMismatch">RouteMismatch</a> -&gt; <a href="Servant-Server.html#t:RouteResult">RouteResult</a> a</li><li class="src short"><a href="#v:succeedWith">succeedWith</a> :: a -&gt; <a href="Servant-Server.html#t:RouteResult">RouteResult</a> a</li><li class="src short"><a href="#v:isMismatch">isMismatch</a> :: <a href="Servant-Server.html#t:RouteResult">RouteResult</a> a -&gt; <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Bool.html#t:Bool">Bool</a></li><li class="src short"><span class="keyword">type</span> <a href="#t:RoutingApplication">RoutingApplication</a> = <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Request">Request</a> -&gt; (<a href="Servant-Server.html#t:RouteResult">RouteResult</a> <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Response">Response</a> -&gt; <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/System-IO.html#t:IO">IO</a> <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:ResponseReceived">ResponseReceived</a>) -&gt; <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/System-IO.html#t:IO">IO</a> <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:ResponseReceived">ResponseReceived</a></li><li class="src short"><span class="keyword">class</span> <a href="#t:HasServer">HasServer</a> layout <span class="keyword">where</span><ul class="subs"><li><span class="keyword">type</span> <a href="#t:Server">Server</a> layout :: *</li><li><a href="#v:route">route</a> :: <a href="Servant.html#t:Proxy">Proxy</a> layout -&gt; <a href="Servant-Server.html#t:Server">Server</a> layout -&gt; <a href="Servant-Server.html#t:RoutingApplication">RoutingApplication</a></li></ul></li></ul></div><div id="interface"><h1 id="g:1">Implementing Servers</h1><div class="top"><p class="src"><a name="v:serve" class="def">serve</a> :: <a href="Servant-Server.html#t:HasServer">HasServer</a> layout =&gt; <a href="Servant.html#t:Proxy">Proxy</a> layout -&gt; <a href="Servant-Server.html#t:Server">Server</a> layout -&gt; <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Application">Application</a> <a href="src/Servant-Server.html#serve" class="link">Source</a></p><div class="doc"><p><code><a href="Servant-Server.html#v:serve">serve</a></code> allows you to implement an API and produce a wai <code><a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Application">Application</a></code>.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; Get [Book] -- GET /books
:&lt;|&gt; &quot;books&quot; :&gt; ReqBody Book :&gt; Post Book -- POST /books
server :: Server MyApi
server = listAllBooks :&lt;|&gt; postBook
where listAllBooks = ...
postBook book = ...
app :: Application
app = serve myApi server
main :: IO ()
main = Network.Wai.Handler.Warp.run 8080 app</pre></div></div><div class="top"><p class="src"><a name="v:toApplication" class="def">toApplication</a> :: <a href="Servant-Server.html#t:RoutingApplication">RoutingApplication</a> -&gt; <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Application">Application</a> <a href="src/Servant-Server.html#toApplication" class="link">Source</a></p></div><h1 id="g:2">Route mismatch</h1><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:RouteMismatch" class="def">RouteMismatch</a> <a href="src/Servant-Server.html#RouteMismatch" class="link">Source</a></p><div class="subs constructors"><p class="caption">Constructors</p><table><tr><td class="src"><a name="v:NotFound" class="def">NotFound</a></td><td class="doc"><p>the usual &quot;not found&quot; error</p></td></tr><tr><td class="src"><a name="v:WrongMethod" class="def">WrongMethod</a></td><td class="doc"><p>a more informative &quot;you just got the HTTP method wrong&quot; error</p></td></tr><tr><td class="src"><a name="v:InvalidBody" class="def">InvalidBody</a></td><td class="doc"><p>an even more informative &quot;your json request body wasn't valid&quot; error</p></td></tr></table></div><div class="subs instances"><p id="control.i:RouteMismatch" class="caption collapser" onclick="toggleSection('i:RouteMismatch')">Instances</p><div id="section.i:RouteMismatch" class="show"><table><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Eq.html#t:Eq">Eq</a> <a href="Servant-Server.html#t:RouteMismatch">RouteMismatch</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Text-Show.html#t:Show">Show</a> <a href="Servant-Server.html#t:RouteMismatch">RouteMismatch</a></td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Monoid.html#t:Monoid">Monoid</a> <a href="Servant-Server.html#t:RouteMismatch">RouteMismatch</a></td><td class="doc"><pre>&gt; mempty = NotFound
&gt;
&gt; NotFound <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Monoid.html#v:mappend">mappend</a></code> x = x
&gt; WrongMethod <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Monoid.html#v:mappend">mappend</a></code> InvalidBody = InvalidBody
&gt; WrongMethod <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Monoid.html#v:mappend">mappend</a></code> _ = WrongMethod
&gt; InvalidBody <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Monoid.html#v:mappend">mappend</a></code> _ = InvalidBody
</pre></td></tr></table></div></div></div><div class="top"><p class="src"><span class="keyword">newtype</span> <a name="t:RouteResult" class="def">RouteResult</a> a <a href="src/Servant-Server.html#RouteResult" class="link">Source</a></p><div class="doc"><p>A wrapper around <code><code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Either.html#t:Either">Either</a></code> <code><a href="Servant-Server.html#t:RouteMismatch">RouteMismatch</a></code> a</code>.</p></div><div class="subs constructors"><p class="caption">Constructors</p><table><tr><td class="src"><a name="v:RR" class="def">RR</a></td><td class="doc empty">&nbsp;</td></tr><tr><td colspan="2"><div class="subs fields"><p class="caption">Fields</p><dl><dt class="src"><a name="v:routeResult" class="def">routeResult</a> :: <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Either.html#t:Either">Either</a> <a href="Servant-Server.html#t:RouteMismatch">RouteMismatch</a> a</dt><dd class="doc empty">&nbsp;</dd></dl><div class="clear"></div></div></td></tr></table></div><div class="subs instances"><p id="control.i:RouteResult" class="caption collapser" onclick="toggleSection('i:RouteResult')">Instances</p><div id="section.i:RouteResult" class="show"><table><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Eq.html#t:Eq">Eq</a> a =&gt; <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Eq.html#t:Eq">Eq</a> (<a href="Servant-Server.html#t:RouteResult">RouteResult</a> a)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Text-Show.html#t:Show">Show</a> a =&gt; <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Text-Show.html#t:Show">Show</a> (<a href="Servant-Server.html#t:RouteResult">RouteResult</a> a)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Monoid.html#t:Monoid">Monoid</a> (<a href="Servant-Server.html#t:RouteResult">RouteResult</a> a)</td><td class="doc"><p>If we get a <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Either.html#v:Right">Right</a></code>, it has precedence over everything else.</p><p>This in particular means that if we could get several <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Either.html#v:Right">Right</a></code>s,
only the first we encounter would be taken into account.</p></td></tr></table></div></div></div><div class="top"><p class="src"><a name="v:failWith" class="def">failWith</a> :: <a href="Servant-Server.html#t:RouteMismatch">RouteMismatch</a> -&gt; <a href="Servant-Server.html#t:RouteResult">RouteResult</a> a <a href="src/Servant-Server.html#failWith" class="link">Source</a></p></div><div class="top"><p class="src"><a name="v:succeedWith" class="def">succeedWith</a> :: a -&gt; <a href="Servant-Server.html#t:RouteResult">RouteResult</a> a <a href="src/Servant-Server.html#succeedWith" class="link">Source</a></p></div><div class="top"><p class="src"><a name="v:isMismatch" class="def">isMismatch</a> :: <a href="Servant-Server.html#t:RouteResult">RouteResult</a> a -&gt; <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Bool.html#t:Bool">Bool</a> <a href="src/Servant-Server.html#isMismatch" class="link">Source</a></p></div><div class="top"><p class="src"><span class="keyword">type</span> <a name="t:RoutingApplication" class="def">RoutingApplication</a> <a href="src/Servant-Server.html#RoutingApplication" class="link">Source</a></p><div class="subs arguments"><p class="caption">Arguments</p><table><tr><td class="src">&nbsp;= <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Request">Request</a></td><td class="doc"><p>the request, the field <code><a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#v:pathInfo">pathInfo</a></code> may be modified by url routing</p></td></tr><tr><td class="src">-&gt; (<a href="Servant-Server.html#t:RouteResult">RouteResult</a> <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:Response">Response</a> -&gt; <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/System-IO.html#t:IO">IO</a> <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:ResponseReceived">ResponseReceived</a>)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src">-&gt; <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/System-IO.html#t:IO">IO</a> <a href="https://hackage.haskell.org/package/wai-3.0.2/docs/Network-Wai.html#t:ResponseReceived">ResponseReceived</a></td><td class="doc empty">&nbsp;</td></tr></table></div></div><div class="top"><p class="src"><span class="keyword">class</span> <a name="t:HasServer" class="def">HasServer</a> layout <span class="keyword">where</span> <a href="src/Servant-Server.html#HasServer" class="link">Source</a></p><div class="subs associated-types"><p class="caption">Associated Types</p><p class="src"><span class="keyword">type</span> <a name="t:Server" class="def">Server</a> layout :: * <a href="src/Servant-Server.html#Server" class="link">Source</a></p></div><div class="subs methods"><p class="caption">Methods</p><p class="src"><a name="v:route" class="def">route</a> :: <a href="Servant.html#t:Proxy">Proxy</a> layout -&gt; <a href="Servant-Server.html#t:Server">Server</a> layout -&gt; <a href="Servant-Server.html#t:RoutingApplication">RoutingApplication</a> <a href="src/Servant-Server.html#route" class="link">Source</a></p></div><div class="subs instances"><p id="control.i:HasServer" class="caption collapser" onclick="toggleSection('i:HasServer')">Instances</p><div id="section.i:HasServer" class="show"><table><tr><td class="src"><a href="Servant-Server.html#t:HasServer">HasServer</a> <a href="Servant-API-Delete.html#t:Delete">Delete</a></td><td class="doc"><p>If you have a <code><a href="Servant-API-Delete.html#t:Delete">Delete</a></code> endpoint in your API,
the handler for this endpoint is meant to delete
a resource.</p><p>The code of the handler will, just like
for <code><a href="Servant-API-Get.html#t:Get">Get</a></code>, <code><a href="Servant-API-Post.html#t:Post">Post</a></code> and
<code><a href="Servant-API-Put.html#t:Put">Put</a></code>, run in <code>EitherT (Int, String) IO ()</code>.
The <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a></code> represents the status code and the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a></code> a message
to be returned. You can use <code><a href="https://hackage.haskell.org/package/either-4.3.2/docs/Control-Monad-Trans-Either.html#v:left">left</a></code> to
painlessly error out if the conditions for a successful deletion
are not met.</p></td></tr><tr><td class="src"><a href="Servant-Server.html#t:HasServer">HasServer</a> <a href="Servant-API-Raw.html#t:Raw">Raw</a></td><td class="doc"><p>Just pass the request to the underlying application and serve its response.</p><p>Example:</p><pre>type MyApi = &quot;images&quot; :&gt; Raw
server :: Server MyApi
server = serveDirectory &quot;/var/www/images&quot;</pre></td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a> result =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Get.html#t:Get">Get</a> result)</td><td class="doc"><p>When implementing the handler for a <code><a href="Servant-API-Get.html#t:Get">Get</a></code> endpoint,
just like for <code><a href="Servant-API-Delete.html#t:Delete">Delete</a></code>, <code><a href="Servant-API-Post.html#t:Post">Post</a></code>
and <code><a href="Servant-API-Put.html#t:Put">Put</a></code>, the handler code runs in the
<code>EitherT (Int, String) IO</code> monad, where the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a></code> represents
the status code and the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a></code> a message, returned in case of
failure. You can quite handily use <code><a href="Control-Monad-Trans-EitherT.html#v:left">left</a></code>
to quickly fail if some conditions are not met.</p><p>If successfully returning a value, we just require that its type has
a <code><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a></code> instance and servant takes care of encoding it for you,
yielding status code 200 along the way.</p></td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a> a =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Post.html#t:Post">Post</a> a)</td><td class="doc"><p>When implementing the handler for a <code><a href="Servant-API-Post.html#t:Post">Post</a></code> endpoint,
just like for <code><a href="Servant-API-Delete.html#t:Delete">Delete</a></code>, <code><a href="Servant-API-Get.html#t:Get">Get</a></code>
and <code><a href="Servant-API-Put.html#t:Put">Put</a></code>, the handler code runs in the
<code>EitherT (Int, String) IO</code> monad, where the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a></code> represents
the status code and the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a></code> a message, returned in case of
failure. You can quite handily use <code><a href="Control-Monad-Trans-EitherT.html#v:left">left</a></code>
to quickly fail if some conditions are not met.</p><p>If successfully returning a value, we just require that its type has
a <code><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a></code> instance and servant takes care of encoding it for you,
yielding status code 201 along the way.</p></td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a> a =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Put.html#t:Put">Put</a> a)</td><td class="doc"><p>When implementing the handler for a <code><a href="Servant-API-Put.html#t:Put">Put</a></code> endpoint,
just like for <code><a href="Servant-API-Delete.html#t:Delete">Delete</a></code>, <code><a href="Servant-API-Get.html#t:Get">Get</a></code>
and <code><a href="Servant-API-Post.html#t:Post">Post</a></code>, the handler code runs in the
<code>EitherT (Int, String) IO</code> monad, where the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Int.html#t:Int">Int</a></code> represents
the status code and the <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-String.html#t:String">String</a></code> a message, returned in case of
failure. You can quite handily use <code><a href="Control-Monad-Trans-EitherT.html#v:left">left</a></code>
to quickly fail if some conditions are not met.</p><p>If successfully returning a value, we just require that its type has
a <code><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:ToJSON">ToJSON</a></code> instance and servant takes care of encoding it for you,
yielding status code 200 along the way.</p></td></tr><tr><td class="src">(<a href="Servant-Server.html#t:HasServer">HasServer</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> b) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Alternative.html#t::-60--124--62-">(:&lt;|&gt;)</a> a b)</td><td class="doc"><p>A server for <code>a <code><a href="Servant-API-Alternative.html#t::-60--124--62-">:&lt;|&gt;</a></code> b</code> first tries to match the request again the route
represented by <code>a</code> and if it fails tries <code>b</code>. You must provide a request
handler for each route.</p><pre>type MyApi = &quot;books&quot; :&gt; Get [Book] -- GET /books
:&lt;|&gt; &quot;books&quot; :&gt; ReqBody Book :&gt; Post Book -- POST /books
server :: Server MyApi
server = listAllBooks :&lt;|&gt; postBook
where listAllBooks = ...
postBook book = ...</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> capture, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-Capture.html#t:Capture">Capture</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * capture a) sublayout)</td><td class="doc"><p>If you use <code><a href="Servant-API-Capture.html#t:Capture">Capture</a></code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of the type specified by the <code><a href="Servant-API-Capture.html#t:Capture">Capture</a></code>.
This lets servant worry about getting it from the URL and turning
it into a value of the type you specify.</p><p>You can control how it'll be converted from <code><a href="https://hackage.haskell.org/package/text-1.2.0.0/docs/Data-Text.html#t:Text">Text</a></code> to your type
by simply providing an instance of <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> for your type.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; Capture &quot;isbn&quot; Text :&gt; Get Book
server :: Server MyApi
server = getBook
where getBook :: Text -&gt; EitherT (Int, String) IO Book
getBook isbn = ...</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-Header.html#t:Header">Header</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout)</td><td class="doc"><p>If you use <code><a href="Servant-API-Header.html#t:Header">Header</a></code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of the type specified by <code><a href="Servant-API-Header.html#t:Header">Header</a></code>.
This lets servant worry about extracting it from the request and turning
it into a value of the type you specify.</p><p>All it asks is for a <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> instance.</p><p>Example:</p><pre>newtype Referer = Referer Text
deriving (Eq, Show, FromText, ToText)
-- GET /view-my-referer
type MyApi = &quot;view-my-referer&quot; :&gt; Header &quot;Referer&quot; Referer :&gt; Get Referer
server :: Server MyApi
server = viewReferer
where viewReferer :: Referer -&gt; EitherT (Int, String) IO referer
viewReferer referer = return referer</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryFlag">QueryFlag</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> sym) sublayout)</td><td class="doc"><p>If you use <code><code><a href="Servant-API-QueryParam.html#t:QueryFlag">QueryFlag</a></code> &quot;published&quot;</code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of type <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Bool.html#t:Bool">Bool</a></code>.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; QueryFlag &quot;published&quot; :&gt; Get [Book]
server :: Server MyApi
server = getBooks
where getBooks :: Bool -&gt; EitherT (Int, String) IO [Book]
getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument...</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryParams">QueryParams</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout)</td><td class="doc"><p>If you use <code><code><a href="Servant-API-QueryParam.html#t:QueryParams">QueryParams</a></code> &quot;authors&quot; Text</code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of type <code>[<code>Text</code>]</code>.</p><p>This lets servant worry about looking up 0 or more values in the query string
associated to <code>authors</code> and turning each of them into a value of
the type you specify.</p><p>You can control how the individual values are converted from <code>Text</code> to your type
by simply providing an instance of <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> for your type.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; QueryParams &quot;authors&quot; Text :&gt; Get [Book]
server :: Server MyApi
server = getBooksBy
where getBooksBy :: [Text] -&gt; EitherT (Int, String) IO [Book]
getBooksBy authors = ...return all books by these authors...</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> sym, <a href="Servant-Common-Text.html#t:FromText">FromText</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-QueryParam.html#t:QueryParam">QueryParam</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> * sym a) sublayout)</td><td class="doc"><p>If you use <code><code><a href="Servant-API-QueryParam.html#t:QueryParam">QueryParam</a></code> &quot;author&quot; Text</code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of type <code><code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a></code> <code>Text</code></code>.</p><p>This lets servant worry about looking it up in the query string
and turning it into a value of the type you specify, enclosed
in <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#t:Maybe">Maybe</a></code>, because it may not be there and servant would then
hand you <code><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#v:Nothing">Nothing</a></code>.</p><p>You can control how it'll be converted from <code>Text</code> to your type
by simply providing an instance of <code><a href="Servant-Common-Text.html#t:FromText">FromText</a></code> for your type.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; QueryParam &quot;author&quot; Text :&gt; Get [Book]
server :: Server MyApi
server = getBooksBy
where getBooksBy :: Maybe Text -&gt; EitherT (Int, String) IO [Book]
getBooksBy Nothing = ...return all books...
getBooksBy (Just author) = ...return books by the given author...</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:FromJSON">FromJSON</a> a, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> * (<a href="Servant-API-ReqBody.html#t:ReqBody">ReqBody</a> * a) sublayout)</td><td class="doc"><p>If you use <code><a href="Servant-API-ReqBody.html#t:ReqBody">ReqBody</a></code> in one of the endpoints for your API,
this automatically requires your server-side handler to be a function
that takes an argument of the type specified by <code><a href="Servant-API-ReqBody.html#t:ReqBody">ReqBody</a></code>.
This lets servant worry about extracting it from the request and turning
it into a value of the type you specify.</p><p>All it asks is for a <code><a href="https://hackage.haskell.org/package/aeson-0.8.0.2/docs/Data-Aeson-Types.html#t:FromJSON">FromJSON</a></code> instance.</p><p>Example:</p><pre>type MyApi = &quot;books&quot; :&gt; ReqBody Book :&gt; Post Book
server :: Server MyApi
server = postBook
where postBook :: Book -&gt; EitherT (Int, String) IO Book
postBook book = ...insert into your db...</pre></td></tr><tr><td class="src">(<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:KnownSymbol">KnownSymbol</a> path, <a href="Servant-Server.html#t:HasServer">HasServer</a> sublayout) =&gt; <a href="Servant-Server.html#t:HasServer">HasServer</a> (<a href="Servant-API-Sub.html#t::-62-">(:&gt;)</a> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-TypeLits.html#t:Symbol">Symbol</a> path sublayout)</td><td class="doc"><p>Make sure the incoming request starts with <code>&quot;/path&quot;</code>, strip it and
pass the rest of the request path to <code>sublayout</code>.</p></td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

23
Servant-Utils-Links.html Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,15 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.Utils.StaticFiles</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant-Utils-StaticFiles.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant-Utils-StaticFiles.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant.Utils.StaticFiles</p></div><div id="description"><p class="caption">Description</p><div class="doc"><p>This module defines a sever-side handler that lets you serve static files.</p><ul><li><code><a href="Servant-Utils-StaticFiles.html#v:serveDirectory">serveDirectory</a></code> lets you serve anything that lives under a particular
directory on your filesystem.</li></ul></div></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><a href="#v:serveDirectory">serveDirectory</a> :: <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/System-IO.html#t:FilePath">FilePath</a> -&gt; <a href="Servant-Server.html#t:Server">Server</a> <a href="Servant-API-Raw.html#t:Raw">Raw</a></li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><a name="v:serveDirectory" class="def">serveDirectory</a> :: <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/System-IO.html#t:FilePath">FilePath</a> -&gt; <a href="Servant-Server.html#t:Server">Server</a> <a href="Servant-API-Raw.html#t:Raw">Raw</a> <a href="src/Servant-Utils-StaticFiles.html#serveDirectory" class="link">Source</a></p><div class="doc"><p>Serve anything under the specified directory as a <code><a href="Servant-API-Raw.html#t:Raw">Raw</a></code> endpoint.</p><pre>type MyApi = &quot;static&quot; :&gt; Raw
server :: Server MyApi
server = serveDirectory &quot;/var/www&quot;
</pre><p>would capture any request to <code>/static/&lt;something&gt;</code> and look for
<code>&lt;something&gt;</code> under <code>/var/www</code>.</p><p>It will do its best to guess the MIME type for that file, based on the extension,
and send an appropriate <em>Content-Type</em> header if possible.</p><p>If your goal is to serve HTML, CSS and Javascript files that use the rest of the API
as a webapp backend, you will most likely not want the static files to be hidden
behind a <em>/static/</em> prefix. In that case, remember to put the <code><a href="Servant-Utils-StaticFiles.html#v:serveDirectory">serveDirectory</a></code>
handler in the last position, because <em>servant</em> will try to match the handlers
in order.</p></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

6
Servant.html Normal file
View file

@ -0,0 +1,6 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();setSynopsis("mini_Servant.html");};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/Servant.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Safe Haskell</th><td>None</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">Servant</p></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short">module <a href="Servant-API.html">Servant.API</a></li><li class="src short">module <a href="Servant-Server.html">Servant.Server</a></li><li class="src short">module <a href="Servant-Common-Text.html">Servant.Common.Text</a></li><li class="src short">module <a href="Servant-QQ.html">Servant.QQ</a></li><li class="src short">module <a href="Servant-Utils-Links.html">Servant.Utils.Links</a></li><li class="src short">module <a href="Servant-Utils-StaticFiles.html">Servant.Utils.StaticFiles</a></li><li class="src short"><span class="keyword">data</span> <a href="#t:Proxy">Proxy</a> t :: k -&gt; * = <a href="#v:Proxy">Proxy</a></li></ul></div><div id="interface"><h1>Documentation</h1><div class="doc"><p>This module and its submodules can be used to define servant APIs. Note
that these API definitions don't directly implement a server (or anything
else).</p></div><div class="top"><p class="src">module <a href="Servant-API.html">Servant.API</a></p></div><div class="doc"><p>For implementing servers for servant APIs.</p></div><div class="top"><p class="src">module <a href="Servant-Server.html">Servant.Server</a></p></div><div class="doc"><p>Using your types in request paths and query string parameters</p></div><div class="top"><p class="src">module <a href="Servant-Common-Text.html">Servant.Common.Text</a></p></div><div class="doc"><p>Utilities on top of the servant core</p></div><div class="top"><p class="src">module <a href="Servant-QQ.html">Servant.QQ</a></p></div><div class="top"><p class="src">module <a href="Servant-Utils-Links.html">Servant.Utils.Links</a></p></div><div class="top"><p class="src">module <a href="Servant-Utils-StaticFiles.html">Servant.Utils.StaticFiles</a></p></div><div class="doc"><p>Useful re-exports</p></div><div class="top"><p class="src"><span class="keyword">data</span> <a name="t:Proxy" class="def">Proxy</a> t :: k -&gt; *</p><div class="doc"><p>A concrete, poly-kinded proxy type</p></div><div class="subs constructors"><p class="caption">Constructors</p><table><tr><td class="src"><a name="v:Proxy" class="def">Proxy</a></td><td class="doc empty">&nbsp;</td></tr></table></div><div class="subs instances"><p id="control.i:Proxy" class="caption collapser" onclick="toggleSection('i:Proxy')">Instances</p><div id="section.i:Proxy" class="show"><table><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Control-Monad.html#t:Monad">Monad</a> (<a href="Servant.html#t:Proxy">Proxy</a> *)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Control-Monad.html#t:Functor">Functor</a> (<a href="Servant.html#t:Proxy">Proxy</a> *)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Control-Applicative.html#t:Applicative">Applicative</a> (<a href="Servant.html#t:Proxy">Proxy</a> *)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Prelude.html#t:Bounded">Bounded</a> (<a href="Servant.html#t:Proxy">Proxy</a> k s)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Prelude.html#t:Enum">Enum</a> (<a href="Servant.html#t:Proxy">Proxy</a> k s)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Eq.html#t:Eq">Eq</a> (<a href="Servant.html#t:Proxy">Proxy</a> k s)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Ord.html#t:Ord">Ord</a> (<a href="Servant.html#t:Proxy">Proxy</a> k s)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Text-Read.html#t:Read">Read</a> (<a href="Servant.html#t:Proxy">Proxy</a> k s)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Text-Show.html#t:Show">Show</a> (<a href="Servant.html#t:Proxy">Proxy</a> k s)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Ix.html#t:Ix">Ix</a> (<a href="Servant.html#t:Proxy">Proxy</a> k s)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-Generics.html#t:Generic">Generic</a> (<a href="Servant.html#t:Proxy">Proxy</a> * t)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Monoid.html#t:Monoid">Monoid</a> (<a href="Servant.html#t:Proxy">Proxy</a> * s)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Typeable-Internal.html#t:Typeable">Typeable</a> (k -&gt; *) (<a href="Servant.html#t:Proxy">Proxy</a> k)</td><td class="doc empty">&nbsp;</td></tr><tr><td class="src"><span class="keyword">type</span> <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-Generics.html#t:Rep">Rep</a> (<a href="Servant.html#t:Proxy">Proxy</a> k t) = <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-Generics.html#t:D1">D1</a> D1Proxy (<a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-Generics.html#t:C1">C1</a> C1_0Proxy <a href="https://hackage.haskell.org/package/base-4.7.0.1/docs/GHC-Generics.html#t:U1">U1</a>)</td><td class="doc empty">&nbsp;</td></tr></table></div></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

View file

@ -1,2 +0,0 @@
import Distribution.Simple
main = defaultMain

4
doc-index.html Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,2 +0,0 @@
- `greet.hs` shows how to write a simple webservice, run it, query it with automatically-derived haskell functions and print the (generated) markdown documentation for the API.
- `greet.md` contains the aforementionned generated documentation.

View file

@ -1,72 +0,0 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import Data.Monoid
import Data.Proxy
import Data.Text
import GHC.Generics
import Network.Wai
import Network.Wai.Handler.Warp
import Servant
-- * Example
-- | A greet message data type
newtype Greet = Greet { msg :: Text }
deriving (Generic, Show)
instance FromJSON Greet
instance ToJSON Greet
-- API specification
type TestApi =
-- GET /hello/:name?capital={true, false} returns a Greet as JSON
"hello" :> Capture "name" Text :> QueryParam "capital" Bool :> Get Greet
-- POST /greet with a Greet as JSON in the request body,
-- returns a Greet as JSON
:<|> "greet" :> ReqBody Greet :> Post Greet
-- DELETE /greet/:greetid
:<|> "greet" :> Capture "greetid" Text :> Delete
testApi :: Proxy TestApi
testApi = Proxy
-- Server-side handlers.
--
-- There's one handler per endpoint, which, just like in the type
-- that represents the API, are glued together using :<|>.
--
-- Each handler runs in the 'EitherT (Int, String) IO' monad.
server :: Server TestApi
server = helloH :<|> postGreetH :<|> deleteGreetH
where helloH name Nothing = helloH name (Just False)
helloH name (Just False) = return . Greet $ "Hello, " <> name
helloH name (Just True) = return . Greet . toUpper $ "Hello, " <> name
postGreetH greet = return greet
deleteGreetH _ = return ()
-- Turn the server into a WAI app. 'serve' is provided by servant,
-- more precisely by the Servant.Server module.
test :: Application
test = serve testApi server
-- Run the server.
--
-- 'run' comes from Network.Wai.Handler.Warp
runTestServer :: Port -> IO ()
runTestServer port = run port test
-- Put this all to work!
main :: IO ()
main = runTestServer 8001

View file

@ -1,52 +0,0 @@
POST /greet
-----------
**Request Body**:
``` javascript
{"msg":"Hello, haskeller!"}
```
**Response**:
- Status code 201
- Response body as below.
``` javascript
{"msg":"Hello, haskeller!"}
```
GET /hello/:name
----------------
**Captures**:
- *name*: name of the person to greet
**GET Parameters**:
- capital
- **Values**: *true, false*
- **Description**: Get the greeting message in uppercase (true) or not (false). Default is false.
**Response**:
- Status code 200
- Response body as below.
``` javascript
{"msg":"Hello, haskeller!"}
```
DELETE /greet/:greetid
----------------------
**Captures**:
- *greetid*: identifier of the greet msg to remove
**Response**:
- Status code 204
- No response body

30
frames.html Normal file
View file

@ -0,0 +1,30 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="haddock-util.js" type="text/javascript"></script>
<script type="text/javascript"><!--
/*
The synopsis frame needs to be updated using javascript, so we hide
it by default and only show it if javascript is enabled.
TODO: provide some means to disable it.
*/
function load() {
var d = document.getElementById("inner-fs");
d.rows = "50%,50%";
postReframe();
}
--></script>
</head>
<frameset id="outer-fs" cols="25%,75%" onload="load()">
<frameset id="inner-fs" rows="100%,0%">
<frame src="index-frames.html" name="modules" />
<frame src="" name="synopsis" />
</frameset>
<frame src="index.html" name="main" />
</frameset>
</html>

344
haddock-util.js Normal file
View file

@ -0,0 +1,344 @@
// Haddock JavaScript utilities
var rspace = /\s\s+/g,
rtrim = /^\s+|\s+$/g;
function spaced(s) { return (" " + s + " ").replace(rspace, " "); }
function trim(s) { return s.replace(rtrim, ""); }
function hasClass(elem, value) {
var className = spaced(elem.className || "");
return className.indexOf( " " + value + " " ) >= 0;
}
function addClass(elem, value) {
var className = spaced(elem.className || "");
if ( className.indexOf( " " + value + " " ) < 0 ) {
elem.className = trim(className + " " + value);
}
}
function removeClass(elem, value) {
var className = spaced(elem.className || "");
className = className.replace(" " + value + " ", " ");
elem.className = trim(className);
}
function toggleClass(elem, valueOn, valueOff, bool) {
if (bool == null) { bool = ! hasClass(elem, valueOn); }
if (bool) {
removeClass(elem, valueOff);
addClass(elem, valueOn);
}
else {
removeClass(elem, valueOn);
addClass(elem, valueOff);
}
return bool;
}
function makeClassToggle(valueOn, valueOff)
{
return function(elem, bool) {
return toggleClass(elem, valueOn, valueOff, bool);
}
}
toggleShow = makeClassToggle("show", "hide");
toggleCollapser = makeClassToggle("collapser", "expander");
function toggleSection(id)
{
var b = toggleShow(document.getElementById("section." + id));
toggleCollapser(document.getElementById("control." + id), b);
rememberCollapsed(id, b);
return b;
}
var collapsed = {};
function rememberCollapsed(id, b)
{
if(b)
delete collapsed[id]
else
collapsed[id] = null;
var sections = [];
for(var i in collapsed)
{
if(collapsed.hasOwnProperty(i))
sections.push(i);
}
// cookie specific to this page; don't use setCookie which sets path=/
document.cookie = "collapsed=" + escape(sections.join('+'));
}
function restoreCollapsed()
{
var cookie = getCookie("collapsed");
if(!cookie)
return;
var ids = cookie.split('+');
for(var i in ids)
{
if(document.getElementById("section." + ids[i]))
toggleSection(ids[i]);
}
}
function setCookie(name, value) {
document.cookie = name + "=" + escape(value) + ";path=/;";
}
function clearCookie(name) {
document.cookie = name + "=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT;";
}
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) {
return unescape(c.substring(nameEQ.length,c.length));
}
}
return null;
}
var max_results = 75; // 50 is not enough to search for map in the base libraries
var shown_range = null;
var last_search = null;
function quick_search()
{
perform_search(false);
}
function full_search()
{
perform_search(true);
}
function perform_search(full)
{
var text = document.getElementById("searchbox").value.toLowerCase();
if (text == last_search && !full) return;
last_search = text;
var table = document.getElementById("indexlist");
var status = document.getElementById("searchmsg");
var children = table.firstChild.childNodes;
// first figure out the first node with the prefix
var first = bisect(-1);
var last = (first == -1 ? -1 : bisect(1));
if (first == -1)
{
table.className = "";
status.innerHTML = "No results found, displaying all";
}
else if (first == 0 && last == children.length - 1)
{
table.className = "";
status.innerHTML = "";
}
else if (last - first >= max_results && !full)
{
table.className = "";
status.innerHTML = "More than " + max_results + ", press Search to display";
}
else
{
// decide what you need to clear/show
if (shown_range)
setclass(shown_range[0], shown_range[1], "indexrow");
setclass(first, last, "indexshow");
shown_range = [first, last];
table.className = "indexsearch";
status.innerHTML = "";
}
function setclass(first, last, status)
{
for (var i = first; i <= last; i++)
{
children[i].className = status;
}
}
// do a binary search, treating 0 as ...
// return either -1 (no 0's found) or location of most far match
function bisect(dir)
{
var first = 0, finish = children.length - 1;
var mid, success = false;
while (finish - first > 3)
{
mid = Math.floor((finish + first) / 2);
var i = checkitem(mid);
if (i == 0) i = dir;
if (i == -1)
finish = mid;
else
first = mid;
}
var a = (dir == 1 ? first : finish);
var b = (dir == 1 ? finish : first);
for (var i = b; i != a - dir; i -= dir)
{
if (checkitem(i) == 0) return i;
}
return -1;
}
// from an index, decide what the result is
// 0 = match, -1 is lower, 1 is higher
function checkitem(i)
{
var s = getitem(i).toLowerCase().substr(0, text.length);
if (s == text) return 0;
else return (s > text ? -1 : 1);
}
// from an index, get its string
// this abstracts over alternates
function getitem(i)
{
for ( ; i >= 0; i--)
{
var s = children[i].firstChild.firstChild.data;
if (s.indexOf(' ') == -1)
return s;
}
return ""; // should never be reached
}
}
function setSynopsis(filename) {
if (parent.window.synopsis) {
if (parent.window.synopsis.location.replace) {
// In Firefox this avoids adding the change to the history.
parent.window.synopsis.location.replace(filename);
} else {
parent.window.synopsis.location = filename;
}
}
}
function addMenuItem(html) {
var menu = document.getElementById("page-menu");
if (menu) {
var btn = menu.firstChild.cloneNode(false);
btn.innerHTML = html;
menu.appendChild(btn);
}
}
function adjustForFrames() {
var bodyCls;
if (parent.location.href == window.location.href) {
// not in frames, so add Frames button
addMenuItem("<a href='#' onclick='reframe();return true;'>Frames</a>");
bodyCls = "no-frame";
}
else {
bodyCls = "in-frame";
}
addClass(document.body, bodyCls);
}
function reframe() {
setCookie("haddock-reframe", document.URL);
window.location = "frames.html";
}
function postReframe() {
var s = getCookie("haddock-reframe");
if (s) {
parent.window.main.location = s;
clearCookie("haddock-reframe");
}
}
function styles() {
var i, a, es = document.getElementsByTagName("link"), rs = [];
for (i = 0; a = es[i]; i++) {
if(a.rel.indexOf("style") != -1 && a.title) {
rs.push(a);
}
}
return rs;
}
function addStyleMenu() {
var as = styles();
var i, a, btns = "";
for(i=0; a = as[i]; i++) {
btns += "<li><a href='#' onclick=\"setActiveStyleSheet('"
+ a.title + "'); return false;\">"
+ a.title + "</a></li>"
}
if (as.length > 1) {
var h = "<div id='style-menu-holder'>"
+ "<a href='#' onclick='styleMenu(); return false;'>Style &#9662;</a>"
+ "<ul id='style-menu' class='hide'>" + btns + "</ul>"
+ "</div>";
addMenuItem(h);
}
}
function setActiveStyleSheet(title) {
var as = styles();
var i, a, found;
for(i=0; a = as[i]; i++) {
a.disabled = true;
// need to do this always, some browsers are edge triggered
if(a.title == title) {
found = a;
}
}
if (found) {
found.disabled = false;
setCookie("haddock-style", title);
}
else {
as[0].disabled = false;
clearCookie("haddock-style");
}
styleMenu(false);
}
function resetStyle() {
var s = getCookie("haddock-style");
if (s) setActiveStyleSheet(s);
}
function styleMenu(show) {
var m = document.getElementById('style-menu');
if (m) toggleShow(m, show);
}
function pageLoad() {
addStyleMenu();
adjustForFrames();
resetStyle();
restoreCollapsed();
}

BIN
hslogo-16.png Normal file

Binary file not shown.

After

(image error) Size: 1.6 KiB

4
index-frames.html Normal file
View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>servant-0.2: A family of combinators for defining webservices APIs and serving them</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-list"><p class="caption">Modules</p><ul><li class="module"><a href="Servant.html" target="main">Servant</a></li><li class="module"><a href="Servant-API.html" target="main">Servant.API</a></li><li class="module"><a href="Servant-API-Alternative.html" target="main">Servant.API.Alternative</a></li><li class="module"><a href="Servant-API-Capture.html" target="main">Servant.API.Capture</a></li><li class="module"><a href="Servant-API-Delete.html" target="main">Servant.API.Delete</a></li><li class="module"><a href="Servant-API-Get.html" target="main">Servant.API.Get</a></li><li class="module"><a href="Servant-API-Header.html" target="main">Servant.API.Header</a></li><li class="module"><a href="Servant-API-Post.html" target="main">Servant.API.Post</a></li><li class="module"><a href="Servant-API-Put.html" target="main">Servant.API.Put</a></li><li class="module"><a href="Servant-API-QueryParam.html" target="main">Servant.API.QueryParam</a></li><li class="module"><a href="Servant-API-Raw.html" target="main">Servant.API.Raw</a></li><li class="module"><a href="Servant-API-ReqBody.html" target="main">Servant.API.ReqBody</a></li><li class="module"><a href="Servant-API-Sub.html" target="main">Servant.API.Sub</a></li><li class="module"><a href="Servant-Common-Text.html" target="main">Servant.Common.Text</a></li><li class="module"><a href="Servant-QQ.html" target="main">Servant.QQ</a></li><li class="module"><a href="Servant-Server.html" target="main">Servant.Server</a></li><li class="module"><a href="Servant-Utils-Links.html" target="main">Servant.Utils.Links</a></li><li class="module"><a href="Servant-Utils-StaticFiles.html" target="main">Servant.Utils.StaticFiles</a></li></ul></div></body></html>

4
index.html Normal file
View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>servant-0.2: A family of combinators for defining webservices APIs and serving them</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">servant-0.2: A family of combinators for defining webservices APIs and serving them</p></div><div id="content"><div id="description"><h1>servant-0.2: A family of combinators for defining webservices APIs and serving them</h1><div class="doc empty">&nbsp;</div></div><div id="module-list"><p class="caption">Modules</p><ul><li><span class="module"><span id="control.n.1" class="collapser" onclick="toggleSection('n.1')">&nbsp;</span><a href="Servant.html">Servant</a></span><ul id="section.n.1" class="show"><li><span class="module"><span id="control.n.1.1" class="collapser" onclick="toggleSection('n.1.1')">&nbsp;</span><a href="Servant-API.html">Servant.API</a></span><ul id="section.n.1.1" class="show"><li><span class="module"><a href="Servant-API-Alternative.html">Servant.API.Alternative</a></span></li><li><span class="module"><a href="Servant-API-Capture.html">Servant.API.Capture</a></span></li><li><span class="module"><a href="Servant-API-Delete.html">Servant.API.Delete</a></span></li><li><span class="module"><a href="Servant-API-Get.html">Servant.API.Get</a></span></li><li><span class="module"><a href="Servant-API-Header.html">Servant.API.Header</a></span></li><li><span class="module"><a href="Servant-API-Post.html">Servant.API.Post</a></span></li><li><span class="module"><a href="Servant-API-Put.html">Servant.API.Put</a></span></li><li><span class="module"><a href="Servant-API-QueryParam.html">Servant.API.QueryParam</a></span></li><li><span class="module"><a href="Servant-API-Raw.html">Servant.API.Raw</a></span></li><li><span class="module"><a href="Servant-API-ReqBody.html">Servant.API.ReqBody</a></span></li><li><span class="module"><a href="Servant-API-Sub.html">Servant.API.Sub</a></span></li></ul></li><li><span id="control.n.1.2" class="module collapser" onclick="toggleSection('n.1.2')">Common</span><ul id="section.n.1.2" class="show"><li><span class="module"><a href="Servant-Common-Text.html">Servant.Common.Text</a></span></li></ul></li><li><span class="module"><a href="Servant-QQ.html">Servant.QQ</a></span></li><li><span class="module"><a href="Servant-Server.html">Servant.Server</a></span></li><li><span id="control.n.1.5" class="module collapser" onclick="toggleSection('n.1.5')">Utils</span><ul id="section.n.1.5" class="show"><li><span class="module"><a href="Servant-Utils-Links.html">Servant.Utils.Links</a></span></li><li><span class="module"><a href="Servant-Utils-StaticFiles.html">Servant.Utils.StaticFiles</a></span></li></ul></li></ul></li></ul></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.15.0</p></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Alternative</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API.Alternative</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> a <a href="Servant-API-Alternative.html#t::-60--124--62-" target="main">:&lt;|&gt;</a> b</p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Capture</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API.Capture</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-API-Capture.html#t:Capture" target="main">Capture</a> sym a</p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Delete</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API.Delete</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-API-Delete.html#t:Delete" target="main">Delete</a></p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Get</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API.Get</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-API-Get.html#t:Get" target="main">Get</a> a</p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Header</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API.Header</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-API-Header.html#t:Header" target="main">Header</a> sym a</p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Post</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API.Post</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-API-Post.html#t:Post" target="main">Post</a> a</p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Put</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API.Put</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-API-Put.html#t:Put" target="main">Put</a> a</p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.QueryParam</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API.QueryParam</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-API-QueryParam.html#t:QueryParam" target="main">QueryParam</a> sym a</p></div><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-API-QueryParam.html#t:QueryParams" target="main">QueryParams</a> sym a</p></div><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-API-QueryParam.html#t:QueryFlag" target="main">QueryFlag</a> sym</p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Raw</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API.Raw</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-API-Raw.html#t:Raw" target="main">Raw</a></p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.ReqBody</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API.ReqBody</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-API-ReqBody.html#t:ReqBody" target="main">ReqBody</a> a</p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API.Sub</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API.Sub</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> path <a href="Servant-API-Sub.html#t::-62-" target="main">:&gt;</a> a</p></div></div></body></html>

4
mini_Servant-API.html Normal file
View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.API</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.API</p></div><div id="interface"><h1>Combinators</h1><h1>Accessing information from the request</h1><h1>Actual endpoints, distinguished by HTTP method</h1><h1>Untyped endpoints</h1><h1>Utilities</h1></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.Common.Text</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.Common.Text</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">class</span> <a href="Servant-Common-Text.html#t:FromText" target="main">FromText</a> a</p></div><div class="top"><p class="src"><span class="keyword">class</span> <a href="Servant-Common-Text.html#t:ToText" target="main">ToText</a> a</p></div></div></body></html>

4
mini_Servant-QQ.html Normal file
View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.QQ</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.QQ</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">class</span> <a href="Servant-QQ.html#t:ExpSYM" target="main">ExpSYM</a> repr' repr</p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:-62-:" target="main">(&gt;:)</a></p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:parseMethod" target="main">parseMethod</a></p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:parseUrlSegment" target="main">parseUrlSegment</a></p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:parseUrl" target="main">parseUrl</a></p></div><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-QQ.html#t:Typ" target="main">Typ</a></p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:parseTyp" target="main">parseTyp</a></p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:parseEntry" target="main">parseEntry</a></p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:blockComment" target="main">blockComment</a></p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:inlineComment" target="main">inlineComment</a></p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:eol" target="main">eol</a></p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:eols" target="main">eols</a></p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:parseAll" target="main">parseAll</a></p></div><div class="top"><p class="src"><a href="Servant-QQ.html#v:sitemap" target="main">sitemap</a></p></div></div></body></html>

4
mini_Servant-Server.html Normal file
View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.Server</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.Server</p></div><div id="interface"><h1>Implementing Servers</h1><div class="top"><p class="src"><a href="Servant-Server.html#v:serve" target="main">serve</a></p></div><div class="top"><p class="src"><a href="Servant-Server.html#v:toApplication" target="main">toApplication</a></p></div><h1>Route mismatch</h1><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-Server.html#t:RouteMismatch" target="main">RouteMismatch</a></p></div><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-Server.html#t:RouteResult" target="main">RouteResult</a> a</p></div><div class="top"><p class="src"><a href="Servant-Server.html#v:failWith" target="main">failWith</a></p></div><div class="top"><p class="src"><a href="Servant-Server.html#v:succeedWith" target="main">succeedWith</a></p></div><div class="top"><p class="src"><a href="Servant-Server.html#v:isMismatch" target="main">isMismatch</a></p></div><div class="top"><p class="src"><span class="keyword">type</span> <a href="Servant-Server.html#t:RoutingApplication" target="main">RoutingApplication</a></p></div><div class="top"><p class="src"><span class="keyword">class</span> <a href="Servant-Server.html#t:HasServer" target="main">HasServer</a> layout</p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.Utils.Links</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.Utils.Links</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">type family</span> <a href="#t:Or">Or</a> a b</p></div><div class="top"><p class="src"><span class="keyword">type family</span> <a href="#t:And">And</a> a b</p></div><div class="top"><p class="src"><span class="keyword">type family</span> <a href="#t:IsElem">IsElem</a> a s</p></div><div class="top"><p class="src"><span class="keyword">type family</span> <a href="#t:IsLink-39--39-">IsLink''</a> l</p></div><div class="top"><p class="src"><span class="keyword">type family</span> <a href="#t:IsLink-39-">IsLink'</a> e</p></div><div class="top"><p class="src"><span class="keyword">type family</span> <a href="#t:IsLink">IsLink</a> e</p></div><div class="top"><p class="src"><span class="keyword">class</span> <a href="Servant-Utils-Links.html#t:ValidLinkIn" target="main">ValidLinkIn</a> f s</p></div><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant-Utils-Links.html#t:Link" target="main">Link</a></p></div><div class="top"><p class="src"><span class="keyword">class</span> <a href="Servant-Utils-Links.html#t:VLinkHelper" target="main">VLinkHelper</a> f</p></div></div></body></html>

View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant.Utils.StaticFiles</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant.Utils.StaticFiles</p></div><div id="interface"><div class="top"><p class="src"><a href="Servant-Utils-StaticFiles.html#v:serveDirectory" target="main">serveDirectory</a></p></div></div></body></html>

4
mini_Servant.html Normal file
View file

@ -0,0 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Servant</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
window.onload = function () {pageLoad();};
//]]>
</script></head><body id="mini"><div id="module-header"><p class="caption">Servant</p></div><div id="interface"><div class="top"><p class="src"><span class="keyword">data</span> <a href="Servant.html#t:Proxy" target="main">Proxy</a> t</p></div></div></body></html>

BIN
minus.gif Normal file

Binary file not shown.

After

(image error) Size: 56 B

577
ocean.css Normal file
View file

@ -0,0 +1,577 @@
/* @group Fundamentals */
* { margin: 0; padding: 0 }
/* Is this portable? */
html {
background-color: white;
width: 100%;
height: 100%;
}
body {
background: white;
color: black;
text-align: left;
min-height: 100%;
position: relative;
}
p {
margin: 0.8em 0;
}
ul, ol {
margin: 0.8em 0 0.8em 2em;
}
dl {
margin: 0.8em 0;
}
dt {
font-weight: bold;
}
dd {
margin-left: 2em;
}
a { text-decoration: none; }
a[href]:link { color: rgb(196,69,29); }
a[href]:visited { color: rgb(171,105,84); }
a[href]:hover { text-decoration:underline; }
/* @end */
/* @group Fonts & Sizes */
/* Basic technique & IE workarounds from YUI 3
For reasons, see:
http://yui.yahooapis.com/3.1.1/build/cssfonts/fonts.css
*/
body {
font:13px/1.4 sans-serif;
*font-size:small; /* for IE */
*font:x-small; /* for IE in quirks mode */
}
h1 { font-size: 146.5%; /* 19pt */ }
h2 { font-size: 131%; /* 17pt */ }
h3 { font-size: 116%; /* 15pt */ }
h4 { font-size: 100%; /* 13pt */ }
h5 { font-size: 100%; /* 13pt */ }
select, input, button, textarea {
font:99% sans-serif;
}
table {
font-size:inherit;
font:100%;
}
pre, code, kbd, samp, tt, .src {
font-family:monospace;
*font-size:108%;
line-height: 124%;
}
.links, .link {
font-size: 85%; /* 11pt */
}
#module-header .caption {
font-size: 182%; /* 24pt */
}
.info {
font-size: 85%; /* 11pt */
}
#table-of-contents, #synopsis {
/* font-size: 85%; /* 11pt */
}
/* @end */
/* @group Common */
.caption, h1, h2, h3, h4, h5, h6 {
font-weight: bold;
color: rgb(78,98,114);
margin: 0.8em 0 0.4em;
}
* + h1, * + h2, * + h3, * + h4, * + h5, * + h6 {
margin-top: 2em;
}
h1 + h2, h2 + h3, h3 + h4, h4 + h5, h5 + h6 {
margin-top: inherit;
}
ul.links {
list-style: none;
text-align: left;
float: right;
display: inline-table;
margin: 0 0 0 1em;
}
ul.links li {
display: inline;
border-left: 1px solid #d5d5d5;
white-space: nowrap;
padding: 0;
}
ul.links li a {
padding: 0.2em 0.5em;
}
.hide { display: none; }
.show { display: inherit; }
.clear { clear: both; }
.collapser {
background-image: url(minus.gif);
background-repeat: no-repeat;
}
.expander {
background-image: url(plus.gif);
background-repeat: no-repeat;
}
p.caption.collapser,
p.caption.expander {
background-position: 0 0.4em;
}
.collapser, .expander {
padding-left: 14px;
margin-left: -14px;
cursor: pointer;
}
pre {
padding: 0.25em;
margin: 0.8em 0;
background: rgb(229,237,244);
overflow: auto;
border-bottom: 0.25em solid white;
/* white border adds some space below the box to compensate
for visual extra space that paragraphs have between baseline
and the bounding box */
}
.src {
background: #f0f0f0;
padding: 0.2em 0.5em;
}
.keyword { font-weight: normal; }
.def { font-weight: bold; }
/* @end */
/* @group Page Structure */
#content {
margin: 0 auto;
padding: 0 2em 6em;
}
#package-header {
background: rgb(41,56,69);
border-top: 5px solid rgb(78,98,114);
color: #ddd;
padding: 0.2em;
position: relative;
text-align: left;
}
#package-header .caption {
background: url(hslogo-16.png) no-repeat 0em;
color: white;
margin: 0 2em;
font-weight: normal;
font-style: normal;
padding-left: 2em;
}
#package-header a:link, #package-header a:visited { color: white; }
#package-header a:hover { background: rgb(78,98,114); }
#module-header .caption {
color: rgb(78,98,114);
font-weight: bold;
border-bottom: 1px solid #ddd;
}
table.info {
float: right;
padding: 0.5em 1em;
border: 1px solid #ddd;
color: rgb(78,98,114);
background-color: #fff;
max-width: 40%;
border-spacing: 0;
position: relative;
top: -0.5em;
margin: 0 0 0 2em;
}
.info th {
padding: 0 1em 0 0;
}
div#style-menu-holder {
position: relative;
z-index: 2;
display: inline;
}
#style-menu {
position: absolute;
z-index: 1;
overflow: visible;
background: #374c5e;
margin: 0;
text-align: center;
right: 0;
padding: 0;
top: 1.25em;
}
#style-menu li {
display: list-item;
border-style: none;
margin: 0;
padding: 0;
color: #000;
list-style-type: none;
}
#style-menu li + li {
border-top: 1px solid #919191;
}
#style-menu a {
width: 6em;
padding: 3px;
display: block;
}
#footer {
background: #ddd;
border-top: 1px solid #aaa;
padding: 0.5em 0;
color: #666;
text-align: center;
position: absolute;
bottom: 0;
width: 100%;
height: 3em;
}
/* @end */
/* @group Front Matter */
#table-of-contents {
float: right;
clear: right;
background: #faf9dc;
border: 1px solid #d8d7ad;
padding: 0.5em 1em;
max-width: 20em;
margin: 0.5em 0 1em 1em;
}
#table-of-contents .caption {
text-align: center;
margin: 0;
}
#table-of-contents ul {
list-style: none;
margin: 0;
}
#table-of-contents ul ul {
margin-left: 2em;
}
#description .caption {
display: none;
}
#synopsis {
display: none;
}
.no-frame #synopsis {
display: block;
position: fixed;
right: 0;
height: 80%;
top: 10%;
padding: 0;
}
#synopsis .caption {
float: left;
width: 29px;
color: rgba(255,255,255,0);
height: 110px;
margin: 0;
font-size: 1px;
padding: 0;
}
#synopsis p.caption.collapser {
background: url(synopsis.png) no-repeat -64px -8px;
}
#synopsis p.caption.expander {
background: url(synopsis.png) no-repeat 0px -8px;
}
#synopsis ul {
height: 100%;
overflow: auto;
padding: 0.5em;
margin: 0;
}
#synopsis ul ul {
overflow: hidden;
}
#synopsis ul,
#synopsis ul li.src {
background-color: #faf9dc;
white-space: nowrap;
list-style: none;
margin-left: 0;
}
/* @end */
/* @group Main Content */
#interface div.top { margin: 2em 0; }
#interface h1 + div.top,
#interface h2 + div.top,
#interface h3 + div.top,
#interface h4 + div.top,
#interface h5 + div.top {
margin-top: 1em;
}
#interface p.src .link {
float: right;
color: #919191;
border-left: 1px solid #919191;
background: #f0f0f0;
padding: 0 0.5em 0.2em;
margin: 0 -0.5em 0 0.5em;
}
#interface span.fixity {
color: #919191;
border-left: 1px solid #919191;
padding: 0.2em 0.5em 0.2em 0.5em;
margin: 0 -1em 0 1em;
}
#interface span.rightedge {
border-left: 1px solid #919191;
padding: 0.2em 0 0.2em 0;
margin: 0 0 0 1em;
}
#interface table { border-spacing: 2px; }
#interface td {
vertical-align: top;
padding-left: 0.5em;
}
#interface td.src {
white-space: nowrap;
}
#interface td.doc p {
margin: 0;
}
#interface td.doc p + p {
margin-top: 0.8em;
}
.subs dl {
margin: 0;
}
.subs dt {
float: left;
clear: left;
display: block;
margin: 1px 0;
}
.subs dd {
float: right;
width: 90%;
display: block;
padding-left: 0.5em;
margin-bottom: 0.5em;
}
.subs dd.empty {
display: none;
}
.subs dd p {
margin: 0;
}
/* Render short-style data instances */
.inst ul {
height: 100%;
padding: 0.5em;
margin: 0;
}
.inst, .inst li {
list-style: none;
margin-left: 1em;
}
.top p.src {
border-top: 1px solid #ccc;
}
.subs, .doc {
/* use this selector for one level of indent */
padding-left: 2em;
}
.warning {
color: red;
}
.arguments {
margin-top: -0.4em;
}
.arguments .caption {
display: none;
}
.fields { padding-left: 1em; }
.fields .caption { display: none; }
.fields p { margin: 0 0; }
/* this seems bulky to me
.methods, .constructors {
background: #f8f8f8;
border: 1px solid #eee;
}
*/
/* @end */
/* @group Auxillary Pages */
.extension-list {
list-style-type: none;
margin-left: 0;
}
#mini {
margin: 0 auto;
padding: 0 1em 1em;
}
#mini > * {
font-size: 93%; /* 12pt */
}
#mini #module-list .caption,
#mini #module-header .caption {
font-size: 125%; /* 15pt */
}
#mini #interface h1,
#mini #interface h2,
#mini #interface h3,
#mini #interface h4 {
font-size: 109%; /* 13pt */
margin: 1em 0 0;
}
#mini #interface .top,
#mini #interface .src {
margin: 0;
}
#mini #module-list ul {
list-style: none;
margin: 0;
}
#alphabet ul {
list-style: none;
padding: 0;
margin: 0.5em 0 0;
text-align: center;
}
#alphabet li {
display: inline;
margin: 0 0.25em;
}
#alphabet a {
font-weight: bold;
}
#index .caption,
#module-list .caption { font-size: 131%; /* 17pt */ }
#index table {
margin-left: 2em;
}
#index .src {
font-weight: bold;
}
#index .alt {
font-size: 77%; /* 10pt */
font-style: italic;
padding-left: 2em;
}
#index td + td {
padding-left: 1em;
}
#module-list ul {
list-style: none;
margin: 0 0 0 2em;
}
#module-list li {
clear: right;
}
#module-list span.collapser,
#module-list span.expander {
background-position: 0 0.3em;
}
#module-list .package {
float: right;
}
/* @end */

BIN
plus.gif Normal file

Binary file not shown.

After

(image error) Size: 59 B

View file

@ -1,97 +0,0 @@
name: servant
version: 0.2
-- synopsis:
-- description:
license: BSD3
license-file: LICENSE
author: Alp Mestanogullari, Sönke Hahn, Julian K. Arni
maintainer: alpmestan@gmail.com
copyright: 2014 Zalora South East Asia Pte Ltd
category: Web
build-type: Simple
cabal-version: >=1.10
tested-with: GHC >= 7.8
library
exposed-modules:
Servant
Servant.API
Servant.API.Alternative
Servant.API.Capture
Servant.API.Delete
Servant.API.Get
Servant.API.Post
Servant.API.Put
Servant.API.QueryParam
Servant.API.Raw
Servant.API.ReqBody
Servant.API.Sub
Servant.Common.Text
Servant.QQ
Servant.Server
Servant.Utils.Links
Servant.Utils.StaticFiles
build-depends:
base >=4.7 && <5
, aeson
, attoparsec
, bytestring
, either
, http-types
, network-uri >= 2.6
, parsec
, safe
, split
, string-conversions
, system-filepath
, template-haskell
, text
, transformers
, wai
, wai-app-static
, warp
hs-source-dirs: src
default-language: Haskell2010
ghc-options: -O0 -Wall
executable greet
main-is: greet.hs
hs-source-dirs: example
ghc-options: -O0 -Wall
default-language: Haskell2010
build-depends:
base
, servant
, aeson
, warp
, wai
, text
test-suite spec
type: exitcode-stdio-1.0
ghc-options:
-Wall -fno-warn-name-shadowing -fno-warn-missing-signatures
default-language: Haskell2010
hs-source-dirs: test
main-is: Spec.hs
build-depends:
base == 4.*
, aeson
, bytestring
, directory
, either
, exceptions
, hspec == 2.*
, hspec-wai
, http-types
, network >= 2.6
, QuickCheck
, parsec
, servant
, string-conversions
, temporary
, text
, transformers
, wai
, wai-extra
, warp

BIN
servant.haddock Normal file

Binary file not shown.

652
servant.txt Normal file
View file

@ -0,0 +1,652 @@
-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | A family of combinators for defining webservices APIs and serving them
--
@package servant
@version 0.2
module Servant.Common.Text
-- | For getting values from url captures and query string parameters
class FromText a
fromText :: FromText a => Text -> Maybe a
-- | For putting values in paths and query string parameters
class ToText a
toText :: ToText a => a -> Text
instance ToText Float
instance FromText Float
instance ToText Double
instance FromText Double
instance ToText Integer
instance FromText Integer
instance ToText Word64
instance FromText Word64
instance ToText Word32
instance FromText Word32
instance ToText Word16
instance FromText Word16
instance ToText Word8
instance FromText Word8
instance ToText Word
instance FromText Word
instance ToText Int64
instance FromText Int64
instance ToText Int32
instance FromText Int32
instance ToText Int16
instance FromText Int16
instance ToText Int8
instance FromText Int8
instance ToText Int
instance FromText Int
instance ToText Bool
instance FromText Bool
instance ToText String
instance FromText String
instance ToText Text
instance FromText Text
-- | This module lets you implement <a>Server</a>s for defined APIs. You'll
-- most likely just need <a>serve</a>.
module Servant.Server
-- | <a>serve</a> allows you to implement an API and produce a wai
-- <a>Application</a>.
--
-- Example:
--
-- <pre>
-- type MyApi = "books" :&gt; Get [Book] -- GET /books
-- :&lt;|&gt; "books" :&gt; ReqBody Book :&gt; Post Book -- POST /books
--
-- server :: Server MyApi
-- server = listAllBooks :&lt;|&gt; postBook
-- where listAllBooks = ...
-- postBook book = ...
--
-- app :: Application
-- app = serve myApi server
--
-- main :: IO ()
-- main = Network.Wai.Handler.Warp.run 8080 app
-- </pre>
serve :: HasServer layout => Proxy layout -> Server layout -> Application
toApplication :: RoutingApplication -> Application
data RouteMismatch
-- | the usual "not found" error
NotFound :: RouteMismatch
-- | a more informative "you just got the HTTP method wrong" error
WrongMethod :: RouteMismatch
-- | an even more informative "your json request body wasn't valid" error
InvalidBody :: RouteMismatch
-- | <pre>
-- &gt; mempty = NotFound
-- &gt;
-- &gt; NotFound <a>mappend</a> x = x
-- &gt; WrongMethod <a>mappend</a> InvalidBody = InvalidBody
-- &gt; WrongMethod <a>mappend</a> _ = WrongMethod
-- &gt; InvalidBody <a>mappend</a> _ = InvalidBody
-- </pre>
-- | A wrapper around <tt><a>Either</a> <a>RouteMismatch</a> a</tt>.
newtype RouteResult a
RR :: Either RouteMismatch a -> RouteResult a
routeResult :: RouteResult a -> Either RouteMismatch a
failWith :: RouteMismatch -> RouteResult a
succeedWith :: a -> RouteResult a
isMismatch :: RouteResult a -> Bool
-- | If we get a <a>Right</a>, it has precedence over everything else.
--
-- This in particular means that if we could get several <a>Right</a>s,
-- only the first we encounter would be taken into account.
type RoutingApplication = Request -> (RouteResult Response -> IO ResponseReceived) -> IO ResponseReceived
class HasServer layout where type family Server layout :: *
route :: HasServer layout => Proxy layout -> Server layout -> RoutingApplication
instance Eq RouteMismatch
instance Show RouteMismatch
instance Eq a => Eq (RouteResult a)
instance Show a => Show (RouteResult a)
instance Monoid (RouteResult a)
instance Monoid RouteMismatch
module Servant.API.Sub
-- | The contained API (second argument) can be found under <tt>("/" ++
-- path)</tt> (path being the first argument).
--
-- Example:
--
-- <pre>
-- -- GET /hello/world
-- -- returning a JSON encoded World value
-- type MyApi = "hello" :&gt; "world" :&gt; Get World
-- </pre>
data (:>) (path :: k) a
(:>) :: Proxy path -> a -> (:>) a
-- | Make sure the incoming request starts with <tt>"/path"</tt>, strip it
-- and pass the rest of the request path to <tt>sublayout</tt>.
instance (KnownSymbol path, HasServer sublayout) => HasServer (path :> sublayout)
module Servant.API.Alternative
-- | Union of two APIs, first takes precedence in case of overlap.
--
-- Example:
--
-- <pre>
-- type MyApi = "books" :&gt; Get [Book] -- GET /books
-- :&lt;|&gt; "books" :&gt; ReqBody Book :&gt; Post Book -- POST /books
-- </pre>
data (:<|>) a b
(:<|>) :: a -> b -> (:<|>) a b
-- | A server for <tt>a <a>:&lt;|&gt;</a> b</tt> first tries to match the
-- request again the route represented by <tt>a</tt> and if it fails
-- tries <tt>b</tt>. You must provide a request handler for each route.
--
-- <pre>
-- type MyApi = "books" :&gt; Get [Book] -- GET /books
-- :&lt;|&gt; "books" :&gt; ReqBody Book :&gt; Post Book -- POST /books
--
-- server :: Server MyApi
-- server = listAllBooks :&lt;|&gt; postBook
-- where listAllBooks = ...
-- postBook book = ...
-- </pre>
instance (HasServer a, HasServer b) => HasServer (a :<|> b)
module Servant.API.Capture
-- | Capture a value from the request path under a certain type <tt>a</tt>.
--
-- Example:
--
-- <pre>
-- -- GET /books/:isbn
-- type MyApi = "books" :&gt; Capture "isbn" Text :&gt; Get Book
-- </pre>
data Capture sym a
instance (KnownSymbol capture, FromText a, HasServer sublayout) => HasServer (Capture capture a :> sublayout)
module Servant.API.Header
-- | Extract the given header's value as a value of type <tt>a</tt>.
--
-- Example:
--
-- <pre>
-- newtype Referer = Referer Text
-- deriving (Eq, Show, FromText, ToText)
--
-- -- GET /view-my-referer
-- type MyApi = "view-my-referer" :&gt; Header "from" Referer :&gt; Get Referer
-- </pre>
data Header sym a
-- | If you use <a>Header</a> in one of the endpoints for your API, this
-- automatically requires your server-side handler to be a function that
-- takes an argument of the type specified by <a>Header</a>. This lets
-- servant worry about extracting it from the request and turning it into
-- a value of the type you specify.
--
-- All it asks is for a <a>FromText</a> instance.
--
-- Example:
--
-- <pre>
-- newtype Referer = Referer Text
-- deriving (Eq, Show, FromText, ToText)
--
-- -- GET /view-my-referer
-- type MyApi = "view-my-referer" :&gt; Header "Referer" Referer :&gt; Get Referer
--
-- server :: Server MyApi
-- server = viewReferer
-- where viewReferer :: Referer -&gt; EitherT (Int, String) IO referer
-- viewReferer referer = return referer
-- </pre>
instance (KnownSymbol sym, FromText a, HasServer sublayout) => HasServer (Header sym a :> sublayout)
module Servant.API.QueryParam
-- | Lookup the value associated to the <tt>sym</tt> query string parameter
-- and try to extract it as a value of type <tt>a</tt>.
--
-- Example:
--
-- <pre>
-- -- /books?author=&lt;author name&gt;
-- type MyApi = "books" :&gt; QueryParam "author" Text :&gt; Get [Book]
-- </pre>
data QueryParam sym a
-- | If you use <tt><a>QueryParam</a> "author" Text</tt> in one of the
-- endpoints for your API, this automatically requires your server-side
-- handler to be a function that takes an argument of type
-- <tt><a>Maybe</a> <tt>Text</tt></tt>.
--
-- This lets servant worry about looking it up in the query string and
-- turning it into a value of the type you specify, enclosed in
-- <a>Maybe</a>, because it may not be there and servant would then hand
-- you <a>Nothing</a>.
--
-- You can control how it'll be converted from <tt>Text</tt> to your type
-- by simply providing an instance of <a>FromText</a> for your type.
--
-- Example:
--
-- <pre>
-- type MyApi = "books" :&gt; QueryParam "author" Text :&gt; Get [Book]
--
-- server :: Server MyApi
-- server = getBooksBy
-- where getBooksBy :: Maybe Text -&gt; EitherT (Int, String) IO [Book]
-- getBooksBy Nothing = ...return all books...
-- getBooksBy (Just author) = ...return books by the given author...
-- </pre>
-- | Lookup the values associated to the <tt>sym</tt> query string
-- parameter and try to extract it as a value of type <tt>[a]</tt>. This
-- is typically meant to support query string parameters of the form
-- <tt>param[]=val1&amp;param[]=val2</tt> and so on. Note that servant
-- doesn't actually require the <tt>[]</tt>s and will fetch the values
-- just fine with <tt>param=val1&amp;param=val2</tt>, too.
--
-- Example:
--
-- <pre>
-- -- /books?authors[]=&lt;author1&gt;&amp;authors[]=&lt;author2&gt;&amp;...
-- type MyApi = "books" :&gt; QueryParams "authors" Text :&gt; Get [Book]
-- </pre>
data QueryParams sym a
-- | If you use <tt><a>QueryParams</a> "authors" Text</tt> in one of the
-- endpoints for your API, this automatically requires your server-side
-- handler to be a function that takes an argument of type
-- <tt>[<tt>Text</tt>]</tt>.
--
-- This lets servant worry about looking up 0 or more values in the query
-- string associated to <tt>authors</tt> and turning each of them into a
-- value of the type you specify.
--
-- You can control how the individual values are converted from
-- <tt>Text</tt> to your type by simply providing an instance of
-- <a>FromText</a> for your type.
--
-- Example:
--
-- <pre>
-- type MyApi = "books" :&gt; QueryParams "authors" Text :&gt; Get [Book]
--
-- server :: Server MyApi
-- server = getBooksBy
-- where getBooksBy :: [Text] -&gt; EitherT (Int, String) IO [Book]
-- getBooksBy authors = ...return all books by these authors...
-- </pre>
-- | Lookup a potentially value-less query string parameter with boolean
-- semantics. If the param <tt>sym</tt> is there without any value, or if
-- it's there with value "true" or "1", it's interpreted as <a>True</a>.
-- Otherwise, it's interpreted as <a>False</a>.
--
-- Example:
--
-- <pre>
-- -- /books?published
-- type MyApi = "books" :&gt; QueryFlag "published" :&gt; Get [Book]
-- </pre>
data QueryFlag sym
-- | If you use <tt><a>QueryFlag</a> "published"</tt> in one of the
-- endpoints for your API, this automatically requires your server-side
-- handler to be a function that takes an argument of type <a>Bool</a>.
--
-- Example:
--
-- <pre>
-- type MyApi = "books" :&gt; QueryFlag "published" :&gt; Get [Book]
--
-- server :: Server MyApi
-- server = getBooks
-- where getBooks :: Bool -&gt; EitherT (Int, String) IO [Book]
-- getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument...
-- </pre>
instance (KnownSymbol sym, HasServer sublayout) => HasServer (QueryFlag sym :> sublayout)
instance (KnownSymbol sym, FromText a, HasServer sublayout) => HasServer (QueryParams sym a :> sublayout)
instance (KnownSymbol sym, FromText a, HasServer sublayout) => HasServer (QueryParam sym a :> sublayout)
module Servant.API.ReqBody
-- | Extract the request body as a value of type <tt>a</tt>.
--
-- Example:
--
-- <pre>
-- -- POST /books
-- type MyApi = "books" :&gt; ReqBody Book :&gt; Post Book
-- </pre>
data ReqBody a
-- | If you use <a>ReqBody</a> in one of the endpoints for your API, this
-- automatically requires your server-side handler to be a function that
-- takes an argument of the type specified by <a>ReqBody</a>. This lets
-- servant worry about extracting it from the request and turning it into
-- a value of the type you specify.
--
-- All it asks is for a <a>FromJSON</a> instance.
--
-- Example:
--
-- <pre>
-- type MyApi = "books" :&gt; ReqBody Book :&gt; Post Book
--
-- server :: Server MyApi
-- server = postBook
-- where postBook :: Book -&gt; EitherT (Int, String) IO Book
-- postBook book = ...insert into your db...
-- </pre>
instance (FromJSON a, HasServer sublayout) => HasServer (ReqBody a :> sublayout)
module Servant.API.Get
-- | Endpoint for simple GET requests. Serves the result as JSON.
--
-- Example:
--
-- <pre>
-- type MyApi = "books" :&gt; Get [Book]
-- </pre>
data Get a
-- | When implementing the handler for a <a>Get</a> endpoint, just like for
-- <a>Delete</a>, <a>Post</a> and <a>Put</a>, the handler code runs in
-- the <tt>EitherT (Int, String) IO</tt> monad, where the <a>Int</a>
-- represents the status code and the <a>String</a> a message, returned
-- in case of failure. You can quite handily use <a>left</a> to quickly
-- fail if some conditions are not met.
--
-- If successfully returning a value, we just require that its type has a
-- <a>ToJSON</a> instance and servant takes care of encoding it for you,
-- yielding status code 200 along the way.
instance Typeable Get
instance ToJSON result => HasServer (Get result)
module Servant.API.Post
-- | Endpoint for POST requests. The type variable represents the type of
-- the response body (not the request body, use <a>RQBody</a> for that).
--
-- Example:
--
-- <pre>
-- -- POST /books
-- -- with a JSON encoded Book as the request body
-- -- returning the just-created Book
-- type MyApi = "books" :&gt; ReqBody Book :&gt; Post Book
-- </pre>
data Post a
-- | When implementing the handler for a <a>Post</a> endpoint, just like
-- for <a>Delete</a>, <a>Get</a> and <a>Put</a>, the handler code runs in
-- the <tt>EitherT (Int, String) IO</tt> monad, where the <a>Int</a>
-- represents the status code and the <a>String</a> a message, returned
-- in case of failure. You can quite handily use <a>left</a> to quickly
-- fail if some conditions are not met.
--
-- If successfully returning a value, we just require that its type has a
-- <a>ToJSON</a> instance and servant takes care of encoding it for you,
-- yielding status code 201 along the way.
instance Typeable Post
instance ToJSON a => HasServer (Post a)
module Servant.API.Delete
-- | Combinator for DELETE requests.
--
-- Example:
--
-- <pre>
-- -- DELETE /books/:isbn
-- type MyApi = "books" :&gt; Capture "isbn" Text :&gt; Delete
-- </pre>
data Delete
-- | If you have a <a>Delete</a> endpoint in your API, the handler for this
-- endpoint is meant to delete a resource.
--
-- The code of the handler will, just like for <a>Get</a>, <a>Post</a>
-- and <a>Put</a>, run in <tt>EitherT (Int, String) IO ()</tt>. The
-- <a>Int</a> represents the status code and the <a>String</a> a message
-- to be returned. You can use <a>left</a> to painlessly error out if the
-- conditions for a successful deletion are not met.
instance Typeable Delete
instance HasServer Delete
module Servant.API.Put
-- | Endpoint for PUT requests, usually used to update a ressource. The
-- type <tt>a</tt> is the type of the response body that's returned.
--
-- Example:
--
-- <pre>
-- -- PUT /books/:isbn
-- -- with a Book as request body, returning the updated Book
-- type MyApi = "books" :&gt; Capture "isbn" Text :&gt; ReqBody Book :&gt; Put Book
-- </pre>
data Put a
-- | When implementing the handler for a <a>Put</a> endpoint, just like for
-- <a>Delete</a>, <a>Get</a> and <a>Post</a>, the handler code runs in
-- the <tt>EitherT (Int, String) IO</tt> monad, where the <a>Int</a>
-- represents the status code and the <a>String</a> a message, returned
-- in case of failure. You can quite handily use <a>left</a> to quickly
-- fail if some conditions are not met.
--
-- If successfully returning a value, we just require that its type has a
-- <a>ToJSON</a> instance and servant takes care of encoding it for you,
-- yielding status code 200 along the way.
instance Typeable Put
instance ToJSON a => HasServer (Put a)
-- | QuasiQuoting utilities for API types.
--
-- <a>sitemap</a> allows you to write your type in a very natural way:
--
-- <pre>
-- [sitemap|
-- PUT hello String -&gt; ()
-- POST hello/p:Int String -&gt; ()
-- GET hello/?name:String Int
-- |]
-- </pre>
--
-- Will generate:
--
-- <pre>
-- "hello" :&gt; ReqBody String :&gt; Put ()
-- :&lt;|&gt; "hello" :&gt; Capture "p" Int :&gt; ReqBody String :&gt; Post ()
-- :&lt;|&gt; "hello" :&gt; QueryParam "name" String :&gt; Get Int
-- </pre>
--
-- Note the <tt>/</tt> before a <tt>QueryParam</tt>!
module Servant.QQ
-- | Finally-tagless encoding for our DSL. Keeping <tt>repr'</tt> and
-- <tt>repr</tt> distinct when writing functions with an <tt>ExpSYM</tt>
-- context ensures certain invariants (for instance, that there is only
-- one of <a>get</a>, <a>post</a>, <a>put</a>, and <a>delete</a> in a
-- value), but sometimes requires a little more work.
class ExpSYM repr' repr | repr -> repr', repr' -> repr
lit :: ExpSYM repr' repr => String -> repr' -> repr
capture :: ExpSYM repr' repr => String -> String -> repr -> repr
reqBody :: ExpSYM repr' repr => String -> repr -> repr
queryParam :: ExpSYM repr' repr => String -> String -> repr -> repr
conj :: ExpSYM repr' repr => repr' -> repr -> repr
get :: ExpSYM repr' repr => String -> repr
post :: ExpSYM repr' repr => String -> repr
put :: ExpSYM repr' repr => String -> repr
delete :: ExpSYM repr' repr => String -> repr
(>:) :: Type -> Type -> Type
parseMethod :: ExpSYM repr' repr => Parser (String -> repr)
parseUrlSegment :: ExpSYM repr repr => Parser (repr -> repr)
parseUrl :: ExpSYM repr repr => Parser (repr -> repr)
data Typ
Val :: String -> Typ
ReqArgVal :: String -> String -> Typ
parseTyp :: Parser Typ
parseEntry :: ExpSYM repr repr => Parser repr
blockComment :: Parser ()
inlineComment :: Parser ()
eol :: Parser String
eols :: Parser ()
parseAll :: Parser Type
-- | The sitemap QuasiQuoter.
--
-- <ul>
-- <li><tt>...<i><a>var</a>:<a>type</a></i>...</tt> becomes a
-- capture</li>
-- <li><tt>.../?<a>var</a>:<a>type</a></tt> becomes a query
-- parameter</li>
-- <li><tt><a>method</a> ... <a>typ</a></tt> becomes a method returning
-- <tt><a>typ</a></tt></li>
-- <li><tt><a>method</a> ... <a>typ1</a> -&gt; <a>typ2</a></tt> becomes a
-- method with request body of <tt><a>typ1</a></tt> and returning
-- <tt><a>typ2</a></tt></li>
-- </ul>
--
-- Comments are allowed, and have the standard Haskell format
--
-- <ul>
-- <li><tt>--</tt> for inline</li>
-- <li><tt>{- ... -}</tt> for block</li>
-- </ul>
sitemap :: QuasiQuoter
instance ExpSYM Type Type
-- | Type safe internal links.
--
-- Provides the function <a>mkLink</a>:
--
-- <pre>
-- type API = Proxy ("hello" :&gt; Get Int
-- :<a>|</a> "bye" :&gt; QueryParam "name" String :&gt; Post Bool)
--
-- api :: API
-- api = proxy
--
-- link1 :: Proxy ("hello" :&gt; Get Int)
-- link1 = proxy
--
-- link2 :: Proxy ("hello" :&gt; Delete)
-- link2 = proxy
--
-- mkLink link1 API -- typechecks, returns 'Link "/hello"'
--
-- mkLink link2 API -- doesn't typecheck
-- </pre>
--
-- That is, <a>mkLink</a> takes two arguments, a link proxy and a
-- sitemap, and returns a <a>Link</a>, but only typechecks if the link
-- proxy is a valid link, and part of the sitemap.
--
-- <b>N.B.:</b> <a>mkLink</a> assumes a capture matches any string
-- (without slashes).
module Servant.Utils.Links
-- | The 'ValidLinkIn f s' constraint holds when <tt>s</tt> is an API that
-- contains <tt>f</tt>, and <tt>f</tt> is a link.
class ValidLinkIn f s
mkLink :: ValidLinkIn f s => f -> s -> Link
data Link
Link :: String -> Link
class VLinkHelper f
vlh :: VLinkHelper f => proxy f -> String
instance Show Link
instance VLinkHelper (Post x)
instance VLinkHelper (Get x)
instance (KnownSymbol s, VLinkHelper e) => VLinkHelper (s :> e)
instance (IsElem f s ~ 'True, IsLink f ~ 'True, VLinkHelper f) => ValidLinkIn f s
module Servant.API.Raw
-- | Endpoint for plugging in your own Wai <a>Application</a>s.
--
-- The given <a>Application</a> will get the request as received by the
-- server, potentially with a modified (stripped) <a>pathInfo</a> if the
-- <a>Application</a> is being routed with <a>:&gt;</a>.
--
-- In addition to just letting you plug in your existing WAI
-- <a>Application</a>s, this can also be used with <a>serveDirectory</a>
-- to serve static files stored in a particular directory on your
-- filesystem, or to serve your API's documentation with
-- <a>serveDocumentation</a>.
data Raw
-- | Just pass the request to the underlying application and serve its
-- response.
--
-- Example:
--
-- <pre>
-- type MyApi = "images" :&gt; Raw
--
-- server :: Server MyApi
-- server = serveDirectory "/var/www/images"
-- </pre>
instance HasServer Raw
-- | This module defines a sever-side handler that lets you serve static
-- files.
--
-- <ul>
-- <li><a>serveDirectory</a> lets you serve anything that lives under a
-- particular directory on your filesystem.</li>
-- </ul>
module Servant.Utils.StaticFiles
-- | Serve anything under the specified directory as a <a>Raw</a> endpoint.
--
-- <pre>
-- type MyApi = "static" :&gt; Raw
--
-- server :: Server MyApi
-- server = serveDirectory "/var/www"
-- </pre>
--
-- would capture any request to <tt>/static/&lt;something&gt;</tt> and
-- look for <tt>&lt;something&gt;</tt> under <tt>/var/www</tt>.
--
-- It will do its best to guess the MIME type for that file, based on the
-- extension, and send an appropriate <i>Content-Type</i> header if
-- possible.
--
-- If your goal is to serve HTML, CSS and Javascript files that use the
-- rest of the API as a webapp backend, you will most likely not want the
-- static files to be hidden behind a <i>/static/</i> prefix. In that
-- case, remember to put the <a>serveDirectory</a> handler in the last
-- position, because <i>servant</i> will try to match the handlers in
-- order.
serveDirectory :: FilePath -> Server Raw
module Servant.API
module Servant
-- | A concrete, poly-kinded proxy type
data Proxy (t :: k) :: k -> *
Proxy :: Proxy

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API/Alternative.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE TypeOperators #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-4"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Alternative</span> <span class='hs-keyword'>where</span>
<a name="line-5"></a>
<a name="line-6"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Monoid</span>
<a name="line-7"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-8"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-9"></a>
<a name="line-10"></a><span class='hs-comment'>-- | Union of two APIs, first takes precedence in case of overlap.</span>
<a name="line-11"></a><span class='hs-comment'>--</span>
<a name="line-12"></a><span class='hs-comment'>-- Example:</span>
<a name="line-13"></a><span class='hs-comment'>--</span>
<a name="line-14"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; Get [Book] -- GET /books</span>
<a name="line-15"></a><span class='hs-comment'>-- &gt; :&lt;|&gt; "books" :&gt; ReqBody Book :&gt; Post Book -- POST /books</span>
<a name="line-16"></a><span class='hs-keyword'>data</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&lt;|&gt;</span> <span class='hs-varid'>b</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&lt;|&gt;</span> <span class='hs-varid'>b</span>
<a name="line-17"></a><span class='hs-keyword'>infixr</span> <span class='hs-num'>8</span> <span class='hs-conop'>:&lt;|&gt;</span>
<a name="line-18"></a>
<a name="line-19"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-comment'>-- | A server for @a ':&lt;|&gt;' b@ first tries to match the request again the route</span>
<a name="line-20"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-comment'>-- represented by @a@ and if it fails tries @b@. You must provide a request</span>
<a name="line-21"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-comment'>-- handler for each route.</span>
<a name="line-22"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-comment'>--</span>
<a name="line-23"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; Get [Book] -- GET /books</span>
<a name="line-24"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-comment'>-- &gt; :&lt;|&gt; "books" :&gt; ReqBody Book :&gt; Post Book -- POST /books</span>
<a name="line-25"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-26"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-comment'>-- &gt; server :: Server MyApi</span>
<a name="line-27"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-comment'>-- &gt; server = listAllBooks :&lt;|&gt; postBook</span>
<a name="line-28"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-comment'>-- &gt; where listAllBooks = ...</span>
<a name="line-29"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-comment'>-- &gt; postBook book = ...</span>
<a name="line-30"></a><a name="instance%20HasServer%20(a%20:%3c%7c%3e%20b)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasServer</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasServer</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>HasServer</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:&lt;|&gt;</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-31"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:&lt;|&gt;</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&lt;|&gt;</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>b</span>
<a name="line-32"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:&lt;|&gt;</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span> <span class='hs-keyglyph'>=</span>
<a name="line-33"></a> <span class='hs-varid'>route</span> <span class='hs-varid'>pa</span> <span class='hs-varid'>a</span> <span class='hs-varid'>request</span> <span class='hs-varop'>$</span> <span class='hs-keyglyph'>\</span> <span class='hs-varid'>mResponse</span> <span class='hs-keyglyph'>-&gt;</span>
<a name="line-34"></a> <span class='hs-keyword'>if</span> <span class='hs-varid'>isMismatch</span> <span class='hs-varid'>mResponse</span>
<a name="line-35"></a> <span class='hs-keyword'>then</span> <span class='hs-varid'>route</span> <span class='hs-varid'>pb</span> <span class='hs-varid'>b</span> <span class='hs-varid'>request</span> <span class='hs-varop'>$</span> <span class='hs-keyglyph'>\</span><span class='hs-varid'>mResponse'</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>respond</span> <span class='hs-layout'>(</span><span class='hs-varid'>mResponse</span> <span class='hs-varop'>&lt;&gt;</span> <span class='hs-varid'>mResponse'</span><span class='hs-layout'>)</span>
<a name="line-36"></a> <span class='hs-keyword'>else</span> <span class='hs-varid'>respond</span> <span class='hs-varid'>mResponse</span>
<a name="line-37"></a>
<a name="line-38"></a> <span class='hs-keyword'>where</span> <span class='hs-varid'>pa</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>a</span>
<a name="line-39"></a> <span class='hs-varid'>pb</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>b</span>
</pre></body>
</html>

View file

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API/Capture.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE PolyKinds #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE TypeOperators #-}</span>
<a name="line-4"></a><span class='hs-comment'>{-# LANGUAGE FlexibleContexts #-}</span>
<a name="line-5"></a><span class='hs-comment'>{-# LANGUAGE FlexibleInstances #-}</span>
<a name="line-6"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-7"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Capture</span> <span class='hs-layout'>(</span><span class='hs-conid'>Capture</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-8"></a>
<a name="line-9"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Text</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>GHC</span><span class='hs-varop'>.</span><span class='hs-conid'>TypeLits</span>
<a name="line-12"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span>
<a name="line-13"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Sub</span>
<a name="line-14"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Text</span>
<a name="line-15"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-16"></a>
<a name="line-17"></a><span class='hs-comment'>-- | Capture a value from the request path under a certain type @a@.</span>
<a name="line-18"></a><span class='hs-comment'>--</span>
<a name="line-19"></a><span class='hs-comment'>-- Example:</span>
<a name="line-20"></a><span class='hs-comment'>--</span>
<a name="line-21"></a><span class='hs-comment'>-- &gt; -- GET /books/:isbn</span>
<a name="line-22"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; Capture "isbn" Text :&gt; Get Book</span>
<a name="line-23"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>Capture</span> <span class='hs-varid'>sym</span> <span class='hs-varid'>a</span>
<a name="line-24"></a>
<a name="line-25"></a><a name="captured"></a><span class='hs-definition'>captured</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>FromText</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-varid'>proxy</span> <span class='hs-layout'>(</span><span class='hs-conid'>Capture</span> <span class='hs-varid'>sym</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Text</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Maybe</span> <span class='hs-varid'>a</span>
<a name="line-26"></a><span class='hs-definition'>captured</span> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>fromText</span>
<a name="line-27"></a>
<a name="line-28"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- | If you use 'Capture' in one of the endpoints for your API,</span>
<a name="line-29"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- this automatically requires your server-side handler to be a function</span>
<a name="line-30"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- that takes an argument of the type specified by the 'Capture'.</span>
<a name="line-31"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- This lets servant worry about getting it from the URL and turning</span>
<a name="line-32"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- it into a value of the type you specify.</span>
<a name="line-33"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-34"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- You can control how it'll be converted from 'Text' to your type</span>
<a name="line-35"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- by simply providing an instance of 'FromText' for your type.</span>
<a name="line-36"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-37"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- Example:</span>
<a name="line-38"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-39"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; Capture "isbn" Text :&gt; Get Book</span>
<a name="line-40"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-41"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server :: Server MyApi</span>
<a name="line-42"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server = getBook</span>
<a name="line-43"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; where getBook :: Text -&gt; EitherT (Int, String) IO Book</span>
<a name="line-44"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; getBook isbn = ...</span>
<a name="line-45"></a><a name="instance%20HasServer%20(Capture%20capture%20a%20:%3e%20sublayout)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>KnownSymbol</span> <span class='hs-varid'>capture</span><span class='hs-layout'>,</span> <span class='hs-conid'>FromText</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasServer</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span>
<a name="line-46"></a> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>HasServer</span> <span class='hs-layout'>(</span><span class='hs-conid'>Capture</span> <span class='hs-varid'>capture</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-47"></a>
<a name="line-48"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-layout'>(</span><span class='hs-conid'>Capture</span> <span class='hs-varid'>capture</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span>
<a name="line-49"></a> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>sublayout</span>
<a name="line-50"></a>
<a name="line-51"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>subserver</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>case</span> <span class='hs-varid'>pathInfo</span> <span class='hs-varid'>request</span> <span class='hs-keyword'>of</span>
<a name="line-52"></a> <span class='hs-layout'>(</span><span class='hs-varid'>first</span> <span class='hs-conop'>:</span> <span class='hs-varid'>rest</span><span class='hs-layout'>)</span>
<a name="line-53"></a> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-keyword'>case</span> <span class='hs-varid'>captured</span> <span class='hs-varid'>captureProxy</span> <span class='hs-varid'>first</span> <span class='hs-keyword'>of</span>
<a name="line-54"></a> <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>NotFound</span>
<a name="line-55"></a> <span class='hs-conid'>Just</span> <span class='hs-varid'>v</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>route</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>subserver</span> <span class='hs-varid'>v</span><span class='hs-layout'>)</span> <span class='hs-varid'>request</span><span class='hs-layout'>{</span>
<a name="line-56"></a> <span class='hs-varid'>pathInfo</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>rest</span>
<a name="line-57"></a> <span class='hs-layout'>}</span> <span class='hs-varid'>respond</span>
<a name="line-58"></a> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>NotFound</span>
<a name="line-59"></a>
<a name="line-60"></a> <span class='hs-keyword'>where</span> <span class='hs-varid'>captureProxy</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-layout'>(</span><span class='hs-conid'>Capture</span> <span class='hs-varid'>capture</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span>
</pre></body>
</html>

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API/Delete.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE OverloadedStrings #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-4"></a><span class='hs-comment'>{-# LANGUAGE DeriveDataTypeable #-}</span>
<a name="line-5"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Delete</span> <span class='hs-keyword'>where</span>
<a name="line-6"></a>
<a name="line-7"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Either</span>
<a name="line-8"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-9"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>String</span><span class='hs-varop'>.</span><span class='hs-conid'>Conversions</span>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Typeable</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>HTTP</span><span class='hs-varop'>.</span><span class='hs-conid'>Types</span>
<a name="line-12"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span>
<a name="line-13"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-14"></a>
<a name="line-15"></a><a name="Delete"></a><span class='hs-comment'>-- | Combinator for DELETE requests.</span>
<a name="line-16"></a><a name="Delete"></a><span class='hs-comment'>--</span>
<a name="line-17"></a><a name="Delete"></a><span class='hs-comment'>-- Example:</span>
<a name="line-18"></a><a name="Delete"></a><span class='hs-comment'>--</span>
<a name="line-19"></a><a name="Delete"></a><span class='hs-comment'>-- &gt; -- DELETE /books/:isbn</span>
<a name="line-20"></a><a name="Delete"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; Capture "isbn" Text :&gt; Delete</span>
<a name="line-21"></a><a name="Delete"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>Delete</span>
<a name="line-22"></a> <span class='hs-keyword'>deriving</span> <span class='hs-conid'>Typeable</span>
<a name="line-23"></a>
<a name="line-24"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-comment'>-- | If you have a 'Delete' endpoint in your API,</span>
<a name="line-25"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-comment'>-- the handler for this endpoint is meant to delete</span>
<a name="line-26"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-comment'>-- a resource.</span>
<a name="line-27"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-comment'>--</span>
<a name="line-28"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-comment'>-- The code of the handler will, just like</span>
<a name="line-29"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-comment'>-- for 'Servant.API.Get.Get', 'Servant.API.Post.Post' and</span>
<a name="line-30"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-comment'>-- 'Servant.API.Put.Put', run in @EitherT (Int, String) IO ()@.</span>
<a name="line-31"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-comment'>-- The 'Int' represents the status code and the 'String' a message</span>
<a name="line-32"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-comment'>-- to be returned. You can use 'Control.Monad.Trans.Either.left' to</span>
<a name="line-33"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-comment'>-- painlessly error out if the conditions for a successful deletion</span>
<a name="line-34"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-comment'>-- are not met.</span>
<a name="line-35"></a><a name="instance%20HasServer%20Delete"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasServer</span> <span class='hs-conid'>Delete</span> <span class='hs-keyword'>where</span>
<a name="line-36"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-conid'>Delete</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>EitherT</span> <span class='hs-layout'>(</span><span class='hs-conid'>Int</span><span class='hs-layout'>,</span> <span class='hs-conid'>String</span><span class='hs-layout'>)</span> <span class='hs-conid'>IO</span> <span class='hs-conid'>()</span>
<a name="line-37"></a>
<a name="line-38"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>action</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span>
<a name="line-39"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>null</span> <span class='hs-layout'>(</span><span class='hs-varid'>pathInfo</span> <span class='hs-varid'>request</span><span class='hs-layout'>)</span> <span class='hs-varop'>&amp;&amp;</span> <span class='hs-varid'>requestMethod</span> <span class='hs-varid'>request</span> <span class='hs-varop'>==</span> <span class='hs-varid'>methodDelete</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-40"></a> <span class='hs-varid'>e</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>runEitherT</span> <span class='hs-varid'>action</span>
<a name="line-41"></a> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>succeedWith</span> <span class='hs-varop'>$</span> <span class='hs-keyword'>case</span> <span class='hs-varid'>e</span> <span class='hs-keyword'>of</span>
<a name="line-42"></a> <span class='hs-conid'>Right</span> <span class='hs-conid'>()</span> <span class='hs-keyglyph'>-&gt;</span>
<a name="line-43"></a> <span class='hs-varid'>responseLBS</span> <span class='hs-varid'>status204</span> <span class='hs-conid'>[]</span> <span class='hs-str'>""</span>
<a name="line-44"></a> <span class='hs-conid'>Left</span> <span class='hs-layout'>(</span><span class='hs-varid'>status</span><span class='hs-layout'>,</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-&gt;</span>
<a name="line-45"></a> <span class='hs-varid'>responseLBS</span> <span class='hs-layout'>(</span><span class='hs-varid'>mkStatus</span> <span class='hs-varid'>status</span> <span class='hs-layout'>(</span><span class='hs-varid'>cs</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <span class='hs-conid'>[]</span> <span class='hs-layout'>(</span><span class='hs-varid'>cs</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span>
<a name="line-46"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>null</span> <span class='hs-layout'>(</span><span class='hs-varid'>pathInfo</span> <span class='hs-varid'>request</span><span class='hs-layout'>)</span> <span class='hs-varop'>&amp;&amp;</span> <span class='hs-varid'>requestMethod</span> <span class='hs-varid'>request</span> <span class='hs-varop'>/=</span> <span class='hs-varid'>methodDelete</span> <span class='hs-keyglyph'>=</span>
<a name="line-47"></a> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>WrongMethod</span>
<a name="line-48"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>otherwise</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>NotFound</span>
</pre></body>
</html>

58
src/Servant-API-Get.html Normal file
View file

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API/Get.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE OverloadedStrings #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-4"></a><span class='hs-comment'>{-# LANGUAGE DeriveDataTypeable #-}</span>
<a name="line-5"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Get</span> <span class='hs-keyword'>where</span>
<a name="line-6"></a>
<a name="line-7"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Either</span>
<a name="line-8"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Aeson</span>
<a name="line-9"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>String</span><span class='hs-varop'>.</span><span class='hs-conid'>Conversions</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Typeable</span>
<a name="line-12"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>HTTP</span><span class='hs-varop'>.</span><span class='hs-conid'>Types</span>
<a name="line-13"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span>
<a name="line-14"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-15"></a>
<a name="line-16"></a><a name="HasServer"></a><span class='hs-comment'>-- | Endpoint for simple GET requests. Serves the result as JSON.</span>
<a name="line-17"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-18"></a><a name="HasServer"></a><span class='hs-comment'>-- Example:</span>
<a name="line-19"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-20"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; Get [Book]</span>
<a name="line-21"></a><a name="HasServer"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>Get</span> <span class='hs-varid'>a</span>
<a name="line-22"></a> <span class='hs-keyword'>deriving</span> <span class='hs-conid'>Typeable</span>
<a name="line-23"></a>
<a name="line-24"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-comment'>-- | When implementing the handler for a 'Get' endpoint,</span>
<a name="line-25"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-comment'>-- just like for 'Servant.API.Delete.Delete', 'Servant.API.Post.Post'</span>
<a name="line-26"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-comment'>-- and 'Servant.API.Put.Put', the handler code runs in the</span>
<a name="line-27"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-comment'>-- @EitherT (Int, String) IO@ monad, where the 'Int' represents</span>
<a name="line-28"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-comment'>-- the status code and the 'String' a message, returned in case of</span>
<a name="line-29"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-comment'>-- failure. You can quite handily use 'Control.Monad.Trans.EitherT.left'</span>
<a name="line-30"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-comment'>-- to quickly fail if some conditions are not met.</span>
<a name="line-31"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-comment'>--</span>
<a name="line-32"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-comment'>-- If successfully returning a value, we just require that its type has</span>
<a name="line-33"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-comment'>-- a 'ToJSON' instance and servant takes care of encoding it for you,</span>
<a name="line-34"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-comment'>-- yielding status code 200 along the way.</span>
<a name="line-35"></a><a name="instance%20HasServer%20(Get%20result)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToJSON</span> <span class='hs-varid'>result</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>HasServer</span> <span class='hs-layout'>(</span><span class='hs-conid'>Get</span> <span class='hs-varid'>result</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-36"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-layout'>(</span><span class='hs-conid'>Get</span> <span class='hs-varid'>result</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>EitherT</span> <span class='hs-layout'>(</span><span class='hs-conid'>Int</span><span class='hs-layout'>,</span> <span class='hs-conid'>String</span><span class='hs-layout'>)</span> <span class='hs-conid'>IO</span> <span class='hs-varid'>result</span>
<a name="line-37"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>action</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span>
<a name="line-38"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>null</span> <span class='hs-layout'>(</span><span class='hs-varid'>pathInfo</span> <span class='hs-varid'>request</span><span class='hs-layout'>)</span> <span class='hs-varop'>&amp;&amp;</span> <span class='hs-varid'>requestMethod</span> <span class='hs-varid'>request</span> <span class='hs-varop'>==</span> <span class='hs-varid'>methodGet</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-39"></a> <span class='hs-varid'>e</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>runEitherT</span> <span class='hs-varid'>action</span>
<a name="line-40"></a> <span class='hs-varid'>respond</span> <span class='hs-varop'>.</span> <span class='hs-varid'>succeedWith</span> <span class='hs-varop'>$</span> <span class='hs-keyword'>case</span> <span class='hs-varid'>e</span> <span class='hs-keyword'>of</span>
<a name="line-41"></a> <span class='hs-conid'>Right</span> <span class='hs-varid'>output</span> <span class='hs-keyglyph'>-&gt;</span>
<a name="line-42"></a> <span class='hs-varid'>responseLBS</span> <span class='hs-varid'>ok200</span> <span class='hs-keyglyph'>[</span><span class='hs-layout'>(</span><span class='hs-str'>"Content-Type"</span><span class='hs-layout'>,</span> <span class='hs-str'>"application/json"</span><span class='hs-layout'>)</span><span class='hs-keyglyph'>]</span> <span class='hs-layout'>(</span><span class='hs-varid'>encode</span> <span class='hs-varid'>output</span><span class='hs-layout'>)</span>
<a name="line-43"></a> <span class='hs-conid'>Left</span> <span class='hs-layout'>(</span><span class='hs-varid'>status</span><span class='hs-layout'>,</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-&gt;</span>
<a name="line-44"></a> <span class='hs-varid'>responseLBS</span> <span class='hs-layout'>(</span><span class='hs-varid'>mkStatus</span> <span class='hs-varid'>status</span> <span class='hs-layout'>(</span><span class='hs-varid'>cs</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <span class='hs-conid'>[]</span> <span class='hs-layout'>(</span><span class='hs-varid'>cs</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span>
<a name="line-45"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>null</span> <span class='hs-layout'>(</span><span class='hs-varid'>pathInfo</span> <span class='hs-varid'>request</span><span class='hs-layout'>)</span> <span class='hs-varop'>&amp;&amp;</span> <span class='hs-varid'>requestMethod</span> <span class='hs-varid'>request</span> <span class='hs-varop'>/=</span> <span class='hs-varid'>methodGet</span> <span class='hs-keyglyph'>=</span>
<a name="line-46"></a> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>WrongMethod</span>
<a name="line-47"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>otherwise</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>NotFound</span>
</pre></body>
</html>

View file

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API/Header.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE PolyKinds #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE TypeOperators #-}</span>
<a name="line-4"></a><span class='hs-comment'>{-# LANGUAGE FlexibleInstances #-}</span>
<a name="line-5"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-6"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Header</span> <span class='hs-keyword'>where</span>
<a name="line-7"></a>
<a name="line-8"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-9"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>String</span>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Text</span><span class='hs-varop'>.</span><span class='hs-conid'>Encoding</span> <span class='hs-layout'>(</span><span class='hs-varid'>decodeUtf8</span><span class='hs-layout'>)</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>GHC</span><span class='hs-varop'>.</span><span class='hs-conid'>TypeLits</span>
<a name="line-12"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span>
<a name="line-13"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Sub</span>
<a name="line-14"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Text</span>
<a name="line-15"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-16"></a>
<a name="line-17"></a><a name="HasServer"></a><span class='hs-comment'>-- | Extract the given header's value as a value of type @a@.</span>
<a name="line-18"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-19"></a><a name="HasServer"></a><span class='hs-comment'>-- Example:</span>
<a name="line-20"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-21"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; newtype Referer = Referer Text</span>
<a name="line-22"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; deriving (Eq, Show, FromText, ToText)</span>
<a name="line-23"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-24"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; -- GET /view-my-referer</span>
<a name="line-25"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; type MyApi = "view-my-referer" :&gt; Header "from" Referer :&gt; Get Referer</span>
<a name="line-26"></a><a name="HasServer"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>Header</span> <span class='hs-varid'>sym</span> <span class='hs-varid'>a</span>
<a name="line-27"></a>
<a name="line-28"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- | If you use 'Header' in one of the endpoints for your API,</span>
<a name="line-29"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- this automatically requires your server-side handler to be a function</span>
<a name="line-30"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- that takes an argument of the type specified by 'Header'.</span>
<a name="line-31"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- This lets servant worry about extracting it from the request and turning</span>
<a name="line-32"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- it into a value of the type you specify.</span>
<a name="line-33"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-34"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- All it asks is for a 'FromText' instance.</span>
<a name="line-35"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-36"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- Example:</span>
<a name="line-37"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-38"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; newtype Referer = Referer Text</span>
<a name="line-39"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; deriving (Eq, Show, FromText, ToText)</span>
<a name="line-40"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-41"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; -- GET /view-my-referer</span>
<a name="line-42"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; type MyApi = "view-my-referer" :&gt; Header "Referer" Referer :&gt; Get Referer</span>
<a name="line-43"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-44"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server :: Server MyApi</span>
<a name="line-45"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server = viewReferer</span>
<a name="line-46"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; where viewReferer :: Referer -&gt; EitherT (Int, String) IO referer</span>
<a name="line-47"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; viewReferer referer = return referer</span>
<a name="line-48"></a><a name="instance%20HasServer%20(Header%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>KnownSymbol</span> <span class='hs-varid'>sym</span><span class='hs-layout'>,</span> <span class='hs-conid'>FromText</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasServer</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span>
<a name="line-49"></a> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>HasServer</span> <span class='hs-layout'>(</span><span class='hs-conid'>Header</span> <span class='hs-varid'>sym</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-50"></a>
<a name="line-51"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-layout'>(</span><span class='hs-conid'>Header</span> <span class='hs-varid'>sym</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span>
<a name="line-52"></a> <span class='hs-conid'>Maybe</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>sublayout</span>
<a name="line-53"></a>
<a name="line-54"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>subserver</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-55"></a> <span class='hs-keyword'>let</span> <span class='hs-varid'>mheader</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>fromText</span> <span class='hs-varop'>.</span> <span class='hs-varid'>decodeUtf8</span> <span class='hs-varop'>=&lt;&lt;</span> <span class='hs-varid'>lookup</span> <span class='hs-varid'>str</span> <span class='hs-layout'>(</span><span class='hs-varid'>requestHeaders</span> <span class='hs-varid'>request</span><span class='hs-layout'>)</span>
<a name="line-56"></a> <span class='hs-varid'>route</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>subserver</span> <span class='hs-varid'>mheader</span><span class='hs-layout'>)</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span>
<a name="line-57"></a>
<a name="line-58"></a> <span class='hs-keyword'>where</span> <span class='hs-varid'>str</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>fromString</span> <span class='hs-varop'>$</span> <span class='hs-varid'>symbolVal</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>sym</span><span class='hs-layout'>)</span>
</pre></body>
</html>

64
src/Servant-API-Post.html Normal file
View file

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API/Post.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE OverloadedStrings #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-4"></a><span class='hs-comment'>{-# LANGUAGE DeriveDataTypeable #-}</span>
<a name="line-5"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Post</span> <span class='hs-keyword'>where</span>
<a name="line-6"></a>
<a name="line-7"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Either</span>
<a name="line-8"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Aeson</span>
<a name="line-9"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>String</span><span class='hs-varop'>.</span><span class='hs-conid'>Conversions</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Typeable</span>
<a name="line-12"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>HTTP</span><span class='hs-varop'>.</span><span class='hs-conid'>Types</span>
<a name="line-13"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span>
<a name="line-14"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-15"></a>
<a name="line-16"></a><a name="HasServer"></a><span class='hs-comment'>-- | Endpoint for POST requests. The type variable represents the type of the</span>
<a name="line-17"></a><a name="HasServer"></a><span class='hs-comment'>-- response body (not the request body, use 'Servant.API.RQBody.RQBody' for</span>
<a name="line-18"></a><a name="HasServer"></a><span class='hs-comment'>-- that).</span>
<a name="line-19"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-20"></a><a name="HasServer"></a><span class='hs-comment'>-- Example:</span>
<a name="line-21"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-22"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; -- POST /books</span>
<a name="line-23"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; -- with a JSON encoded Book as the request body</span>
<a name="line-24"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; -- returning the just-created Book</span>
<a name="line-25"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; ReqBody Book :&gt; Post Book</span>
<a name="line-26"></a><a name="HasServer"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>Post</span> <span class='hs-varid'>a</span>
<a name="line-27"></a> <span class='hs-keyword'>deriving</span> <span class='hs-conid'>Typeable</span>
<a name="line-28"></a>
<a name="line-29"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-comment'>-- | When implementing the handler for a 'Post' endpoint,</span>
<a name="line-30"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-comment'>-- just like for 'Servant.API.Delete.Delete', 'Servant.API.Get.Get'</span>
<a name="line-31"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-comment'>-- and 'Servant.API.Put.Put', the handler code runs in the</span>
<a name="line-32"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-comment'>-- @EitherT (Int, String) IO@ monad, where the 'Int' represents</span>
<a name="line-33"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-comment'>-- the status code and the 'String' a message, returned in case of</span>
<a name="line-34"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-comment'>-- failure. You can quite handily use 'Control.Monad.Trans.EitherT.left'</span>
<a name="line-35"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-comment'>-- to quickly fail if some conditions are not met.</span>
<a name="line-36"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-comment'>--</span>
<a name="line-37"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-comment'>-- If successfully returning a value, we just require that its type has</span>
<a name="line-38"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-comment'>-- a 'ToJSON' instance and servant takes care of encoding it for you,</span>
<a name="line-39"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-comment'>-- yielding status code 201 along the way.</span>
<a name="line-40"></a><a name="instance%20HasServer%20(Post%20a)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToJSON</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>HasServer</span> <span class='hs-layout'>(</span><span class='hs-conid'>Post</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-41"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-layout'>(</span><span class='hs-conid'>Post</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>EitherT</span> <span class='hs-layout'>(</span><span class='hs-conid'>Int</span><span class='hs-layout'>,</span> <span class='hs-conid'>String</span><span class='hs-layout'>)</span> <span class='hs-conid'>IO</span> <span class='hs-varid'>a</span>
<a name="line-42"></a>
<a name="line-43"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>action</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span>
<a name="line-44"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>null</span> <span class='hs-layout'>(</span><span class='hs-varid'>pathInfo</span> <span class='hs-varid'>request</span><span class='hs-layout'>)</span> <span class='hs-varop'>&amp;&amp;</span> <span class='hs-varid'>requestMethod</span> <span class='hs-varid'>request</span> <span class='hs-varop'>==</span> <span class='hs-varid'>methodPost</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-45"></a> <span class='hs-varid'>e</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>runEitherT</span> <span class='hs-varid'>action</span>
<a name="line-46"></a> <span class='hs-varid'>respond</span> <span class='hs-varop'>.</span> <span class='hs-varid'>succeedWith</span> <span class='hs-varop'>$</span> <span class='hs-keyword'>case</span> <span class='hs-varid'>e</span> <span class='hs-keyword'>of</span>
<a name="line-47"></a> <span class='hs-conid'>Right</span> <span class='hs-varid'>out</span> <span class='hs-keyglyph'>-&gt;</span>
<a name="line-48"></a> <span class='hs-varid'>responseLBS</span> <span class='hs-varid'>status201</span> <span class='hs-keyglyph'>[</span><span class='hs-layout'>(</span><span class='hs-str'>"Content-Type"</span><span class='hs-layout'>,</span> <span class='hs-str'>"application/json"</span><span class='hs-layout'>)</span><span class='hs-keyglyph'>]</span> <span class='hs-layout'>(</span><span class='hs-varid'>encode</span> <span class='hs-varid'>out</span><span class='hs-layout'>)</span>
<a name="line-49"></a> <span class='hs-conid'>Left</span> <span class='hs-layout'>(</span><span class='hs-varid'>status</span><span class='hs-layout'>,</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-&gt;</span>
<a name="line-50"></a> <span class='hs-varid'>responseLBS</span> <span class='hs-layout'>(</span><span class='hs-varid'>mkStatus</span> <span class='hs-varid'>status</span> <span class='hs-layout'>(</span><span class='hs-varid'>cs</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <span class='hs-conid'>[]</span> <span class='hs-layout'>(</span><span class='hs-varid'>cs</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span>
<a name="line-51"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>null</span> <span class='hs-layout'>(</span><span class='hs-varid'>pathInfo</span> <span class='hs-varid'>request</span><span class='hs-layout'>)</span> <span class='hs-varop'>&amp;&amp;</span> <span class='hs-varid'>requestMethod</span> <span class='hs-varid'>request</span> <span class='hs-varop'>/=</span> <span class='hs-varid'>methodPost</span> <span class='hs-keyglyph'>=</span>
<a name="line-52"></a> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>WrongMethod</span>
<a name="line-53"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>otherwise</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>NotFound</span>
</pre></body>
</html>

63
src/Servant-API-Put.html Normal file
View file

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API/Put.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE OverloadedStrings #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-4"></a><span class='hs-comment'>{-# LANGUAGE DeriveDataTypeable #-}</span>
<a name="line-5"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Put</span> <span class='hs-keyword'>where</span>
<a name="line-6"></a>
<a name="line-7"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Either</span>
<a name="line-8"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Aeson</span>
<a name="line-9"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>String</span><span class='hs-varop'>.</span><span class='hs-conid'>Conversions</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Typeable</span>
<a name="line-12"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>HTTP</span><span class='hs-varop'>.</span><span class='hs-conid'>Types</span>
<a name="line-13"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span>
<a name="line-14"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-15"></a>
<a name="line-16"></a><a name="HasServer"></a><span class='hs-comment'>-- | Endpoint for PUT requests, usually used to update a ressource.</span>
<a name="line-17"></a><a name="HasServer"></a><span class='hs-comment'>-- The type @a@ is the type of the response body that's returned.</span>
<a name="line-18"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-19"></a><a name="HasServer"></a><span class='hs-comment'>-- Example:</span>
<a name="line-20"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-21"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; -- PUT /books/:isbn</span>
<a name="line-22"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; -- with a Book as request body, returning the updated Book</span>
<a name="line-23"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; Capture "isbn" Text :&gt; ReqBody Book :&gt; Put Book</span>
<a name="line-24"></a><a name="HasServer"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>Put</span> <span class='hs-varid'>a</span>
<a name="line-25"></a> <span class='hs-keyword'>deriving</span> <span class='hs-conid'>Typeable</span>
<a name="line-26"></a>
<a name="line-27"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-comment'>-- | When implementing the handler for a 'Put' endpoint,</span>
<a name="line-28"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-comment'>-- just like for 'Servant.API.Delete.Delete', 'Servant.API.Get.Get'</span>
<a name="line-29"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-comment'>-- and 'Servant.API.Post.Post', the handler code runs in the</span>
<a name="line-30"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-comment'>-- @EitherT (Int, String) IO@ monad, where the 'Int' represents</span>
<a name="line-31"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-comment'>-- the status code and the 'String' a message, returned in case of</span>
<a name="line-32"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-comment'>-- failure. You can quite handily use 'Control.Monad.Trans.EitherT.left'</span>
<a name="line-33"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-comment'>-- to quickly fail if some conditions are not met.</span>
<a name="line-34"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-comment'>--</span>
<a name="line-35"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-comment'>-- If successfully returning a value, we just require that its type has</span>
<a name="line-36"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-comment'>-- a 'ToJSON' instance and servant takes care of encoding it for you,</span>
<a name="line-37"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-comment'>-- yielding status code 200 along the way.</span>
<a name="line-38"></a><a name="instance%20HasServer%20(Put%20a)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToJSON</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>HasServer</span> <span class='hs-layout'>(</span><span class='hs-conid'>Put</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-39"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-layout'>(</span><span class='hs-conid'>Put</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>EitherT</span> <span class='hs-layout'>(</span><span class='hs-conid'>Int</span><span class='hs-layout'>,</span> <span class='hs-conid'>String</span><span class='hs-layout'>)</span> <span class='hs-conid'>IO</span> <span class='hs-varid'>a</span>
<a name="line-40"></a>
<a name="line-41"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>action</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span>
<a name="line-42"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>null</span> <span class='hs-layout'>(</span><span class='hs-varid'>pathInfo</span> <span class='hs-varid'>request</span><span class='hs-layout'>)</span> <span class='hs-varop'>&amp;&amp;</span> <span class='hs-varid'>requestMethod</span> <span class='hs-varid'>request</span> <span class='hs-varop'>==</span> <span class='hs-varid'>methodPut</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-43"></a> <span class='hs-varid'>e</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>runEitherT</span> <span class='hs-varid'>action</span>
<a name="line-44"></a> <span class='hs-varid'>respond</span> <span class='hs-varop'>.</span> <span class='hs-varid'>succeedWith</span> <span class='hs-varop'>$</span> <span class='hs-keyword'>case</span> <span class='hs-varid'>e</span> <span class='hs-keyword'>of</span>
<a name="line-45"></a> <span class='hs-conid'>Right</span> <span class='hs-varid'>out</span> <span class='hs-keyglyph'>-&gt;</span>
<a name="line-46"></a> <span class='hs-varid'>responseLBS</span> <span class='hs-varid'>ok200</span> <span class='hs-keyglyph'>[</span><span class='hs-layout'>(</span><span class='hs-str'>"Content-Type"</span><span class='hs-layout'>,</span> <span class='hs-str'>"application/json"</span><span class='hs-layout'>)</span><span class='hs-keyglyph'>]</span> <span class='hs-layout'>(</span><span class='hs-varid'>encode</span> <span class='hs-varid'>out</span><span class='hs-layout'>)</span>
<a name="line-47"></a> <span class='hs-conid'>Left</span> <span class='hs-layout'>(</span><span class='hs-varid'>status</span><span class='hs-layout'>,</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-&gt;</span>
<a name="line-48"></a> <span class='hs-varid'>responseLBS</span> <span class='hs-layout'>(</span><span class='hs-varid'>mkStatus</span> <span class='hs-varid'>status</span> <span class='hs-layout'>(</span><span class='hs-varid'>cs</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <span class='hs-conid'>[]</span> <span class='hs-layout'>(</span><span class='hs-varid'>cs</span> <span class='hs-varid'>message</span><span class='hs-layout'>)</span>
<a name="line-49"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>null</span> <span class='hs-layout'>(</span><span class='hs-varid'>pathInfo</span> <span class='hs-varid'>request</span><span class='hs-layout'>)</span> <span class='hs-varop'>&amp;&amp;</span> <span class='hs-varid'>requestMethod</span> <span class='hs-varid'>request</span> <span class='hs-varop'>/=</span> <span class='hs-varid'>methodPut</span> <span class='hs-keyglyph'>=</span>
<a name="line-50"></a> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>WrongMethod</span>
<a name="line-51"></a>
<a name="line-52"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>otherwise</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>NotFound</span>
</pre></body>
</html>

View file

@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API/QueryParam.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE PolyKinds #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE TypeOperators #-}</span>
<a name="line-4"></a><span class='hs-comment'>{-# LANGUAGE FlexibleContexts #-}</span>
<a name="line-5"></a><span class='hs-comment'>{-# LANGUAGE FlexibleInstances #-}</span>
<a name="line-6"></a><span class='hs-comment'>{-# LANGUAGE OverloadedStrings #-}</span>
<a name="line-7"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-8"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>QueryParam</span> <span class='hs-keyword'>where</span>
<a name="line-9"></a>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Maybe</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-12"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>String</span><span class='hs-varop'>.</span><span class='hs-conid'>Conversions</span>
<a name="line-13"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>GHC</span><span class='hs-varop'>.</span><span class='hs-conid'>TypeLits</span>
<a name="line-14"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>HTTP</span><span class='hs-varop'>.</span><span class='hs-conid'>Types</span>
<a name="line-15"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span>
<a name="line-16"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Sub</span>
<a name="line-17"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Text</span>
<a name="line-18"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-19"></a>
<a name="line-20"></a><a name="HasServer"></a><span class='hs-comment'>-- | Lookup the value associated to the @sym@ query string parameter</span>
<a name="line-21"></a><a name="HasServer"></a><span class='hs-comment'>-- and try to extract it as a value of type @a@.</span>
<a name="line-22"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-23"></a><a name="HasServer"></a><span class='hs-comment'>-- Example:</span>
<a name="line-24"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-25"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; -- /books?author=&lt;author name&gt;</span>
<a name="line-26"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; QueryParam "author" Text :&gt; Get [Book]</span>
<a name="line-27"></a><a name="HasServer"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>QueryParam</span> <span class='hs-varid'>sym</span> <span class='hs-varid'>a</span>
<a name="line-28"></a>
<a name="line-29"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- | If you use @'QueryParam' "author" Text@ in one of the endpoints for your API,</span>
<a name="line-30"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- this automatically requires your server-side handler to be a function</span>
<a name="line-31"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- that takes an argument of type @'Maybe' 'Text'@.</span>
<a name="line-32"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-33"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- This lets servant worry about looking it up in the query string</span>
<a name="line-34"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- and turning it into a value of the type you specify, enclosed</span>
<a name="line-35"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- in 'Maybe', because it may not be there and servant would then</span>
<a name="line-36"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- hand you 'Nothing'.</span>
<a name="line-37"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-38"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- You can control how it'll be converted from 'Text' to your type</span>
<a name="line-39"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- by simply providing an instance of 'FromText' for your type.</span>
<a name="line-40"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-41"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- Example:</span>
<a name="line-42"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-43"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; QueryParam "author" Text :&gt; Get [Book]</span>
<a name="line-44"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-45"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server :: Server MyApi</span>
<a name="line-46"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server = getBooksBy</span>
<a name="line-47"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; where getBooksBy :: Maybe Text -&gt; EitherT (Int, String) IO [Book]</span>
<a name="line-48"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; getBooksBy Nothing = ...return all books...</span>
<a name="line-49"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; getBooksBy (Just author) = ...return books by the given author...</span>
<a name="line-50"></a><a name="instance%20HasServer%20(QueryParam%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>KnownSymbol</span> <span class='hs-varid'>sym</span><span class='hs-layout'>,</span> <span class='hs-conid'>FromText</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasServer</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span>
<a name="line-51"></a> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>HasServer</span> <span class='hs-layout'>(</span><span class='hs-conid'>QueryParam</span> <span class='hs-varid'>sym</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-52"></a>
<a name="line-53"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-layout'>(</span><span class='hs-conid'>QueryParam</span> <span class='hs-varid'>sym</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span>
<a name="line-54"></a> <span class='hs-conid'>Maybe</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>sublayout</span>
<a name="line-55"></a>
<a name="line-56"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>subserver</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-57"></a> <span class='hs-keyword'>let</span> <span class='hs-varid'>querytext</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>parseQueryText</span> <span class='hs-varop'>$</span> <span class='hs-varid'>rawQueryString</span> <span class='hs-varid'>request</span>
<a name="line-58"></a> <span class='hs-varid'>param</span> <span class='hs-keyglyph'>=</span>
<a name="line-59"></a> <span class='hs-keyword'>case</span> <span class='hs-varid'>lookup</span> <span class='hs-varid'>paramname</span> <span class='hs-varid'>querytext</span> <span class='hs-keyword'>of</span>
<a name="line-60"></a> <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Nothing</span> <span class='hs-comment'>-- param absent from the query string</span>
<a name="line-61"></a> <span class='hs-conid'>Just</span> <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Nothing</span> <span class='hs-comment'>-- param present with no value -&gt; Nothing</span>
<a name="line-62"></a> <span class='hs-conid'>Just</span> <span class='hs-layout'>(</span><span class='hs-conid'>Just</span> <span class='hs-varid'>v</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>fromText</span> <span class='hs-varid'>v</span> <span class='hs-comment'>-- if present, we try to convert to</span>
<a name="line-63"></a> <span class='hs-comment'>-- the right type</span>
<a name="line-64"></a>
<a name="line-65"></a> <span class='hs-varid'>route</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>subserver</span> <span class='hs-varid'>param</span><span class='hs-layout'>)</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span>
<a name="line-66"></a>
<a name="line-67"></a> <span class='hs-keyword'>where</span> <span class='hs-varid'>paramname</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>$</span> <span class='hs-varid'>symbolVal</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>sym</span><span class='hs-layout'>)</span>
<a name="line-68"></a>
<a name="line-69"></a><a name="HasServer"></a><span class='hs-comment'>-- | Lookup the values associated to the @sym@ query string parameter</span>
<a name="line-70"></a><a name="HasServer"></a><span class='hs-comment'>-- and try to extract it as a value of type @[a]@. This is typically</span>
<a name="line-71"></a><a name="HasServer"></a><span class='hs-comment'>-- meant to support query string parameters of the form</span>
<a name="line-72"></a><a name="HasServer"></a><span class='hs-comment'>-- @param[]=val1&amp;param[]=val2@ and so on. Note that servant doesn't actually</span>
<a name="line-73"></a><a name="HasServer"></a><span class='hs-comment'>-- require the @[]@s and will fetch the values just fine with</span>
<a name="line-74"></a><a name="HasServer"></a><span class='hs-comment'>-- @param=val1&amp;param=val2@, too.</span>
<a name="line-75"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-76"></a><a name="HasServer"></a><span class='hs-comment'>-- Example:</span>
<a name="line-77"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-78"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; -- /books?authors[]=&lt;author1&gt;&amp;authors[]=&lt;author2&gt;&amp;...</span>
<a name="line-79"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; QueryParams "authors" Text :&gt; Get [Book]</span>
<a name="line-80"></a><a name="HasServer"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>QueryParams</span> <span class='hs-varid'>sym</span> <span class='hs-varid'>a</span>
<a name="line-81"></a>
<a name="line-82"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- | If you use @'QueryParams' "authors" Text@ in one of the endpoints for your API,</span>
<a name="line-83"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- this automatically requires your server-side handler to be a function</span>
<a name="line-84"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- that takes an argument of type @['Text']@.</span>
<a name="line-85"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-86"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- This lets servant worry about looking up 0 or more values in the query string</span>
<a name="line-87"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- associated to @authors@ and turning each of them into a value of</span>
<a name="line-88"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- the type you specify.</span>
<a name="line-89"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-90"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- You can control how the individual values are converted from 'Text' to your type</span>
<a name="line-91"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- by simply providing an instance of 'FromText' for your type.</span>
<a name="line-92"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-93"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- Example:</span>
<a name="line-94"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-95"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; QueryParams "authors" Text :&gt; Get [Book]</span>
<a name="line-96"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-97"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server :: Server MyApi</span>
<a name="line-98"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server = getBooksBy</span>
<a name="line-99"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; where getBooksBy :: [Text] -&gt; EitherT (Int, String) IO [Book]</span>
<a name="line-100"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; getBooksBy authors = ...return all books by these authors...</span>
<a name="line-101"></a><a name="instance%20HasServer%20(QueryParams%20sym%20a%20:%3e%20sublayout)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>KnownSymbol</span> <span class='hs-varid'>sym</span><span class='hs-layout'>,</span> <span class='hs-conid'>FromText</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasServer</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span>
<a name="line-102"></a> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>HasServer</span> <span class='hs-layout'>(</span><span class='hs-conid'>QueryParams</span> <span class='hs-varid'>sym</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-103"></a>
<a name="line-104"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-layout'>(</span><span class='hs-conid'>QueryParams</span> <span class='hs-varid'>sym</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span>
<a name="line-105"></a> <span class='hs-keyglyph'>[</span><span class='hs-varid'>a</span><span class='hs-keyglyph'>]</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>sublayout</span>
<a name="line-106"></a>
<a name="line-107"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>subserver</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-108"></a> <span class='hs-keyword'>let</span> <span class='hs-varid'>querytext</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>parseQueryText</span> <span class='hs-varop'>$</span> <span class='hs-varid'>rawQueryString</span> <span class='hs-varid'>request</span>
<a name="line-109"></a> <span class='hs-comment'>-- if sym is "foo", we look for query string parameters</span>
<a name="line-110"></a> <span class='hs-comment'>-- named "foo" or "foo[]" and call fromText on the</span>
<a name="line-111"></a> <span class='hs-comment'>-- corresponding values</span>
<a name="line-112"></a> <span class='hs-varid'>parameters</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>filter</span> <span class='hs-varid'>looksLikeParam</span> <span class='hs-varid'>querytext</span>
<a name="line-113"></a> <span class='hs-varid'>values</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>catMaybes</span> <span class='hs-varop'>$</span> <span class='hs-varid'>map</span> <span class='hs-layout'>(</span><span class='hs-varid'>convert</span> <span class='hs-varop'>.</span> <span class='hs-varid'>snd</span><span class='hs-layout'>)</span> <span class='hs-varid'>parameters</span>
<a name="line-114"></a>
<a name="line-115"></a> <span class='hs-varid'>route</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>subserver</span> <span class='hs-varid'>values</span><span class='hs-layout'>)</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span>
<a name="line-116"></a>
<a name="line-117"></a> <span class='hs-keyword'>where</span> <span class='hs-varid'>paramname</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>$</span> <span class='hs-varid'>symbolVal</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>sym</span><span class='hs-layout'>)</span>
<a name="line-118"></a> <span class='hs-varid'>looksLikeParam</span> <span class='hs-layout'>(</span><span class='hs-varid'>name</span><span class='hs-layout'>,</span> <span class='hs-keyword'>_</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>name</span> <span class='hs-varop'>==</span> <span class='hs-varid'>paramname</span> <span class='hs-varop'>||</span> <span class='hs-varid'>name</span> <span class='hs-varop'>==</span> <span class='hs-layout'>(</span><span class='hs-varid'>paramname</span> <span class='hs-varop'>&lt;&gt;</span> <span class='hs-str'>"[]"</span><span class='hs-layout'>)</span>
<a name="line-119"></a> <span class='hs-varid'>convert</span> <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Nothing</span>
<a name="line-120"></a> <span class='hs-varid'>convert</span> <span class='hs-layout'>(</span><span class='hs-conid'>Just</span> <span class='hs-varid'>v</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>fromText</span> <span class='hs-varid'>v</span>
<a name="line-121"></a>
<a name="line-122"></a><a name="HasServer"></a><span class='hs-comment'>-- | Lookup a potentially value-less query string parameter</span>
<a name="line-123"></a><a name="HasServer"></a><span class='hs-comment'>-- with boolean semantics. If the param @sym@ is there without any value,</span>
<a name="line-124"></a><a name="HasServer"></a><span class='hs-comment'>-- or if it's there with value "true" or "1", it's interpreted as 'True'.</span>
<a name="line-125"></a><a name="HasServer"></a><span class='hs-comment'>-- Otherwise, it's interpreted as 'False'.</span>
<a name="line-126"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-127"></a><a name="HasServer"></a><span class='hs-comment'>-- Example:</span>
<a name="line-128"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-129"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; -- /books?published</span>
<a name="line-130"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; QueryFlag "published" :&gt; Get [Book]</span>
<a name="line-131"></a><a name="HasServer"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>QueryFlag</span> <span class='hs-varid'>sym</span>
<a name="line-132"></a>
<a name="line-133"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>-- | If you use @'QueryFlag' "published"@ in one of the endpoints for your API,</span>
<a name="line-134"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>-- this automatically requires your server-side handler to be a function</span>
<a name="line-135"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>-- that takes an argument of type 'Bool'.</span>
<a name="line-136"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-137"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>-- Example:</span>
<a name="line-138"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-139"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; QueryFlag "published" :&gt; Get [Book]</span>
<a name="line-140"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-141"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server :: Server MyApi</span>
<a name="line-142"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server = getBooks</span>
<a name="line-143"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; where getBooks :: Bool -&gt; EitherT (Int, String) IO [Book]</span>
<a name="line-144"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument...</span>
<a name="line-145"></a><a name="instance%20HasServer%20(QueryFlag%20sym%20:%3e%20sublayout)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>KnownSymbol</span> <span class='hs-varid'>sym</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasServer</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span>
<a name="line-146"></a> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>HasServer</span> <span class='hs-layout'>(</span><span class='hs-conid'>QueryFlag</span> <span class='hs-varid'>sym</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-147"></a>
<a name="line-148"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-layout'>(</span><span class='hs-conid'>QueryFlag</span> <span class='hs-varid'>sym</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span>
<a name="line-149"></a> <span class='hs-conid'>Bool</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>sublayout</span>
<a name="line-150"></a>
<a name="line-151"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>subserver</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-152"></a> <span class='hs-keyword'>let</span> <span class='hs-varid'>querytext</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>parseQueryText</span> <span class='hs-varop'>$</span> <span class='hs-varid'>rawQueryString</span> <span class='hs-varid'>request</span>
<a name="line-153"></a> <span class='hs-varid'>param</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>case</span> <span class='hs-varid'>lookup</span> <span class='hs-varid'>paramname</span> <span class='hs-varid'>querytext</span> <span class='hs-keyword'>of</span>
<a name="line-154"></a> <span class='hs-conid'>Just</span> <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>True</span> <span class='hs-comment'>-- param is there, with no value</span>
<a name="line-155"></a> <span class='hs-conid'>Just</span> <span class='hs-layout'>(</span><span class='hs-conid'>Just</span> <span class='hs-varid'>v</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>examine</span> <span class='hs-varid'>v</span> <span class='hs-comment'>-- param with a value</span>
<a name="line-156"></a> <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>False</span> <span class='hs-comment'>-- param not in the query string</span>
<a name="line-157"></a>
<a name="line-158"></a> <span class='hs-varid'>route</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>subserver</span> <span class='hs-varid'>param</span><span class='hs-layout'>)</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span>
<a name="line-159"></a>
<a name="line-160"></a> <span class='hs-keyword'>where</span> <span class='hs-varid'>paramname</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>$</span> <span class='hs-varid'>symbolVal</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>sym</span><span class='hs-layout'>)</span>
<a name="line-161"></a> <span class='hs-varid'>examine</span> <span class='hs-varid'>v</span> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>v</span> <span class='hs-varop'>==</span> <span class='hs-str'>"true"</span> <span class='hs-varop'>||</span> <span class='hs-varid'>v</span> <span class='hs-varop'>==</span> <span class='hs-str'>"1"</span> <span class='hs-varop'>||</span> <span class='hs-varid'>v</span> <span class='hs-varop'>==</span> <span class='hs-str'>""</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>True</span>
<a name="line-162"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>otherwise</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>False</span>
</pre></body>
</html>

43
src/Servant-API-Raw.html Normal file
View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API/Raw.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE InstanceSigs #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE OverloadedStrings #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-4"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Raw</span> <span class='hs-keyword'>where</span>
<a name="line-5"></a>
<a name="line-6"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-7"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span>
<a name="line-8"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-9"></a>
<a name="line-10"></a><a name="Raw"></a><span class='hs-comment'>-- | Endpoint for plugging in your own Wai 'Application's.</span>
<a name="line-11"></a><a name="Raw"></a><span class='hs-comment'>--</span>
<a name="line-12"></a><a name="Raw"></a><span class='hs-comment'>-- The given 'Application' will get the request as received by the server, potentially with</span>
<a name="line-13"></a><a name="Raw"></a><span class='hs-comment'>-- a modified (stripped) 'pathInfo' if the 'Application' is being routed with 'Servant.API.Sub.:&gt;'.</span>
<a name="line-14"></a><a name="Raw"></a><span class='hs-comment'>--</span>
<a name="line-15"></a><a name="Raw"></a><span class='hs-comment'>-- In addition to just letting you plug in your existing WAI 'Application's,</span>
<a name="line-16"></a><a name="Raw"></a><span class='hs-comment'>-- this can also be used with 'Servant.Utils.StaticFiles.serveDirectory' to serve</span>
<a name="line-17"></a><a name="Raw"></a><span class='hs-comment'>-- static files stored in a particular directory on your filesystem, or to serve</span>
<a name="line-18"></a><a name="Raw"></a><span class='hs-comment'>-- your API's documentation with 'Servant.Utils.StaticFiles.serveDocumentation'.</span>
<a name="line-19"></a><a name="Raw"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>Raw</span>
<a name="line-20"></a>
<a name="line-21"></a><a name="instance%20HasServer%20Raw"></a><span class='hs-comment'>-- | Just pass the request to the underlying application and serve its response.</span>
<a name="line-22"></a><a name="instance%20HasServer%20Raw"></a><span class='hs-comment'>--</span>
<a name="line-23"></a><a name="instance%20HasServer%20Raw"></a><span class='hs-comment'>-- Example:</span>
<a name="line-24"></a><a name="instance%20HasServer%20Raw"></a><span class='hs-comment'>--</span>
<a name="line-25"></a><a name="instance%20HasServer%20Raw"></a><span class='hs-comment'>-- &gt; type MyApi = "images" :&gt; Raw</span>
<a name="line-26"></a><a name="instance%20HasServer%20Raw"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-27"></a><a name="instance%20HasServer%20Raw"></a><span class='hs-comment'>-- &gt; server :: Server MyApi</span>
<a name="line-28"></a><a name="instance%20HasServer%20Raw"></a><span class='hs-comment'>-- &gt; server = serveDirectory "/var/www/images"</span>
<a name="line-29"></a><a name="instance%20HasServer%20Raw"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasServer</span> <span class='hs-conid'>Raw</span> <span class='hs-keyword'>where</span>
<a name="line-30"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-conid'>Raw</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Application</span>
<a name="line-31"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>rawApplication</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span> <span class='hs-keyglyph'>=</span>
<a name="line-32"></a> <span class='hs-varid'>rawApplication</span> <span class='hs-varid'>request</span> <span class='hs-layout'>(</span><span class='hs-varid'>respond</span> <span class='hs-varop'>.</span> <span class='hs-varid'>succeedWith</span><span class='hs-layout'>)</span>
</pre></body>
</html>

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API/ReqBody.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE PolyKinds #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE TypeOperators #-}</span>
<a name="line-4"></a><span class='hs-comment'>{-# LANGUAGE FlexibleInstances #-}</span>
<a name="line-5"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-6"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>ReqBody</span> <span class='hs-keyword'>where</span>
<a name="line-7"></a>
<a name="line-8"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Applicative</span>
<a name="line-9"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Aeson</span>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span>
<a name="line-12"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Sub</span>
<a name="line-13"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-14"></a>
<a name="line-15"></a><a name="HasServer"></a><span class='hs-comment'>-- | Extract the request body as a value of type @a@.</span>
<a name="line-16"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-17"></a><a name="HasServer"></a><span class='hs-comment'>-- Example:</span>
<a name="line-18"></a><a name="HasServer"></a><span class='hs-comment'>--</span>
<a name="line-19"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; -- POST /books</span>
<a name="line-20"></a><a name="HasServer"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; ReqBody Book :&gt; Post Book</span>
<a name="line-21"></a><a name="HasServer"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>ReqBody</span> <span class='hs-varid'>a</span>
<a name="line-22"></a>
<a name="line-23"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- | If you use 'ReqBody' in one of the endpoints for your API,</span>
<a name="line-24"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- this automatically requires your server-side handler to be a function</span>
<a name="line-25"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- that takes an argument of the type specified by 'ReqBody'.</span>
<a name="line-26"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- This lets servant worry about extracting it from the request and turning</span>
<a name="line-27"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- it into a value of the type you specify.</span>
<a name="line-28"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-29"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- All it asks is for a 'FromJSON' instance.</span>
<a name="line-30"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-31"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- Example:</span>
<a name="line-32"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>--</span>
<a name="line-33"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; ReqBody Book :&gt; Post Book</span>
<a name="line-34"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-35"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server :: Server MyApi</span>
<a name="line-36"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; server = postBook</span>
<a name="line-37"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; where postBook :: Book -&gt; EitherT (Int, String) IO Book</span>
<a name="line-38"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-comment'>-- &gt; postBook book = ...insert into your db...</span>
<a name="line-39"></a><a name="instance%20HasServer%20(ReqBody%20a%20:%3e%20sublayout)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>FromJSON</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasServer</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span>
<a name="line-40"></a> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>HasServer</span> <span class='hs-layout'>(</span><span class='hs-conid'>ReqBody</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-41"></a>
<a name="line-42"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-layout'>(</span><span class='hs-conid'>ReqBody</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span>
<a name="line-43"></a> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>sublayout</span>
<a name="line-44"></a>
<a name="line-45"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>subserver</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-46"></a> <span class='hs-varid'>mrqbody</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>decode'</span> <span class='hs-varop'>&lt;$&gt;</span> <span class='hs-varid'>lazyRequestBody</span> <span class='hs-varid'>request</span>
<a name="line-47"></a> <span class='hs-keyword'>case</span> <span class='hs-varid'>mrqbody</span> <span class='hs-keyword'>of</span>
<a name="line-48"></a> <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>InvalidBody</span>
<a name="line-49"></a> <span class='hs-conid'>Just</span> <span class='hs-varid'>v</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>route</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>subserver</span> <span class='hs-varid'>v</span><span class='hs-layout'>)</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span>
</pre></body>
</html>

47
src/Servant-API-Sub.html Normal file
View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API/Sub.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE PolyKinds #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE TypeOperators #-}</span>
<a name="line-4"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-5"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Sub</span> <span class='hs-keyword'>where</span>
<a name="line-6"></a>
<a name="line-7"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-8"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>String</span><span class='hs-varop'>.</span><span class='hs-conid'>Conversions</span>
<a name="line-9"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>GHC</span><span class='hs-varop'>.</span><span class='hs-conid'>TypeLits</span>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-12"></a>
<a name="line-13"></a><span class='hs-comment'>-- | The contained API (second argument) can be found under @("/" ++ path)@</span>
<a name="line-14"></a><span class='hs-comment'>-- (path being the first argument).</span>
<a name="line-15"></a><span class='hs-comment'>--</span>
<a name="line-16"></a><span class='hs-comment'>-- Example:</span>
<a name="line-17"></a><span class='hs-comment'>--</span>
<a name="line-18"></a><span class='hs-comment'>-- &gt; -- GET /hello/world</span>
<a name="line-19"></a><span class='hs-comment'>-- &gt; -- returning a JSON encoded World value</span>
<a name="line-20"></a><span class='hs-comment'>-- &gt; type MyApi = "hello" :&gt; "world" :&gt; Get World</span>
<a name="line-21"></a><span class='hs-keyword'>data</span> <span class='hs-layout'>(</span><span class='hs-varid'>path</span> <span class='hs-keyglyph'>::</span> <span class='hs-varid'>k</span><span class='hs-layout'>)</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>path</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>a</span>
<a name="line-22"></a><span class='hs-keyword'>infixr</span> <span class='hs-num'>9</span> <span class='hs-conop'>:&gt;</span>
<a name="line-23"></a>
<a name="line-24"></a><a name="instance%20HasServer%20(path%20:%3e%20sublayout)"></a><span class='hs-comment'>-- | Make sure the incoming request starts with @"/path"@, strip it and</span>
<a name="line-25"></a><a name="instance%20HasServer%20(path%20:%3e%20sublayout)"></a><span class='hs-comment'>-- pass the rest of the request path to @sublayout@.</span>
<a name="line-26"></a><a name="instance%20HasServer%20(path%20:%3e%20sublayout)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>KnownSymbol</span> <span class='hs-varid'>path</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasServer</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>HasServer</span> <span class='hs-layout'>(</span><span class='hs-varid'>path</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-27"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-layout'>(</span><span class='hs-varid'>path</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>sublayout</span>
<a name="line-28"></a> <span class='hs-varid'>route</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>subserver</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>case</span> <span class='hs-varid'>pathInfo</span> <span class='hs-varid'>request</span> <span class='hs-keyword'>of</span>
<a name="line-29"></a> <span class='hs-layout'>(</span><span class='hs-varid'>first</span> <span class='hs-conop'>:</span> <span class='hs-varid'>rest</span><span class='hs-layout'>)</span>
<a name="line-30"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>first</span> <span class='hs-varop'>==</span> <span class='hs-varid'>cs</span> <span class='hs-layout'>(</span><span class='hs-varid'>symbolVal</span> <span class='hs-varid'>proxyPath</span><span class='hs-layout'>)</span>
<a name="line-31"></a> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>route</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>sublayout</span><span class='hs-layout'>)</span> <span class='hs-varid'>subserver</span> <span class='hs-varid'>request</span><span class='hs-layout'>{</span>
<a name="line-32"></a> <span class='hs-varid'>pathInfo</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>rest</span>
<a name="line-33"></a> <span class='hs-layout'>}</span> <span class='hs-varid'>respond</span>
<a name="line-34"></a> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>failWith</span> <span class='hs-conid'>NotFound</span>
<a name="line-35"></a>
<a name="line-36"></a> <span class='hs-keyword'>where</span> <span class='hs-varid'>proxyPath</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>path</span>
</pre></body>
</html>

65
src/Servant-API.html Normal file
View file

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/API.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span> <span class='hs-layout'>(</span>
<a name="line-2"></a>
<a name="line-3"></a> <span class='hs-comment'>-- * Combinators</span>
<a name="line-4"></a> <span class='hs-comment'>-- | Type-level combinator for expressing subrouting: @':&gt;'@</span>
<a name="line-5"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Sub</span><span class='hs-layout'>,</span>
<a name="line-6"></a> <span class='hs-comment'>-- | Type-level combinator for alternative endpoints: @':&lt;|&gt;'@</span>
<a name="line-7"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Alternative</span><span class='hs-layout'>,</span>
<a name="line-8"></a>
<a name="line-9"></a> <span class='hs-comment'>-- * Accessing information from the request</span>
<a name="line-10"></a> <span class='hs-comment'>-- | Capturing parts of the url path as parsed values: @'Capture'@</span>
<a name="line-11"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Capture</span><span class='hs-layout'>,</span>
<a name="line-12"></a> <span class='hs-comment'>-- | Retrieving specific headers from the request</span>
<a name="line-13"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Header</span><span class='hs-layout'>,</span>
<a name="line-14"></a> <span class='hs-comment'>-- | Retrieving parameters from the query string of the 'URI': @'QueryParam'@</span>
<a name="line-15"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>QueryParam</span><span class='hs-layout'>,</span>
<a name="line-16"></a> <span class='hs-comment'>-- | Accessing the request body as a JSON-encoded type: @'ReqBody'@</span>
<a name="line-17"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>ReqBody</span><span class='hs-layout'>,</span>
<a name="line-18"></a>
<a name="line-19"></a> <span class='hs-comment'>-- * Actual endpoints, distinguished by HTTP method</span>
<a name="line-20"></a> <span class='hs-comment'>-- | GET requests</span>
<a name="line-21"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Get</span><span class='hs-layout'>,</span>
<a name="line-22"></a> <span class='hs-comment'>-- | POST requests</span>
<a name="line-23"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Post</span><span class='hs-layout'>,</span>
<a name="line-24"></a> <span class='hs-comment'>-- | DELETE requests</span>
<a name="line-25"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Delete</span><span class='hs-layout'>,</span>
<a name="line-26"></a> <span class='hs-comment'>-- | PUT requests</span>
<a name="line-27"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Put</span><span class='hs-layout'>,</span>
<a name="line-28"></a>
<a name="line-29"></a> <span class='hs-comment'>-- * Untyped endpoints</span>
<a name="line-30"></a> <span class='hs-comment'>-- | Plugging in a wai 'Network.Wai.Application', serving directories</span>
<a name="line-31"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Raw</span><span class='hs-layout'>,</span>
<a name="line-32"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span><span class='hs-varop'>.</span><span class='hs-conid'>StaticFiles</span><span class='hs-layout'>,</span>
<a name="line-33"></a>
<a name="line-34"></a> <span class='hs-comment'>-- * Utilities</span>
<a name="line-35"></a> <span class='hs-comment'>-- | QuasiQuotes for endpoints</span>
<a name="line-36"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>QQ</span><span class='hs-layout'>,</span>
<a name="line-37"></a> <span class='hs-comment'>-- | Type-safe internal URLs</span>
<a name="line-38"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span><span class='hs-varop'>.</span><span class='hs-conid'>Links</span><span class='hs-layout'>,</span>
<a name="line-39"></a> <span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-40"></a>
<a name="line-41"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Alternative</span>
<a name="line-42"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Capture</span>
<a name="line-43"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Delete</span>
<a name="line-44"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Get</span>
<a name="line-45"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Header</span>
<a name="line-46"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Post</span>
<a name="line-47"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Put</span>
<a name="line-48"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>QueryParam</span>
<a name="line-49"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Raw</span>
<a name="line-50"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>ReqBody</span>
<a name="line-51"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Sub</span>
<a name="line-52"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>QQ</span> <span class='hs-layout'>(</span><span class='hs-varid'>sitemap</span><span class='hs-layout'>)</span>
<a name="line-53"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span><span class='hs-varop'>.</span><span class='hs-conid'>Links</span> <span class='hs-layout'>(</span><span class='hs-varid'>mkLink</span><span class='hs-layout'>)</span>
<a name="line-54"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span><span class='hs-varop'>.</span><span class='hs-conid'>StaticFiles</span>
</pre></body>
</html>

View file

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/Common/Text.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE FlexibleInstances #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE OverloadedStrings #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE TypeSynonymInstances #-}</span>
<a name="line-4"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Text</span>
<a name="line-5"></a> <span class='hs-layout'>(</span> <span class='hs-conid'>FromText</span><span class='hs-layout'>(</span><span class='hs-keyglyph'>..</span><span class='hs-layout'>)</span>
<a name="line-6"></a> <span class='hs-layout'>,</span> <span class='hs-conid'>ToText</span><span class='hs-layout'>(</span><span class='hs-keyglyph'>..</span><span class='hs-layout'>)</span>
<a name="line-7"></a> <span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-8"></a>
<a name="line-9"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>String</span><span class='hs-varop'>.</span><span class='hs-conid'>Conversions</span>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Int</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Text</span>
<a name="line-12"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Text</span><span class='hs-varop'>.</span><span class='hs-conid'>Read</span>
<a name="line-13"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Word</span>
<a name="line-14"></a>
<a name="line-15"></a><a name="FromText"></a><span class='hs-comment'>-- | For getting values from url captures and query string parameters</span>
<a name="line-16"></a><a name="FromText"></a><span class='hs-keyword'>class</span> <span class='hs-conid'>FromText</span> <span class='hs-varid'>a</span> <span class='hs-keyword'>where</span>
<a name="line-17"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Text</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Maybe</span> <span class='hs-varid'>a</span>
<a name="line-18"></a>
<a name="line-19"></a><a name="ToText"></a><span class='hs-comment'>-- | For putting values in paths and query string parameters</span>
<a name="line-20"></a><a name="ToText"></a><span class='hs-keyword'>class</span> <span class='hs-conid'>ToText</span> <span class='hs-varid'>a</span> <span class='hs-keyword'>where</span>
<a name="line-21"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>::</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Text</span>
<a name="line-22"></a>
<a name="line-23"></a><a name="instance%20FromText%20Text"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Text</span> <span class='hs-keyword'>where</span>
<a name="line-24"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Just</span>
<a name="line-25"></a>
<a name="line-26"></a><a name="instance%20ToText%20Text"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Text</span> <span class='hs-keyword'>where</span>
<a name="line-27"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>id</span>
<a name="line-28"></a>
<a name="line-29"></a><a name="instance%20FromText%20String"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>String</span> <span class='hs-keyword'>where</span>
<a name="line-30"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Just</span> <span class='hs-varop'>.</span> <span class='hs-varid'>cs</span>
<a name="line-31"></a>
<a name="line-32"></a><a name="instance%20ToText%20String"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>String</span> <span class='hs-keyword'>where</span>
<a name="line-33"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span>
<a name="line-34"></a>
<a name="line-35"></a><a name="instance%20FromText%20Bool"></a><span class='hs-comment'>-- |</span>
<a name="line-36"></a><a name="instance%20FromText%20Bool"></a><span class='hs-comment'>-- &gt; fromText "true" = Just True</span>
<a name="line-37"></a><a name="instance%20FromText%20Bool"></a><span class='hs-comment'>-- &gt; fromText "false" = Just False</span>
<a name="line-38"></a><a name="instance%20FromText%20Bool"></a><span class='hs-comment'>-- &gt; fromText _ = Nothing</span>
<a name="line-39"></a><a name="instance%20FromText%20Bool"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Bool</span> <span class='hs-keyword'>where</span>
<a name="line-40"></a> <span class='hs-varid'>fromText</span> <span class='hs-str'>"true"</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Just</span> <span class='hs-conid'>True</span>
<a name="line-41"></a> <span class='hs-varid'>fromText</span> <span class='hs-str'>"false"</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Just</span> <span class='hs-conid'>False</span>
<a name="line-42"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Nothing</span>
<a name="line-43"></a>
<a name="line-44"></a><a name="instance%20ToText%20Bool"></a><span class='hs-comment'>-- |</span>
<a name="line-45"></a><a name="instance%20ToText%20Bool"></a><span class='hs-comment'>-- &gt; toText True = "true"</span>
<a name="line-46"></a><a name="instance%20ToText%20Bool"></a><span class='hs-comment'>-- &gt; toText False = "false"</span>
<a name="line-47"></a><a name="instance%20ToText%20Bool"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Bool</span> <span class='hs-keyword'>where</span>
<a name="line-48"></a> <span class='hs-varid'>toText</span> <span class='hs-conid'>True</span> <span class='hs-keyglyph'>=</span> <span class='hs-str'>"true"</span>
<a name="line-49"></a> <span class='hs-varid'>toText</span> <span class='hs-conid'>False</span> <span class='hs-keyglyph'>=</span> <span class='hs-str'>"false"</span>
<a name="line-50"></a>
<a name="line-51"></a><a name="instance%20FromText%20Int"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Int</span> <span class='hs-keyword'>where</span>
<a name="line-52"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-layout'>(</span><span class='hs-varid'>signed</span> <span class='hs-varid'>decimal</span><span class='hs-layout'>)</span>
<a name="line-53"></a>
<a name="line-54"></a><a name="instance%20ToText%20Int"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Int</span> <span class='hs-keyword'>where</span>
<a name="line-55"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-56"></a>
<a name="line-57"></a><a name="instance%20FromText%20Int8"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Int8</span> <span class='hs-keyword'>where</span>
<a name="line-58"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-layout'>(</span><span class='hs-varid'>signed</span> <span class='hs-varid'>decimal</span><span class='hs-layout'>)</span>
<a name="line-59"></a>
<a name="line-60"></a><a name="instance%20ToText%20Int8"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Int8</span> <span class='hs-keyword'>where</span>
<a name="line-61"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-62"></a>
<a name="line-63"></a><a name="instance%20FromText%20Int16"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Int16</span> <span class='hs-keyword'>where</span>
<a name="line-64"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-layout'>(</span><span class='hs-varid'>signed</span> <span class='hs-varid'>decimal</span><span class='hs-layout'>)</span>
<a name="line-65"></a>
<a name="line-66"></a><a name="instance%20ToText%20Int16"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Int16</span> <span class='hs-keyword'>where</span>
<a name="line-67"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-68"></a>
<a name="line-69"></a><a name="instance%20FromText%20Int32"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Int32</span> <span class='hs-keyword'>where</span>
<a name="line-70"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-layout'>(</span><span class='hs-varid'>signed</span> <span class='hs-varid'>decimal</span><span class='hs-layout'>)</span>
<a name="line-71"></a>
<a name="line-72"></a><a name="instance%20ToText%20Int32"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Int32</span> <span class='hs-keyword'>where</span>
<a name="line-73"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-74"></a>
<a name="line-75"></a><a name="instance%20FromText%20Int64"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Int64</span> <span class='hs-keyword'>where</span>
<a name="line-76"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-layout'>(</span><span class='hs-varid'>signed</span> <span class='hs-varid'>decimal</span><span class='hs-layout'>)</span>
<a name="line-77"></a>
<a name="line-78"></a><a name="instance%20ToText%20Int64"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Int64</span> <span class='hs-keyword'>where</span>
<a name="line-79"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-80"></a>
<a name="line-81"></a><a name="instance%20FromText%20Word"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Word</span> <span class='hs-keyword'>where</span>
<a name="line-82"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-varid'>decimal</span>
<a name="line-83"></a>
<a name="line-84"></a><a name="instance%20ToText%20Word"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Word</span> <span class='hs-keyword'>where</span>
<a name="line-85"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-86"></a>
<a name="line-87"></a><a name="instance%20FromText%20Word8"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Word8</span> <span class='hs-keyword'>where</span>
<a name="line-88"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-varid'>decimal</span>
<a name="line-89"></a>
<a name="line-90"></a><a name="instance%20ToText%20Word8"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Word8</span> <span class='hs-keyword'>where</span>
<a name="line-91"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-92"></a>
<a name="line-93"></a><a name="instance%20FromText%20Word16"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Word16</span> <span class='hs-keyword'>where</span>
<a name="line-94"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-varid'>decimal</span>
<a name="line-95"></a>
<a name="line-96"></a><a name="instance%20ToText%20Word16"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Word16</span> <span class='hs-keyword'>where</span>
<a name="line-97"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-98"></a>
<a name="line-99"></a><a name="instance%20FromText%20Word32"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Word32</span> <span class='hs-keyword'>where</span>
<a name="line-100"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-varid'>decimal</span>
<a name="line-101"></a>
<a name="line-102"></a><a name="instance%20ToText%20Word32"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Word32</span> <span class='hs-keyword'>where</span>
<a name="line-103"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-104"></a>
<a name="line-105"></a><a name="instance%20FromText%20Word64"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Word64</span> <span class='hs-keyword'>where</span>
<a name="line-106"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-varid'>decimal</span>
<a name="line-107"></a>
<a name="line-108"></a><a name="instance%20ToText%20Word64"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Word64</span> <span class='hs-keyword'>where</span>
<a name="line-109"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-110"></a>
<a name="line-111"></a><a name="instance%20FromText%20Integer"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Integer</span> <span class='hs-keyword'>where</span>
<a name="line-112"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-varid'>decimal</span>
<a name="line-113"></a>
<a name="line-114"></a><a name="instance%20ToText%20Integer"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Integer</span> <span class='hs-keyword'>where</span>
<a name="line-115"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-116"></a>
<a name="line-117"></a><a name="instance%20FromText%20Double"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Double</span> <span class='hs-keyword'>where</span>
<a name="line-118"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-varid'>rational</span>
<a name="line-119"></a>
<a name="line-120"></a><a name="instance%20ToText%20Double"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Double</span> <span class='hs-keyword'>where</span>
<a name="line-121"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-122"></a>
<a name="line-123"></a><a name="instance%20FromText%20Float"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>FromText</span> <span class='hs-conid'>Float</span> <span class='hs-keyword'>where</span>
<a name="line-124"></a> <span class='hs-varid'>fromText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runReader</span> <span class='hs-varid'>rational</span>
<a name="line-125"></a>
<a name="line-126"></a><a name="instance%20ToText%20Float"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ToText</span> <span class='hs-conid'>Float</span> <span class='hs-keyword'>where</span>
<a name="line-127"></a> <span class='hs-varid'>toText</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>cs</span> <span class='hs-varop'>.</span> <span class='hs-varid'>show</span>
<a name="line-128"></a>
<a name="line-129"></a><a name="runReader"></a><span class='hs-definition'>runReader</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Reader</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Text</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Maybe</span> <span class='hs-varid'>a</span>
<a name="line-130"></a><span class='hs-definition'>runReader</span> <span class='hs-varid'>reader</span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>either</span> <span class='hs-layout'>(</span><span class='hs-varid'>const</span> <span class='hs-conid'>Nothing</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>Just</span> <span class='hs-varop'>.</span> <span class='hs-varid'>fst</span><span class='hs-layout'>)</span> <span class='hs-varop'>$</span> <span class='hs-varid'>reader</span> <span class='hs-varid'>t</span>
</pre></body>
</html>

209
src/Servant-QQ.html Normal file
View file

@ -0,0 +1,209 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/QQ.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE MultiParamTypeClasses #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE FunctionalDependencies #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE DataKinds #-}</span>
<a name="line-4"></a><span class='hs-comment'>{-# LANGUAGE FlexibleInstances #-}</span>
<a name="line-5"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-6"></a><span class='hs-comment'>{-# LANGUAGE TemplateHaskell #-}</span>
<a name="line-7"></a><span class='hs-comment'>{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}</span>
<a name="line-8"></a><span class='hs-comment'>-- | QuasiQuoting utilities for API types.</span>
<a name="line-9"></a><span class='hs-comment'>--</span>
<a name="line-10"></a><span class='hs-comment'>-- 'sitemap' allows you to write your type in a very natural way:</span>
<a name="line-11"></a><span class='hs-comment'>--</span>
<a name="line-12"></a><span class='hs-comment'>-- @</span>
<a name="line-13"></a><span class='hs-comment'>-- [sitemap|</span>
<a name="line-14"></a><span class='hs-comment'>-- PUT hello String -&gt; ()</span>
<a name="line-15"></a><span class='hs-comment'>-- POST hello/p:Int String -&gt; ()</span>
<a name="line-16"></a><span class='hs-comment'>-- GET hello/?name:String Int</span>
<a name="line-17"></a><span class='hs-comment'>-- |]</span>
<a name="line-18"></a><span class='hs-comment'>-- @</span>
<a name="line-19"></a><span class='hs-comment'>--</span>
<a name="line-20"></a><span class='hs-comment'>-- Will generate:</span>
<a name="line-21"></a><span class='hs-comment'>--</span>
<a name="line-22"></a><span class='hs-comment'>-- @</span>
<a name="line-23"></a><span class='hs-comment'>-- "hello" :&gt; ReqBody String :&gt; Put ()</span>
<a name="line-24"></a><span class='hs-comment'>-- :\&lt;|&gt; "hello" :&gt; Capture "p" Int :&gt; ReqBody String :&gt; Post ()</span>
<a name="line-25"></a><span class='hs-comment'>-- :\&lt;|&gt; "hello" :&gt; QueryParam "name" String :&gt; Get Int</span>
<a name="line-26"></a><span class='hs-comment'>-- @</span>
<a name="line-27"></a><span class='hs-comment'>--</span>
<a name="line-28"></a><span class='hs-comment'>-- Note the @/@ before a @QueryParam@!</span>
<a name="line-29"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>QQ</span> <span class='hs-keyword'>where</span>
<a name="line-30"></a>
<a name="line-31"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span> <span class='hs-layout'>(</span><span class='hs-varid'>void</span><span class='hs-layout'>)</span>
<a name="line-32"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Applicative</span> <span class='hs-varid'>hiding</span> <span class='hs-layout'>(</span><span class='hs-varid'>many</span><span class='hs-layout'>,</span> <span class='hs-layout'>(</span><span class='hs-varop'>&lt;|&gt;</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <span class='hs-varid'>optional</span><span class='hs-layout'>)</span>
<a name="line-33"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Language</span><span class='hs-varop'>.</span><span class='hs-conid'>Haskell</span><span class='hs-varop'>.</span><span class='hs-conid'>TH</span><span class='hs-varop'>.</span><span class='hs-conid'>Quote</span>
<a name="line-34"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Language</span><span class='hs-varop'>.</span><span class='hs-conid'>Haskell</span><span class='hs-varop'>.</span><span class='hs-conid'>TH</span>
<a name="line-35"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Text</span><span class='hs-varop'>.</span><span class='hs-conid'>ParserCombinators</span><span class='hs-varop'>.</span><span class='hs-conid'>Parsec</span>
<a name="line-36"></a>
<a name="line-37"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Capture</span>
<a name="line-38"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Get</span>
<a name="line-39"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Post</span>
<a name="line-40"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Put</span>
<a name="line-41"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Delete</span>
<a name="line-42"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>QueryParam</span>
<a name="line-43"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>ReqBody</span>
<a name="line-44"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Sub</span>
<a name="line-45"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Alternative</span>
<a name="line-46"></a>
<a name="line-47"></a><a name="ExpSYM"></a><span class='hs-comment'>-- | Finally-tagless encoding for our DSL.</span>
<a name="line-48"></a><a name="ExpSYM"></a><span class='hs-comment'>-- Keeping 'repr'' and 'repr' distinct when writing functions with an</span>
<a name="line-49"></a><a name="ExpSYM"></a><span class='hs-comment'>-- @ExpSYM@ context ensures certain invariants (for instance, that there is</span>
<a name="line-50"></a><a name="ExpSYM"></a><span class='hs-comment'>-- only one of 'get', 'post', 'put', and 'delete' in a value), but</span>
<a name="line-51"></a><a name="ExpSYM"></a><span class='hs-comment'>-- sometimes requires a little more work.</span>
<a name="line-52"></a><a name="ExpSYM"></a><span class='hs-keyword'>class</span> <span class='hs-conid'>ExpSYM</span> <span class='hs-varid'>repr'</span> <span class='hs-varid'>repr</span> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>repr</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr'</span><span class='hs-layout'>,</span> <span class='hs-varid'>repr'</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span> <span class='hs-keyword'>where</span>
<a name="line-53"></a> <span class='hs-varid'>lit</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>String</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr'</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span>
<a name="line-54"></a> <span class='hs-varid'>capture</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>String</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>String</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span>
<a name="line-55"></a> <span class='hs-varid'>reqBody</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>String</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span>
<a name="line-56"></a> <span class='hs-varid'>queryParam</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>String</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>String</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span>
<a name="line-57"></a> <span class='hs-varid'>conj</span> <span class='hs-keyglyph'>::</span> <span class='hs-varid'>repr'</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span>
<a name="line-58"></a> <span class='hs-varid'>get</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>String</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span>
<a name="line-59"></a> <span class='hs-varid'>post</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>String</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span>
<a name="line-60"></a> <span class='hs-varid'>put</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>String</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span>
<a name="line-61"></a> <span class='hs-varid'>delete</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>String</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span>
<a name="line-62"></a>
<a name="line-63"></a>
<a name="line-64"></a><span class='hs-keyword'>infixr</span> <span class='hs-num'>6</span> <span class='hs-varop'>&gt;:</span>
<a name="line-65"></a>
<a name="line-66"></a><a name="%3e:"></a><span class='hs-layout'>(</span><span class='hs-varop'>&gt;:</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Type</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Type</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Type</span>
<a name="line-67"></a><span class='hs-layout'>(</span><span class='hs-varop'>&gt;:</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>conj</span>
<a name="line-68"></a>
<a name="line-69"></a>
<a name="line-70"></a><a name="instance%20ExpSYM%20Type%20Type"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>ExpSYM</span> <span class='hs-conid'>Type</span> <span class='hs-conid'>Type</span> <span class='hs-keyword'>where</span>
<a name="line-71"></a> <span class='hs-varid'>lit</span> <span class='hs-varid'>name</span> <span class='hs-varid'>r</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>LitT</span> <span class='hs-layout'>(</span><span class='hs-conid'>StrTyLit</span> <span class='hs-varid'>name</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;:</span> <span class='hs-varid'>r</span>
<a name="line-72"></a> <span class='hs-varid'>capture</span> <span class='hs-varid'>name</span> <span class='hs-varid'>typ</span> <span class='hs-varid'>r</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-chr'>'</span><span class='hs-chr'>'</span><span class='hs-conid'>Capture</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>LitT</span> <span class='hs-layout'>(</span><span class='hs-conid'>StrTyLit</span> <span class='hs-varid'>name</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span>
<a name="line-73"></a> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-varop'>$</span> <span class='hs-varid'>mkName</span> <span class='hs-varid'>typ</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;:</span> <span class='hs-varid'>r</span>
<a name="line-74"></a> <span class='hs-varid'>reqBody</span> <span class='hs-varid'>typ</span> <span class='hs-varid'>r</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-chr'>'</span><span class='hs-chr'>'</span><span class='hs-conid'>ReqBody</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-varop'>$</span> <span class='hs-varid'>mkName</span> <span class='hs-varid'>typ</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;:</span> <span class='hs-varid'>r</span>
<a name="line-75"></a> <span class='hs-varid'>queryParam</span> <span class='hs-varid'>name</span> <span class='hs-varid'>typ</span> <span class='hs-varid'>r</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-chr'>'</span><span class='hs-chr'>'</span><span class='hs-conid'>QueryParam</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>LitT</span> <span class='hs-layout'>(</span><span class='hs-conid'>StrTyLit</span> <span class='hs-varid'>name</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span>
<a name="line-76"></a> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-varop'>$</span> <span class='hs-varid'>mkName</span> <span class='hs-varid'>typ</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;:</span> <span class='hs-varid'>r</span>
<a name="line-77"></a> <span class='hs-varid'>conj</span> <span class='hs-varid'>x</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-chr'>'</span><span class='hs-chr'>'</span><span class='hs-layout'>(</span><span class='hs-conop'>:&gt;</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <span class='hs-varid'>x</span><span class='hs-layout'>)</span>
<a name="line-78"></a> <span class='hs-varid'>get</span> <span class='hs-varid'>typ</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-chr'>'</span><span class='hs-chr'>'</span><span class='hs-conid'>Get</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-varop'>$</span> <span class='hs-varid'>mkName</span> <span class='hs-varid'>typ</span><span class='hs-layout'>)</span>
<a name="line-79"></a> <span class='hs-varid'>post</span> <span class='hs-varid'>typ</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-chr'>'</span><span class='hs-chr'>'</span><span class='hs-conid'>Post</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-varop'>$</span> <span class='hs-varid'>mkName</span> <span class='hs-varid'>typ</span><span class='hs-layout'>)</span>
<a name="line-80"></a> <span class='hs-varid'>put</span> <span class='hs-varid'>typ</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-chr'>'</span><span class='hs-chr'>'</span><span class='hs-conid'>Put</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-varop'>$</span> <span class='hs-varid'>mkName</span> <span class='hs-varid'>typ</span><span class='hs-layout'>)</span>
<a name="line-81"></a> <span class='hs-varid'>delete</span> <span class='hs-str'>"()"</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>ConT</span> <span class='hs-chr'>'</span><span class='hs-chr'>'</span><span class='hs-conid'>Delete</span>
<a name="line-82"></a> <span class='hs-varid'>delete</span> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>error</span> <span class='hs-str'>"Delete does not return a request body"</span>
<a name="line-83"></a>
<a name="line-84"></a><a name="parseMethod"></a><span class='hs-definition'>parseMethod</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>ExpSYM</span> <span class='hs-varid'>repr'</span> <span class='hs-varid'>repr</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>Parser</span> <span class='hs-layout'>(</span><span class='hs-conid'>String</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span><span class='hs-layout'>)</span>
<a name="line-85"></a><span class='hs-definition'>parseMethod</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>try</span> <span class='hs-layout'>(</span><span class='hs-varid'>string</span> <span class='hs-str'>"GET"</span> <span class='hs-varop'>&gt;&gt;</span> <span class='hs-varid'>return</span> <span class='hs-varid'>get</span><span class='hs-layout'>)</span>
<a name="line-86"></a> <span class='hs-varop'>&lt;|&gt;</span> <span class='hs-varid'>try</span> <span class='hs-layout'>(</span><span class='hs-varid'>string</span> <span class='hs-str'>"POST"</span> <span class='hs-varop'>&gt;&gt;</span> <span class='hs-varid'>return</span> <span class='hs-varid'>post</span><span class='hs-layout'>)</span>
<a name="line-87"></a> <span class='hs-varop'>&lt;|&gt;</span> <span class='hs-varid'>try</span> <span class='hs-layout'>(</span><span class='hs-varid'>string</span> <span class='hs-str'>"PUT"</span> <span class='hs-varop'>&gt;&gt;</span> <span class='hs-varid'>return</span> <span class='hs-varid'>put</span><span class='hs-layout'>)</span>
<a name="line-88"></a> <span class='hs-varop'>&lt;|&gt;</span> <span class='hs-varid'>try</span> <span class='hs-layout'>(</span><span class='hs-varid'>string</span> <span class='hs-str'>"DELETE"</span> <span class='hs-varop'>&gt;&gt;</span> <span class='hs-varid'>return</span> <span class='hs-varid'>delete</span><span class='hs-layout'>)</span>
<a name="line-89"></a>
<a name="line-90"></a><a name="parseUrlSegment"></a><span class='hs-definition'>parseUrlSegment</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>ExpSYM</span> <span class='hs-varid'>repr</span> <span class='hs-varid'>repr</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>Parser</span> <span class='hs-layout'>(</span><span class='hs-varid'>repr</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span><span class='hs-layout'>)</span>
<a name="line-91"></a><span class='hs-definition'>parseUrlSegment</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>try</span> <span class='hs-varid'>parseCapture</span>
<a name="line-92"></a> <span class='hs-varop'>&lt;|&gt;</span> <span class='hs-varid'>try</span> <span class='hs-varid'>parseQueryParam</span>
<a name="line-93"></a> <span class='hs-varop'>&lt;|&gt;</span> <span class='hs-varid'>try</span> <span class='hs-varid'>parseLit</span>
<a name="line-94"></a> <span class='hs-keyword'>where</span>
<a name="line-95"></a> <span class='hs-varid'>parseCapture</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-96"></a> <span class='hs-varid'>cname</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>many</span> <span class='hs-layout'>(</span><span class='hs-varid'>noneOf</span> <span class='hs-str'>" ?/:"</span><span class='hs-layout'>)</span>
<a name="line-97"></a> <span class='hs-varid'>char</span> <span class='hs-chr'>':'</span>
<a name="line-98"></a> <span class='hs-varid'>ctyp</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>many</span> <span class='hs-layout'>(</span><span class='hs-varid'>noneOf</span> <span class='hs-str'>" ?/:"</span><span class='hs-layout'>)</span>
<a name="line-99"></a> <span class='hs-varid'>return</span> <span class='hs-varop'>$</span> <span class='hs-varid'>capture</span> <span class='hs-varid'>cname</span> <span class='hs-varid'>ctyp</span>
<a name="line-100"></a> <span class='hs-varid'>parseQueryParam</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-101"></a> <span class='hs-varid'>char</span> <span class='hs-chr'>'?'</span>
<a name="line-102"></a> <span class='hs-varid'>cname</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>many</span> <span class='hs-layout'>(</span><span class='hs-varid'>noneOf</span> <span class='hs-str'>" ?/:"</span><span class='hs-layout'>)</span>
<a name="line-103"></a> <span class='hs-varid'>char</span> <span class='hs-chr'>':'</span>
<a name="line-104"></a> <span class='hs-varid'>ctyp</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>many</span> <span class='hs-layout'>(</span><span class='hs-varid'>noneOf</span> <span class='hs-str'>" ?/:"</span><span class='hs-layout'>)</span>
<a name="line-105"></a> <span class='hs-varid'>return</span> <span class='hs-varop'>$</span> <span class='hs-varid'>queryParam</span> <span class='hs-varid'>cname</span> <span class='hs-varid'>ctyp</span>
<a name="line-106"></a> <span class='hs-varid'>parseLit</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>lit</span> <span class='hs-varop'>&lt;$&gt;</span> <span class='hs-varid'>many</span> <span class='hs-layout'>(</span><span class='hs-varid'>noneOf</span> <span class='hs-str'>" ?/:"</span><span class='hs-layout'>)</span>
<a name="line-107"></a>
<a name="line-108"></a><a name="parseUrl"></a><span class='hs-definition'>parseUrl</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>ExpSYM</span> <span class='hs-varid'>repr</span> <span class='hs-varid'>repr</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>Parser</span> <span class='hs-layout'>(</span><span class='hs-varid'>repr</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>repr</span><span class='hs-layout'>)</span>
<a name="line-109"></a><span class='hs-definition'>parseUrl</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-110"></a> <span class='hs-varid'>optional</span> <span class='hs-varop'>$</span> <span class='hs-varid'>char</span> <span class='hs-chr'>'/'</span>
<a name="line-111"></a> <span class='hs-varid'>url</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>parseUrlSegment</span> <span class='hs-varop'>`sepBy1`</span> <span class='hs-varid'>char</span> <span class='hs-chr'>'/'</span>
<a name="line-112"></a> <span class='hs-varid'>return</span> <span class='hs-varop'>$</span> <span class='hs-varid'>foldr1</span> <span class='hs-layout'>(</span><span class='hs-varop'>.</span><span class='hs-layout'>)</span> <span class='hs-varid'>url</span>
<a name="line-113"></a>
<a name="line-114"></a><a name="Typ"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>Typ</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Val</span> <span class='hs-conid'>String</span>
<a name="line-115"></a> <span class='hs-keyglyph'>|</span> <span class='hs-conid'>ReqArgVal</span> <span class='hs-conid'>String</span> <span class='hs-conid'>String</span>
<a name="line-116"></a>
<a name="line-117"></a><a name="parseTyp"></a><span class='hs-definition'>parseTyp</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Parser</span> <span class='hs-conid'>Typ</span>
<a name="line-118"></a><span class='hs-definition'>parseTyp</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-119"></a> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>many</span> <span class='hs-layout'>(</span><span class='hs-varid'>noneOf</span> <span class='hs-str'>"-{\n\r"</span><span class='hs-layout'>)</span>
<a name="line-120"></a> <span class='hs-varid'>spaces</span>
<a name="line-121"></a> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>optionMaybe</span> <span class='hs-layout'>(</span><span class='hs-varid'>try</span> <span class='hs-varid'>parseRet</span><span class='hs-layout'>)</span>
<a name="line-122"></a> <span class='hs-varid'>try</span> <span class='hs-varop'>$</span> <span class='hs-varid'>optional</span> <span class='hs-varid'>inlineComment</span>
<a name="line-123"></a> <span class='hs-varid'>try</span> <span class='hs-varop'>$</span> <span class='hs-varid'>optional</span> <span class='hs-varid'>blockComment</span>
<a name="line-124"></a> <span class='hs-keyword'>case</span> <span class='hs-varid'>s</span> <span class='hs-keyword'>of</span>
<a name="line-125"></a> <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>return</span> <span class='hs-varop'>$</span> <span class='hs-conid'>Val</span> <span class='hs-layout'>(</span><span class='hs-varid'>stripTr</span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span>
<a name="line-126"></a> <span class='hs-conid'>Just</span> <span class='hs-varid'>s'</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>return</span> <span class='hs-varop'>$</span> <span class='hs-conid'>ReqArgVal</span> <span class='hs-layout'>(</span><span class='hs-varid'>stripTr</span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>stripTr</span> <span class='hs-varid'>s'</span><span class='hs-layout'>)</span>
<a name="line-127"></a> <span class='hs-keyword'>where</span>
<a name="line-128"></a> <span class='hs-varid'>parseRet</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Parser</span> <span class='hs-conid'>String</span>
<a name="line-129"></a> <span class='hs-varid'>parseRet</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-130"></a> <span class='hs-varid'>string</span> <span class='hs-str'>"-&gt;"</span>
<a name="line-131"></a> <span class='hs-varid'>spaces</span>
<a name="line-132"></a> <span class='hs-varid'>many</span> <span class='hs-layout'>(</span><span class='hs-varid'>noneOf</span> <span class='hs-str'>"-{\n\r"</span><span class='hs-layout'>)</span>
<a name="line-133"></a> <span class='hs-varid'>stripTr</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>reverse</span> <span class='hs-varop'>.</span> <span class='hs-varid'>dropWhile</span> <span class='hs-layout'>(</span><span class='hs-varop'>==</span> <span class='hs-chr'>' '</span><span class='hs-layout'>)</span> <span class='hs-varop'>.</span> <span class='hs-varid'>reverse</span>
<a name="line-134"></a>
<a name="line-135"></a>
<a name="line-136"></a><a name="parseEntry"></a><span class='hs-definition'>parseEntry</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>ExpSYM</span> <span class='hs-varid'>repr</span> <span class='hs-varid'>repr</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>Parser</span> <span class='hs-varid'>repr</span>
<a name="line-137"></a><span class='hs-definition'>parseEntry</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-138"></a> <span class='hs-varid'>met</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>parseMethod</span>
<a name="line-139"></a> <span class='hs-varid'>spaces</span>
<a name="line-140"></a> <span class='hs-varid'>url</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>parseUrl</span>
<a name="line-141"></a> <span class='hs-varid'>spaces</span>
<a name="line-142"></a> <span class='hs-varid'>typ</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>parseTyp</span>
<a name="line-143"></a> <span class='hs-keyword'>case</span> <span class='hs-varid'>typ</span> <span class='hs-keyword'>of</span>
<a name="line-144"></a> <span class='hs-conid'>Val</span> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>return</span> <span class='hs-varop'>$</span> <span class='hs-varid'>url</span> <span class='hs-layout'>(</span><span class='hs-varid'>met</span> <span class='hs-varid'>s</span><span class='hs-layout'>)</span>
<a name="line-145"></a> <span class='hs-conid'>ReqArgVal</span> <span class='hs-varid'>i</span> <span class='hs-varid'>o</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>return</span> <span class='hs-varop'>$</span> <span class='hs-varid'>url</span> <span class='hs-varop'>$</span> <span class='hs-varid'>reqBody</span> <span class='hs-varid'>i</span> <span class='hs-layout'>(</span><span class='hs-varid'>met</span> <span class='hs-varid'>o</span><span class='hs-layout'>)</span>
<a name="line-146"></a>
<a name="line-147"></a><a name="blockComment"></a><span class='hs-definition'>blockComment</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Parser</span> <span class='hs-conid'>()</span>
<a name="line-148"></a><span class='hs-definition'>blockComment</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-149"></a> <span class='hs-varid'>string</span> <span class='hs-str'>"{-"</span>
<a name="line-150"></a> <span class='hs-varid'>manyTill</span> <span class='hs-varid'>anyChar</span> <span class='hs-layout'>(</span><span class='hs-varid'>try</span> <span class='hs-varop'>$</span> <span class='hs-varid'>string</span> <span class='hs-str'>"-}"</span><span class='hs-layout'>)</span>
<a name="line-151"></a> <span class='hs-varid'>return</span> <span class='hs-conid'>()</span>
<a name="line-152"></a>
<a name="line-153"></a><a name="inlineComment"></a><span class='hs-definition'>inlineComment</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Parser</span> <span class='hs-conid'>()</span>
<a name="line-154"></a><span class='hs-definition'>inlineComment</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-155"></a> <span class='hs-varid'>string</span> <span class='hs-str'>"--"</span>
<a name="line-156"></a> <span class='hs-varid'>manyTill</span> <span class='hs-varid'>anyChar</span> <span class='hs-layout'>(</span><span class='hs-varid'>try</span> <span class='hs-varop'>$</span> <span class='hs-varid'>lookAhead</span> <span class='hs-varid'>eol</span><span class='hs-layout'>)</span>
<a name="line-157"></a> <span class='hs-varid'>return</span> <span class='hs-conid'>()</span>
<a name="line-158"></a>
<a name="line-159"></a><a name="eol"></a><span class='hs-definition'>eol</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Parser</span> <span class='hs-conid'>String</span>
<a name="line-160"></a><span class='hs-definition'>eol</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>try</span> <span class='hs-layout'>(</span><span class='hs-varid'>string</span> <span class='hs-str'>"\n\r"</span><span class='hs-layout'>)</span>
<a name="line-161"></a> <span class='hs-varop'>&lt;|&gt;</span> <span class='hs-varid'>try</span> <span class='hs-layout'>(</span><span class='hs-varid'>string</span> <span class='hs-str'>"\r\n"</span><span class='hs-layout'>)</span>
<a name="line-162"></a> <span class='hs-varop'>&lt;|&gt;</span> <span class='hs-varid'>string</span> <span class='hs-str'>"\n"</span>
<a name="line-163"></a> <span class='hs-varop'>&lt;|&gt;</span> <span class='hs-varid'>string</span> <span class='hs-str'>"\r"</span>
<a name="line-164"></a> <span class='hs-varop'>&lt;?&gt;</span> <span class='hs-str'>"end of line"</span>
<a name="line-165"></a>
<a name="line-166"></a><a name="eols"></a><span class='hs-definition'>eols</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Parser</span> <span class='hs-conid'>()</span>
<a name="line-167"></a><span class='hs-definition'>eols</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>skipMany</span> <span class='hs-varop'>$</span> <span class='hs-varid'>void</span> <span class='hs-varid'>eol</span> <span class='hs-varop'>&lt;|&gt;</span> <span class='hs-varid'>blockComment</span> <span class='hs-varop'>&lt;|&gt;</span> <span class='hs-varid'>inlineComment</span>
<a name="line-168"></a>
<a name="line-169"></a><a name="parseAll"></a><span class='hs-definition'>parseAll</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Parser</span> <span class='hs-conid'>Type</span>
<a name="line-170"></a><span class='hs-definition'>parseAll</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-171"></a> <span class='hs-varid'>eols</span>
<a name="line-172"></a> <span class='hs-varid'>entries</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>parseEntry</span> <span class='hs-varop'>`endBy`</span> <span class='hs-varid'>eols</span>
<a name="line-173"></a> <span class='hs-varid'>return</span> <span class='hs-varop'>$</span> <span class='hs-varid'>foldr1</span> <span class='hs-varid'>union</span> <span class='hs-varid'>entries</span>
<a name="line-174"></a> <span class='hs-keyword'>where</span> <span class='hs-varid'>union</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Type</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Type</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Type</span>
<a name="line-175"></a> <span class='hs-varid'>union</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>AppT</span> <span class='hs-layout'>(</span><span class='hs-conid'>ConT</span> <span class='hs-chr'>'</span><span class='hs-chr'>'</span><span class='hs-layout'>(</span><span class='hs-conop'>:&lt;|&gt;</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span>
<a name="line-176"></a>
<a name="line-177"></a><a name="sitemap"></a><span class='hs-comment'>-- | The sitemap QuasiQuoter.</span>
<a name="line-178"></a><span class='hs-comment'>--</span>
<a name="line-179"></a><span class='hs-comment'>-- * @.../&lt;var&gt;:&lt;type&gt;/...@ becomes a capture</span>
<a name="line-180"></a><span class='hs-comment'>-- * @.../?&lt;var&gt;:&lt;type&gt;@ becomes a query parameter</span>
<a name="line-181"></a><span class='hs-comment'>-- * @&lt;method&gt; ... &lt;typ&gt;@ becomes a method returning @&lt;typ&gt;@</span>
<a name="line-182"></a><span class='hs-comment'>-- * @&lt;method&gt; ... &lt;typ1&gt; -&gt; &lt;typ2&gt;@ becomes a method with request</span>
<a name="line-183"></a><span class='hs-comment'>-- body of @&lt;typ1&gt;@ and returning @&lt;typ2&gt;@</span>
<a name="line-184"></a><span class='hs-comment'>--</span>
<a name="line-185"></a><span class='hs-comment'>-- Comments are allowed, and have the standard Haskell format</span>
<a name="line-186"></a><span class='hs-comment'>--</span>
<a name="line-187"></a><span class='hs-comment'>-- * @--@ for inline</span>
<a name="line-188"></a><span class='hs-comment'>-- * @{- ... -}@ for block</span>
<a name="line-189"></a><span class='hs-comment'>--</span>
<a name="line-190"></a><span class='hs-definition'>sitemap</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>QuasiQuoter</span>
<a name="line-191"></a><span class='hs-definition'>sitemap</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>QuasiQuoter</span> <span class='hs-layout'>{</span> <span class='hs-varid'>quoteExp</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>undefined</span>
<a name="line-192"></a> <span class='hs-layout'>,</span> <span class='hs-varid'>quotePat</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>undefined</span>
<a name="line-193"></a> <span class='hs-layout'>,</span> <span class='hs-varid'>quoteType</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyglyph'>\</span><span class='hs-varid'>x</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-keyword'>case</span> <span class='hs-varid'>parse</span> <span class='hs-varid'>parseAll</span> <span class='hs-str'>""</span> <span class='hs-varid'>x</span> <span class='hs-keyword'>of</span>
<a name="line-194"></a> <span class='hs-conid'>Left</span> <span class='hs-varid'>err</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>error</span> <span class='hs-varop'>$</span> <span class='hs-varid'>show</span> <span class='hs-varid'>err</span>
<a name="line-195"></a> <span class='hs-conid'>Right</span> <span class='hs-varid'>st</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>return</span> <span class='hs-varid'>st</span>
<a name="line-196"></a> <span class='hs-layout'>,</span> <span class='hs-varid'>quoteDec</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>undefined</span>
<a name="line-197"></a> <span class='hs-layout'>}</span>
<a name="line-198"></a>
</pre></body>
</html>

116
src/Servant-Server.html Normal file
View file

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/Server.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE OverloadedStrings #-}</span>
<a name="line-3"></a>
<a name="line-4"></a><span class='hs-comment'>-- | This module lets you implement 'Server's for defined APIs. You'll</span>
<a name="line-5"></a><span class='hs-comment'>-- most likely just need 'serve'.</span>
<a name="line-6"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span> <span class='hs-keyword'>where</span>
<a name="line-7"></a>
<a name="line-8"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Monoid</span>
<a name="line-9"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>HTTP</span><span class='hs-varop'>.</span><span class='hs-conid'>Types</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span>
<a name="line-12"></a>
<a name="line-13"></a><span class='hs-comment'>-- * Implementing Servers</span>
<a name="line-14"></a>
<a name="line-15"></a><a name="serve"></a><span class='hs-comment'>-- | 'serve' allows you to implement an API and produce a wai 'Application'.</span>
<a name="line-16"></a><span class='hs-comment'>--</span>
<a name="line-17"></a><span class='hs-comment'>-- Example:</span>
<a name="line-18"></a><span class='hs-comment'>--</span>
<a name="line-19"></a><span class='hs-comment'>-- &gt; type MyApi = "books" :&gt; Get [Book] -- GET /books</span>
<a name="line-20"></a><span class='hs-comment'>-- &gt; :&lt;|&gt; "books" :&gt; ReqBody Book :&gt; Post Book -- POST /books</span>
<a name="line-21"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-22"></a><span class='hs-comment'>-- &gt; server :: Server MyApi</span>
<a name="line-23"></a><span class='hs-comment'>-- &gt; server = listAllBooks :&lt;|&gt; postBook</span>
<a name="line-24"></a><span class='hs-comment'>-- &gt; where listAllBooks = ...</span>
<a name="line-25"></a><span class='hs-comment'>-- &gt; postBook book = ...</span>
<a name="line-26"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-27"></a><span class='hs-comment'>-- &gt; app :: Application</span>
<a name="line-28"></a><span class='hs-comment'>-- &gt; app = serve myApi server</span>
<a name="line-29"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-30"></a><span class='hs-comment'>-- &gt; main :: IO ()</span>
<a name="line-31"></a><span class='hs-comment'>-- &gt; main = Network.Wai.Handler.Warp.run 8080 app</span>
<a name="line-32"></a><span class='hs-definition'>serve</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>HasServer</span> <span class='hs-varid'>layout</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>layout</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>layout</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Application</span>
<a name="line-33"></a><span class='hs-definition'>serve</span> <span class='hs-varid'>p</span> <span class='hs-varid'>server</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>toApplication</span> <span class='hs-layout'>(</span><span class='hs-varid'>route</span> <span class='hs-varid'>p</span> <span class='hs-varid'>server</span><span class='hs-layout'>)</span>
<a name="line-34"></a>
<a name="line-35"></a><a name="toApplication"></a><span class='hs-definition'>toApplication</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>RoutingApplication</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Application</span>
<a name="line-36"></a><span class='hs-definition'>toApplication</span> <span class='hs-varid'>ra</span> <span class='hs-varid'>request</span> <span class='hs-varid'>respond</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
<a name="line-37"></a> <span class='hs-varid'>ra</span> <span class='hs-varid'>request</span> <span class='hs-layout'>(</span><span class='hs-varid'>routingRespond</span> <span class='hs-varop'>.</span> <span class='hs-varid'>routeResult</span><span class='hs-layout'>)</span>
<a name="line-38"></a> <span class='hs-keyword'>where</span>
<a name="line-39"></a> <span class='hs-varid'>routingRespond</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Either</span> <span class='hs-conid'>RouteMismatch</span> <span class='hs-conid'>Response</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>IO</span> <span class='hs-conid'>ResponseReceived</span>
<a name="line-40"></a> <span class='hs-varid'>routingRespond</span> <span class='hs-layout'>(</span><span class='hs-conid'>Left</span> <span class='hs-conid'>NotFound</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span>
<a name="line-41"></a> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>responseLBS</span> <span class='hs-varid'>notFound404</span> <span class='hs-conid'>[]</span> <span class='hs-str'>"not found"</span>
<a name="line-42"></a> <span class='hs-varid'>routingRespond</span> <span class='hs-layout'>(</span><span class='hs-conid'>Left</span> <span class='hs-conid'>WrongMethod</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span>
<a name="line-43"></a> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>responseLBS</span> <span class='hs-varid'>methodNotAllowed405</span> <span class='hs-conid'>[]</span> <span class='hs-str'>"method not allowed"</span>
<a name="line-44"></a> <span class='hs-varid'>routingRespond</span> <span class='hs-layout'>(</span><span class='hs-conid'>Left</span> <span class='hs-conid'>InvalidBody</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span>
<a name="line-45"></a> <span class='hs-varid'>respond</span> <span class='hs-varop'>$</span> <span class='hs-varid'>responseLBS</span> <span class='hs-varid'>badRequest400</span> <span class='hs-conid'>[]</span> <span class='hs-str'>"Invalid JSON in request body"</span>
<a name="line-46"></a> <span class='hs-varid'>routingRespond</span> <span class='hs-layout'>(</span><span class='hs-conid'>Right</span> <span class='hs-varid'>response</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span>
<a name="line-47"></a> <span class='hs-varid'>respond</span> <span class='hs-varid'>response</span>
<a name="line-48"></a>
<a name="line-49"></a><a name="RouteMismatch"></a><span class='hs-comment'>-- * Route mismatch</span>
<a name="line-50"></a><a name="RouteMismatch"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>RouteMismatch</span> <span class='hs-keyglyph'>=</span>
<a name="line-51"></a> <span class='hs-conid'>NotFound</span> <span class='hs-comment'>-- ^ the usual "not found" error</span>
<a name="line-52"></a> <span class='hs-keyglyph'>|</span> <span class='hs-conid'>WrongMethod</span> <span class='hs-comment'>-- ^ a more informative "you just got the HTTP method wrong" error</span>
<a name="line-53"></a> <span class='hs-keyglyph'>|</span> <span class='hs-conid'>InvalidBody</span> <span class='hs-comment'>-- ^ an even more informative "your json request body wasn't valid" error</span>
<a name="line-54"></a> <span class='hs-keyword'>deriving</span> <span class='hs-layout'>(</span><span class='hs-conid'>Eq</span><span class='hs-layout'>,</span> <span class='hs-conid'>Show</span><span class='hs-layout'>)</span>
<a name="line-55"></a>
<a name="line-56"></a><a name="instance%20Monoid%20RouteMismatch"></a><span class='hs-comment'>-- | </span>
<a name="line-57"></a><a name="instance%20Monoid%20RouteMismatch"></a><span class='hs-comment'>-- @</span>
<a name="line-58"></a><a name="instance%20Monoid%20RouteMismatch"></a><span class='hs-comment'>-- &gt; mempty = NotFound</span>
<a name="line-59"></a><a name="instance%20Monoid%20RouteMismatch"></a><span class='hs-comment'>-- &gt;</span>
<a name="line-60"></a><a name="instance%20Monoid%20RouteMismatch"></a><span class='hs-comment'>-- &gt; NotFound `mappend` x = x</span>
<a name="line-61"></a><a name="instance%20Monoid%20RouteMismatch"></a><span class='hs-comment'>-- &gt; WrongMethod `mappend` InvalidBody = InvalidBody</span>
<a name="line-62"></a><a name="instance%20Monoid%20RouteMismatch"></a><span class='hs-comment'>-- &gt; WrongMethod `mappend` _ = WrongMethod</span>
<a name="line-63"></a><a name="instance%20Monoid%20RouteMismatch"></a><span class='hs-comment'>-- &gt; InvalidBody `mappend` _ = InvalidBody</span>
<a name="line-64"></a><a name="instance%20Monoid%20RouteMismatch"></a><span class='hs-comment'>-- @</span>
<a name="line-65"></a><a name="instance%20Monoid%20RouteMismatch"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>Monoid</span> <span class='hs-conid'>RouteMismatch</span> <span class='hs-keyword'>where</span>
<a name="line-66"></a> <span class='hs-varid'>mempty</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>NotFound</span>
<a name="line-67"></a>
<a name="line-68"></a> <span class='hs-conid'>NotFound</span> <span class='hs-varop'>`mappend`</span> <span class='hs-varid'>x</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>x</span>
<a name="line-69"></a> <span class='hs-conid'>WrongMethod</span> <span class='hs-varop'>`mappend`</span> <span class='hs-conid'>InvalidBody</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>InvalidBody</span>
<a name="line-70"></a> <span class='hs-conid'>WrongMethod</span> <span class='hs-varop'>`mappend`</span> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>WrongMethod</span>
<a name="line-71"></a> <span class='hs-conid'>InvalidBody</span> <span class='hs-varop'>`mappend`</span> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>InvalidBody</span>
<a name="line-72"></a>
<a name="line-73"></a><a name="RouteResult"></a><span class='hs-comment'>-- | A wrapper around @'Either' 'RouteMismatch' a@.</span>
<a name="line-74"></a><a name="RouteResult"></a><span class='hs-keyword'>newtype</span> <span class='hs-conid'>RouteResult</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span>
<a name="line-75"></a> <span class='hs-conid'>RR</span> <span class='hs-layout'>{</span> <span class='hs-varid'>routeResult</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Either</span> <span class='hs-conid'>RouteMismatch</span> <span class='hs-varid'>a</span> <span class='hs-layout'>}</span>
<a name="line-76"></a> <span class='hs-keyword'>deriving</span> <span class='hs-layout'>(</span><span class='hs-conid'>Eq</span><span class='hs-layout'>,</span> <span class='hs-conid'>Show</span><span class='hs-layout'>)</span>
<a name="line-77"></a>
<a name="line-78"></a><a name="failWith"></a><span class='hs-definition'>failWith</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>RouteMismatch</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>RouteResult</span> <span class='hs-varid'>a</span>
<a name="line-79"></a><span class='hs-definition'>failWith</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>RR</span> <span class='hs-varop'>.</span> <span class='hs-conid'>Left</span>
<a name="line-80"></a>
<a name="line-81"></a><a name="succeedWith"></a><span class='hs-definition'>succeedWith</span> <span class='hs-keyglyph'>::</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>RouteResult</span> <span class='hs-varid'>a</span>
<a name="line-82"></a><span class='hs-definition'>succeedWith</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>RR</span> <span class='hs-varop'>.</span> <span class='hs-conid'>Right</span>
<a name="line-83"></a>
<a name="line-84"></a><a name="isMismatch"></a><span class='hs-definition'>isMismatch</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>RouteResult</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Bool</span>
<a name="line-85"></a><span class='hs-definition'>isMismatch</span> <span class='hs-layout'>(</span><span class='hs-conid'>RR</span> <span class='hs-layout'>(</span><span class='hs-conid'>Left</span> <span class='hs-keyword'>_</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>True</span>
<a name="line-86"></a><span class='hs-definition'>isMismatch</span> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>False</span>
<a name="line-87"></a>
<a name="line-88"></a><a name="instance%20Monoid%20(RouteResult%20a)"></a><span class='hs-comment'>-- | If we get a `Right`, it has precedence over everything else.</span>
<a name="line-89"></a><a name="instance%20Monoid%20(RouteResult%20a)"></a><span class='hs-comment'>--</span>
<a name="line-90"></a><a name="instance%20Monoid%20(RouteResult%20a)"></a><span class='hs-comment'>-- This in particular means that if we could get several 'Right's,</span>
<a name="line-91"></a><a name="instance%20Monoid%20(RouteResult%20a)"></a><span class='hs-comment'>-- only the first we encounter would be taken into account.</span>
<a name="line-92"></a><a name="instance%20Monoid%20(RouteResult%20a)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>Monoid</span> <span class='hs-layout'>(</span><span class='hs-conid'>RouteResult</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-93"></a> <span class='hs-varid'>mempty</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>RR</span> <span class='hs-varop'>$</span> <span class='hs-conid'>Left</span> <span class='hs-varid'>mempty</span>
<a name="line-94"></a>
<a name="line-95"></a> <span class='hs-conid'>RR</span> <span class='hs-layout'>(</span><span class='hs-conid'>Left</span> <span class='hs-varid'>x</span><span class='hs-layout'>)</span> <span class='hs-varop'>`mappend`</span> <span class='hs-conid'>RR</span> <span class='hs-layout'>(</span><span class='hs-conid'>Left</span> <span class='hs-varid'>y</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>RR</span> <span class='hs-varop'>$</span> <span class='hs-conid'>Left</span> <span class='hs-layout'>(</span><span class='hs-varid'>x</span> <span class='hs-varop'>&lt;&gt;</span> <span class='hs-varid'>y</span><span class='hs-layout'>)</span>
<a name="line-96"></a> <span class='hs-conid'>RR</span> <span class='hs-layout'>(</span><span class='hs-conid'>Left</span> <span class='hs-keyword'>_</span><span class='hs-layout'>)</span> <span class='hs-varop'>`mappend`</span> <span class='hs-conid'>RR</span> <span class='hs-layout'>(</span><span class='hs-conid'>Right</span> <span class='hs-varid'>y</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>RR</span> <span class='hs-varop'>$</span> <span class='hs-conid'>Right</span> <span class='hs-varid'>y</span>
<a name="line-97"></a> <span class='hs-varid'>r</span> <span class='hs-varop'>`mappend`</span> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>r</span>
<a name="line-98"></a>
<a name="line-99"></a><a name="RoutingApplication"></a><span class='hs-keyword'>type</span> <span class='hs-conid'>RoutingApplication</span> <span class='hs-keyglyph'>=</span>
<a name="line-100"></a> <span class='hs-conid'>Request</span> <span class='hs-comment'>-- ^ the request, the field 'pathInfo' may be modified by url routing</span>
<a name="line-101"></a> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-layout'>(</span><span class='hs-conid'>RouteResult</span> <span class='hs-conid'>Response</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>IO</span> <span class='hs-conid'>ResponseReceived</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>IO</span> <span class='hs-conid'>ResponseReceived</span>
<a name="line-102"></a>
<a name="line-103"></a><span class='hs-keyword'>class</span> <span class='hs-conid'>HasServer</span> <span class='hs-varid'>layout</span> <span class='hs-keyword'>where</span>
<a name="line-104"></a> <span class='hs-keyword'>type</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>layout</span> <span class='hs-keyglyph'>::</span> <span class='hs-varop'>*</span>
<a name="line-105"></a> <span class='hs-varid'>route</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>layout</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Server</span> <span class='hs-varid'>layout</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>RoutingApplication</span>
</pre></body>
</html>

View file

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/Utils/Links.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE PolyKinds #-}</span>
<a name="line-2"></a><span class='hs-comment'>{-# LANGUAGE DataKinds #-}</span>
<a name="line-3"></a><span class='hs-comment'>{-# LANGUAGE FlexibleInstances #-}</span>
<a name="line-4"></a><span class='hs-comment'>{-# LANGUAGE TypeFamilies #-}</span>
<a name="line-5"></a><span class='hs-comment'>{-# LANGUAGE TypeOperators #-}</span>
<a name="line-6"></a><span class='hs-comment'>{-# LANGUAGE FunctionalDependencies #-}</span>
<a name="line-7"></a><span class='hs-comment'>{-# LANGUAGE ScopedTypeVariables #-}</span>
<a name="line-8"></a><span class='hs-comment'>{-# LANGUAGE UndecidableInstances #-}</span>
<a name="line-9"></a><span class='hs-comment'>-- | Type safe internal links.</span>
<a name="line-10"></a><span class='hs-comment'>--</span>
<a name="line-11"></a><span class='hs-comment'>-- Provides the function 'mkLink':</span>
<a name="line-12"></a><span class='hs-comment'>--</span>
<a name="line-13"></a><span class='hs-comment'>-- @</span>
<a name="line-14"></a><span class='hs-comment'>-- type API = Proxy ("hello" :&gt; Get Int</span>
<a name="line-15"></a><span class='hs-comment'>-- :&lt;|&gt; "bye" :&gt; QueryParam "name" String :&gt; Post Bool)</span>
<a name="line-16"></a><span class='hs-comment'>--</span>
<a name="line-17"></a><span class='hs-comment'>-- api :: API</span>
<a name="line-18"></a><span class='hs-comment'>-- api = proxy</span>
<a name="line-19"></a><span class='hs-comment'>--</span>
<a name="line-20"></a><span class='hs-comment'>-- link1 :: Proxy ("hello" :&gt; Get Int)</span>
<a name="line-21"></a><span class='hs-comment'>-- link1 = proxy</span>
<a name="line-22"></a><span class='hs-comment'>--</span>
<a name="line-23"></a><span class='hs-comment'>-- link2 :: Proxy ("hello" :&gt; Delete)</span>
<a name="line-24"></a><span class='hs-comment'>-- link2 = proxy</span>
<a name="line-25"></a><span class='hs-comment'>--</span>
<a name="line-26"></a><span class='hs-comment'>-- mkLink link1 API -- typechecks, returns 'Link "/hello"'</span>
<a name="line-27"></a><span class='hs-comment'>--</span>
<a name="line-28"></a><span class='hs-comment'>-- mkLink link2 API -- doesn't typecheck</span>
<a name="line-29"></a><span class='hs-comment'>-- @</span>
<a name="line-30"></a><span class='hs-comment'>--</span>
<a name="line-31"></a><span class='hs-comment'>-- That is, 'mkLink' takes two arguments, a link proxy and a sitemap, and</span>
<a name="line-32"></a><span class='hs-comment'>-- returns a 'Link', but only typechecks if the link proxy is a valid link,</span>
<a name="line-33"></a><span class='hs-comment'>-- and part of the sitemap.</span>
<a name="line-34"></a><span class='hs-comment'>--</span>
<a name="line-35"></a><span class='hs-comment'>-- __N.B.:__ 'mkLink' assumes a capture matches any string (without slashes).</span>
<a name="line-36"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span><span class='hs-varop'>.</span><span class='hs-conid'>Links</span> <span class='hs-keyword'>where</span>
<a name="line-37"></a>
<a name="line-38"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-39"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>GHC</span><span class='hs-varop'>.</span><span class='hs-conid'>TypeLits</span>
<a name="line-40"></a>
<a name="line-41"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Capture</span>
<a name="line-42"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>ReqBody</span>
<a name="line-43"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>QueryParam</span>
<a name="line-44"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Get</span>
<a name="line-45"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Post</span>
<a name="line-46"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Put</span>
<a name="line-47"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Delete</span>
<a name="line-48"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Sub</span>
<a name="line-49"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Alternative</span>
<a name="line-50"></a>
<a name="line-51"></a>
<a name="line-52"></a><span class='hs-keyword'>type</span> <span class='hs-varid'>family</span> <span class='hs-conid'>Or</span> <span class='hs-varid'>a</span> <span class='hs-varid'>b</span> <span class='hs-keyword'>where</span>
<a name="line-53"></a> <span class='hs-conid'>Or</span> <span class='hs-chr'>'</span><span class='hs-conid'>False</span> <span class='hs-chr'>'</span><span class='hs-conid'>False</span> <span class='hs-keyglyph'>=</span> <span class='hs-chr'>'</span><span class='hs-conid'>False</span>
<a name="line-54"></a> <span class='hs-conid'>Or</span> <span class='hs-chr'>'</span><span class='hs-conid'>True</span> <span class='hs-varid'>b</span> <span class='hs-keyglyph'>=</span> <span class='hs-chr'>'</span><span class='hs-conid'>True</span>
<a name="line-55"></a> <span class='hs-conid'>Or</span> <span class='hs-varid'>a</span> <span class='hs-chr'>'</span><span class='hs-conid'>True</span> <span class='hs-keyglyph'>=</span> <span class='hs-chr'>'</span><span class='hs-conid'>True</span>
<a name="line-56"></a>
<a name="line-57"></a><span class='hs-keyword'>type</span> <span class='hs-varid'>family</span> <span class='hs-conid'>And</span> <span class='hs-varid'>a</span> <span class='hs-varid'>b</span> <span class='hs-keyword'>where</span>
<a name="line-58"></a> <span class='hs-conid'>And</span> <span class='hs-chr'>'</span><span class='hs-conid'>True</span> <span class='hs-chr'>'</span><span class='hs-conid'>True</span> <span class='hs-keyglyph'>=</span> <span class='hs-chr'>'</span><span class='hs-conid'>True</span>
<a name="line-59"></a> <span class='hs-conid'>And</span> <span class='hs-varid'>a</span> <span class='hs-chr'>'</span><span class='hs-conid'>False</span> <span class='hs-keyglyph'>=</span> <span class='hs-chr'>'</span><span class='hs-conid'>False</span>
<a name="line-60"></a> <span class='hs-conid'>And</span> <span class='hs-chr'>'</span><span class='hs-conid'>False</span> <span class='hs-varid'>b</span> <span class='hs-keyglyph'>=</span> <span class='hs-chr'>'</span><span class='hs-conid'>False</span>
<a name="line-61"></a>
<a name="line-62"></a><span class='hs-keyword'>type</span> <span class='hs-varid'>family</span> <span class='hs-conid'>IsElem</span> <span class='hs-varid'>a</span> <span class='hs-varid'>s</span> <span class='hs-keyword'>where</span>
<a name="line-63"></a> <span class='hs-conid'>IsElem</span> <span class='hs-varid'>e</span> <span class='hs-layout'>(</span><span class='hs-varid'>sa</span> <span class='hs-conop'>:&lt;|&gt;</span> <span class='hs-varid'>sb</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Or</span> <span class='hs-layout'>(</span><span class='hs-conid'>IsElem</span> <span class='hs-varid'>e</span> <span class='hs-varid'>sa</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>IsElem</span> <span class='hs-varid'>e</span> <span class='hs-varid'>sb</span><span class='hs-layout'>)</span>
<a name="line-64"></a> <span class='hs-conid'>IsElem</span> <span class='hs-layout'>(</span><span class='hs-varid'>e</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sa</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>e</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sb</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>IsElem</span> <span class='hs-varid'>sa</span> <span class='hs-varid'>sb</span>
<a name="line-65"></a> <span class='hs-conid'>IsElem</span> <span class='hs-layout'>(</span><span class='hs-varid'>e</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sa</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>Capture</span> <span class='hs-varid'>x</span> <span class='hs-varid'>y</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sb</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>IsElem</span> <span class='hs-varid'>sa</span> <span class='hs-varid'>sb</span>
<a name="line-66"></a> <span class='hs-conid'>IsElem</span> <span class='hs-varid'>sa</span> <span class='hs-layout'>(</span><span class='hs-conid'>ReqBody</span> <span class='hs-varid'>x</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sb</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>IsElem</span> <span class='hs-varid'>sa</span> <span class='hs-varid'>sb</span>
<a name="line-67"></a> <span class='hs-conid'>IsElem</span> <span class='hs-varid'>sa</span> <span class='hs-layout'>(</span><span class='hs-conid'>QueryParam</span> <span class='hs-varid'>x</span> <span class='hs-varid'>y</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>sb</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>IsElem</span> <span class='hs-varid'>sa</span> <span class='hs-varid'>sb</span>
<a name="line-68"></a> <span class='hs-conid'>IsElem</span> <span class='hs-varid'>e</span> <span class='hs-varid'>e</span> <span class='hs-keyglyph'>=</span> <span class='hs-chr'>'</span><span class='hs-conid'>True</span>
<a name="line-69"></a> <span class='hs-conid'>IsElem</span> <span class='hs-varid'>e</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-chr'>'</span><span class='hs-conid'>False</span>
<a name="line-70"></a>
<a name="line-71"></a><span class='hs-keyword'>type</span> <span class='hs-varid'>family</span> <span class='hs-conid'>IsLink''</span> <span class='hs-varid'>l</span> <span class='hs-keyword'>where</span>
<a name="line-72"></a> <span class='hs-conid'>IsLink''</span> <span class='hs-layout'>(</span><span class='hs-varid'>e</span> <span class='hs-conop'>:&gt;</span> <span class='hs-conid'>Get</span> <span class='hs-varid'>x</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>IsLink'</span> <span class='hs-varid'>e</span>
<a name="line-73"></a> <span class='hs-conid'>IsLink''</span> <span class='hs-layout'>(</span><span class='hs-varid'>e</span> <span class='hs-conop'>:&gt;</span> <span class='hs-conid'>Post</span> <span class='hs-varid'>x</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>IsLink'</span> <span class='hs-varid'>e</span>
<a name="line-74"></a> <span class='hs-conid'>IsLink''</span> <span class='hs-layout'>(</span><span class='hs-varid'>e</span> <span class='hs-conop'>:&gt;</span> <span class='hs-conid'>Put</span> <span class='hs-varid'>x</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>IsLink'</span> <span class='hs-varid'>e</span>
<a name="line-75"></a> <span class='hs-conid'>IsLink''</span> <span class='hs-layout'>(</span><span class='hs-varid'>e</span> <span class='hs-conop'>:&gt;</span> <span class='hs-conid'>Delete</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>IsLink'</span> <span class='hs-varid'>e</span>
<a name="line-76"></a> <span class='hs-conid'>IsLink''</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-chr'>'</span><span class='hs-conid'>False</span>
<a name="line-77"></a>
<a name="line-78"></a><span class='hs-keyword'>type</span> <span class='hs-varid'>family</span> <span class='hs-conid'>IsLink'</span> <span class='hs-varid'>e</span> <span class='hs-keyword'>where</span>
<a name="line-79"></a> <span class='hs-conid'>IsLink'</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Symbol</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-chr'>'</span><span class='hs-conid'>True</span>
<a name="line-80"></a>
<a name="line-81"></a><span class='hs-keyword'>type</span> <span class='hs-varid'>family</span> <span class='hs-conid'>IsLink</span> <span class='hs-varid'>e</span> <span class='hs-keyword'>where</span>
<a name="line-82"></a> <span class='hs-conid'>IsLink</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Or</span> <span class='hs-layout'>(</span><span class='hs-conid'>And</span> <span class='hs-layout'>(</span><span class='hs-conid'>IsLink'</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>IsLink''</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span>
<a name="line-83"></a> <span class='hs-layout'>(</span><span class='hs-conid'>IsLink''</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span>
<a name="line-84"></a>
<a name="line-85"></a>
<a name="line-86"></a><a name="ValidLinkIn"></a><span class='hs-comment'>-- | The 'ValidLinkIn f s' constraint holds when 's' is an API that</span>
<a name="line-87"></a><a name="ValidLinkIn"></a><span class='hs-comment'>-- contains 'f', and 'f' is a link.</span>
<a name="line-88"></a><a name="ValidLinkIn"></a><span class='hs-keyword'>class</span> <span class='hs-conid'>ValidLinkIn</span> <span class='hs-varid'>f</span> <span class='hs-varid'>s</span> <span class='hs-keyword'>where</span>
<a name="line-89"></a> <span class='hs-varid'>mkLink</span> <span class='hs-keyglyph'>::</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Link</span> <span class='hs-comment'>-- ^ This function will only typecheck if `f`</span>
<a name="line-90"></a> <span class='hs-comment'>-- is an URI within `s`</span>
<a name="line-91"></a>
<a name="line-92"></a><a name="instance%20ValidLinkIn%20f%20s"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span> <span class='hs-conid'>IsElem</span> <span class='hs-varid'>f</span> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>~</span> <span class='hs-chr'>'</span><span class='hs-conid'>True</span>
<a name="line-93"></a> <span class='hs-layout'>,</span> <span class='hs-conid'>IsLink</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>~</span> <span class='hs-chr'>'</span><span class='hs-conid'>True</span>
<a name="line-94"></a> <span class='hs-layout'>,</span> <span class='hs-conid'>VLinkHelper</span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>ValidLinkIn</span> <span class='hs-varid'>f</span> <span class='hs-varid'>s</span> <span class='hs-keyword'>where</span>
<a name="line-95"></a> <span class='hs-varid'>mkLink</span> <span class='hs-keyword'>_</span> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Link</span> <span class='hs-layout'>(</span><span class='hs-varid'>vlh</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span>
<a name="line-96"></a>
<a name="line-97"></a><a name="Link"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>Link</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Link</span> <span class='hs-conid'>String</span> <span class='hs-keyword'>deriving</span> <span class='hs-conid'>Show</span>
<a name="line-98"></a>
<a name="line-99"></a><a name="VLinkHelper"></a><span class='hs-keyword'>class</span> <span class='hs-conid'>VLinkHelper</span> <span class='hs-varid'>f</span> <span class='hs-keyword'>where</span>
<a name="line-100"></a> <span class='hs-varid'>vlh</span> <span class='hs-keyglyph'>::</span> <span class='hs-keyword'>forall</span> <span class='hs-varid'>proxy</span><span class='hs-varop'>.</span> <span class='hs-varid'>proxy</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>String</span>
<a name="line-101"></a>
<a name="line-102"></a><a name="instance%20VLinkHelper%20(s%20:%3e%20e)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>KnownSymbol</span> <span class='hs-varid'>s</span><span class='hs-layout'>,</span> <span class='hs-conid'>VLinkHelper</span> <span class='hs-varid'>e</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-conid'>VLinkHelper</span> <span class='hs-layout'>(</span><span class='hs-varid'>s</span> <span class='hs-conop'>:&gt;</span> <span class='hs-varid'>e</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-103"></a> <span class='hs-varid'>vlh</span> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>=</span> <span class='hs-str'>"/"</span> <span class='hs-varop'>++</span> <span class='hs-varid'>symbolVal</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>s</span><span class='hs-layout'>)</span> <span class='hs-varop'>++</span> <span class='hs-varid'>vlh</span> <span class='hs-layout'>(</span><span class='hs-conid'>Proxy</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Proxy</span> <span class='hs-varid'>e</span><span class='hs-layout'>)</span>
<a name="line-104"></a>
<a name="line-105"></a><a name="instance%20VLinkHelper%20(Get%20x)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>VLinkHelper</span> <span class='hs-layout'>(</span><span class='hs-conid'>Get</span> <span class='hs-varid'>x</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-106"></a> <span class='hs-varid'>vlh</span> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>=</span> <span class='hs-str'>""</span>
<a name="line-107"></a>
<a name="line-108"></a><a name="instance%20VLinkHelper%20(Post%20x)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>VLinkHelper</span> <span class='hs-layout'>(</span><span class='hs-conid'>Post</span> <span class='hs-varid'>x</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-109"></a> <span class='hs-varid'>vlh</span> <span class='hs-keyword'>_</span> <span class='hs-keyglyph'>=</span> <span class='hs-str'>""</span>
<a name="line-110"></a>
</pre></body>
</html>

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant/Utils/StaticFiles.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>-- | This module defines a sever-side handler that lets you serve static files.</span>
<a name="line-2"></a><span class='hs-comment'>--</span>
<a name="line-3"></a><span class='hs-comment'>-- - 'serveDirectory' lets you serve anything that lives under a particular</span>
<a name="line-4"></a><span class='hs-comment'>-- directory on your filesystem.</span>
<a name="line-5"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span><span class='hs-varop'>.</span><span class='hs-conid'>StaticFiles</span> <span class='hs-layout'>(</span>
<a name="line-6"></a> <span class='hs-varid'>serveDirectory</span><span class='hs-layout'>,</span>
<a name="line-7"></a> <span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-8"></a>
<a name="line-9"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Filesystem</span><span class='hs-varop'>.</span><span class='hs-conid'>Path</span><span class='hs-varop'>.</span><span class='hs-conid'>CurrentOS</span> <span class='hs-layout'>(</span><span class='hs-varid'>decodeString</span><span class='hs-layout'>)</span>
<a name="line-10"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Wai</span><span class='hs-varop'>.</span><span class='hs-conid'>Application</span><span class='hs-varop'>.</span><span class='hs-conid'>Static</span>
<a name="line-11"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-varop'>.</span><span class='hs-conid'>Raw</span>
<a name="line-12"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-13"></a>
<a name="line-14"></a><a name="serveDirectory"></a><span class='hs-comment'>-- | Serve anything under the specified directory as a 'Raw' endpoint.</span>
<a name="line-15"></a><span class='hs-comment'>--</span>
<a name="line-16"></a><span class='hs-comment'>-- @</span>
<a name="line-17"></a><span class='hs-comment'>-- type MyApi = "static" :&gt; Raw</span>
<a name="line-18"></a><span class='hs-comment'>--</span>
<a name="line-19"></a><span class='hs-comment'>-- server :: Server MyApi</span>
<a name="line-20"></a><span class='hs-comment'>-- server = serveDirectory "\/var\/www"</span>
<a name="line-21"></a><span class='hs-comment'>-- @</span>
<a name="line-22"></a><span class='hs-comment'>--</span>
<a name="line-23"></a><span class='hs-comment'>-- would capture any request to @\/static\/\&lt;something&gt;@ and look for</span>
<a name="line-24"></a><span class='hs-comment'>-- @\&lt;something&gt;@ under @\/var\/www@.</span>
<a name="line-25"></a><span class='hs-comment'>--</span>
<a name="line-26"></a><span class='hs-comment'>-- It will do its best to guess the MIME type for that file, based on the extension,</span>
<a name="line-27"></a><span class='hs-comment'>-- and send an appropriate /Content-Type/ header if possible.</span>
<a name="line-28"></a><span class='hs-comment'>--</span>
<a name="line-29"></a><span class='hs-comment'>-- If your goal is to serve HTML, CSS and Javascript files that use the rest of the API</span>
<a name="line-30"></a><span class='hs-comment'>-- as a webapp backend, you will most likely not want the static files to be hidden</span>
<a name="line-31"></a><span class='hs-comment'>-- behind a /\/static\// prefix. In that case, remember to put the 'serveDirectory'</span>
<a name="line-32"></a><span class='hs-comment'>-- handler in the last position, because /servant/ will try to match the handlers</span>
<a name="line-33"></a><span class='hs-comment'>-- in order.</span>
<a name="line-34"></a><span class='hs-definition'>serveDirectory</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>FilePath</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-conid'>Server</span> <span class='hs-conid'>Raw</span>
<a name="line-35"></a><span class='hs-definition'>serveDirectory</span> <span class='hs-varid'>documentRoot</span> <span class='hs-keyglyph'>=</span>
<a name="line-36"></a> <span class='hs-varid'>staticApp</span> <span class='hs-layout'>(</span><span class='hs-varid'>defaultFileServerSettings</span> <span class='hs-layout'>(</span><span class='hs-varid'>decodeString</span> <span class='hs-layout'>(</span><span class='hs-varid'>documentRoot</span> <span class='hs-varop'>++</span> <span class='hs-str'>"/"</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span>
</pre></body>
</html>

View file

@ -1,24 +0,0 @@
module Servant (
-- | This module and its submodules can be used to define servant APIs. Note
-- that these API definitions don't directly implement a server (or anything
-- else).
module Servant.API,
-- | For implementing servers for servant APIs.
module Servant.Server,
-- | Using your types in request paths and query string parameters
module Servant.Common.Text,
-- | Utilities on top of the servant core
module Servant.QQ,
module Servant.Utils.Links,
module Servant.Utils.StaticFiles,
-- | Useful re-exports
Proxy(..),
) where
import Data.Proxy
import Servant.API
import Servant.Common.Text
import Servant.Server
import Servant.QQ
import Servant.Utils.Links
import Servant.Utils.StaticFiles

35
src/Servant.html Normal file
View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Servant.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span> <span class='hs-layout'>(</span>
<a name="line-2"></a> <span class='hs-comment'>-- | This module and its submodules can be used to define servant APIs. Note</span>
<a name="line-3"></a> <span class='hs-comment'>-- that these API definitions don't directly implement a server (or anything</span>
<a name="line-4"></a> <span class='hs-comment'>-- else).</span>
<a name="line-5"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span><span class='hs-layout'>,</span>
<a name="line-6"></a> <span class='hs-comment'>-- | For implementing servers for servant APIs.</span>
<a name="line-7"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span><span class='hs-layout'>,</span>
<a name="line-8"></a> <span class='hs-comment'>-- | Using your types in request paths and query string parameters</span>
<a name="line-9"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Text</span><span class='hs-layout'>,</span>
<a name="line-10"></a> <span class='hs-comment'>-- | Utilities on top of the servant core</span>
<a name="line-11"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>QQ</span><span class='hs-layout'>,</span>
<a name="line-12"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span><span class='hs-varop'>.</span><span class='hs-conid'>Links</span><span class='hs-layout'>,</span>
<a name="line-13"></a> <span class='hs-keyword'>module</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span><span class='hs-varop'>.</span><span class='hs-conid'>StaticFiles</span><span class='hs-layout'>,</span>
<a name="line-14"></a> <span class='hs-comment'>-- | Useful re-exports</span>
<a name="line-15"></a> <span class='hs-conid'>Proxy</span><span class='hs-layout'>(</span><span class='hs-keyglyph'>..</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span>
<a name="line-16"></a> <span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-17"></a>
<a name="line-18"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Proxy</span>
<a name="line-19"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>API</span>
<a name="line-20"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Text</span>
<a name="line-21"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Server</span>
<a name="line-22"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>QQ</span>
<a name="line-23"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span><span class='hs-varop'>.</span><span class='hs-conid'>Links</span>
<a name="line-24"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Servant</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span><span class='hs-varop'>.</span><span class='hs-conid'>StaticFiles</span>
</pre></body>
</html>

View file

@ -1,51 +0,0 @@
module Servant.API (
-- * Combinators
-- | Type-level combinator for expressing subrouting: @':>'@
module Servant.API.Sub,
-- | Type-level combinator for alternative endpoints: @':<|>'@
module Servant.API.Alternative,
-- * Accessing information from the request
-- | Capturing parts of the url path as parsed values: @'Capture'@
module Servant.API.Capture,
-- | Retrieving parameters from the query string of the 'URI': @'QueryParam'@
module Servant.API.QueryParam,
-- | Accessing the request body as a JSON-encoded type: @'ReqBody'@
module Servant.API.ReqBody,
-- * Actual endpoints, distinguished by HTTP method
-- | GET requests
module Servant.API.Get,
-- | POST requests
module Servant.API.Post,
-- | DELETE requests
module Servant.API.Delete,
-- | PUT requests
module Servant.API.Put,
-- * Untyped endpoints
-- | Plugging in a wai 'Network.Wai.Application', serving directories
module Servant.API.Raw,
module Servant.Utils.StaticFiles,
-- * Utilities
-- | QuasiQuotes for endpoints
module Servant.QQ,
-- | Type-safe internal URLs
module Servant.Utils.Links,
) where
import Servant.API.Alternative
import Servant.API.Capture
import Servant.API.Delete
import Servant.API.Get
import Servant.API.Post
import Servant.API.Put
import Servant.API.QueryParam
import Servant.API.Raw
import Servant.API.ReqBody
import Servant.API.Sub
import Servant.QQ (sitemap)
import Servant.Utils.Links (mkLink)
import Servant.Utils.StaticFiles

View file

@ -1,39 +0,0 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Servant.API.Alternative where
import Data.Monoid
import Data.Proxy
import Servant.Server
-- | Union of two APIs, first takes precedence in case of overlap.
--
-- Example:
--
-- > type MyApi = "books" :> Get [Book] -- GET /books
-- > :<|> "books" :> ReqBody Book :> Post Book -- POST /books
data a :<|> b = a :<|> b
infixr 8 :<|>
-- | A server for @a ':<|>' b@ first tries to match the request again the route
-- represented by @a@ and if it fails tries @b@. You must provide a request
-- handler for each route.
--
-- > type MyApi = "books" :> Get [Book] -- GET /books
-- > :<|> "books" :> ReqBody Book :> Post Book -- POST /books
-- >
-- > server :: Server MyApi
-- > server = listAllBooks :<|> postBook
-- > where listAllBooks = ...
-- > postBook book = ...
instance (HasServer a, HasServer b) => HasServer (a :<|> b) where
type Server (a :<|> b) = Server a :<|> Server b
route Proxy (a :<|> b) request respond =
route pa a request $ \ mResponse ->
if isMismatch mResponse
then route pb b request $ \mResponse' -> respond (mResponse <> mResponse')
else respond mResponse
where pa = Proxy :: Proxy a
pb = Proxy :: Proxy b

View file

@ -1,60 +0,0 @@
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Servant.API.Capture (Capture) where
import Data.Proxy
import Data.Text
import GHC.TypeLits
import Network.Wai
import Servant.API.Sub
import Servant.Common.Text
import Servant.Server
-- | Capture a value from the request path under a certain type @a@.
--
-- Example:
--
-- > -- GET /books/:isbn
-- > type MyApi = "books" :> Capture "isbn" Text :> Get Book
data Capture sym a
captured :: FromText a => proxy (Capture sym a) -> Text -> Maybe a
captured _ = fromText
-- | If you use 'Capture' in one of the endpoints for your API,
-- this automatically requires your server-side handler to be a function
-- that takes an argument of the type specified by the 'Capture'.
-- This lets servant worry about getting it from the URL and turning
-- it into a value of the type you specify.
--
-- You can control how it'll be converted from 'Text' to your type
-- by simply providing an instance of 'FromText' for your type.
--
-- Example:
--
-- > type MyApi = "books" :> Capture "isbn" Text :> Get Book
-- >
-- > server :: Server MyApi
-- > server = getBook
-- > where getBook :: Text -> EitherT (Int, String) IO Book
-- > getBook isbn = ...
instance (KnownSymbol capture, FromText a, HasServer sublayout)
=> HasServer (Capture capture a :> sublayout) where
type Server (Capture capture a :> sublayout) =
a -> Server sublayout
route Proxy subserver request respond = case pathInfo request of
(first : rest)
-> case captured captureProxy first of
Nothing -> respond $ failWith NotFound
Just v -> route (Proxy :: Proxy sublayout) (subserver v) request{
pathInfo = rest
} respond
_ -> respond $ failWith NotFound
where captureProxy = Proxy :: Proxy (Capture capture a)

View file

@ -1,48 +0,0 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Servant.API.Delete where
import Control.Monad.Trans.Either
import Data.Proxy
import Data.String.Conversions
import Data.Typeable
import Network.HTTP.Types
import Network.Wai
import Servant.Server
-- | Combinator for DELETE requests.
--
-- Example:
--
-- > -- DELETE /books/:isbn
-- > type MyApi = "books" :> Capture "isbn" Text :> Delete
data Delete
deriving Typeable
-- | If you have a 'Delete' endpoint in your API,
-- the handler for this endpoint is meant to delete
-- a resource.
--
-- The code of the handler will, just like
-- for 'Servant.API.Get.Get', 'Servant.API.Post.Post' and
-- 'Servant.API.Put.Put', run in @EitherT (Int, String) IO ()@.
-- The 'Int' represents the status code and the 'String' a message
-- to be returned. You can use 'Control.Monad.Trans.Either.left' to
-- painlessly error out if the conditions for a successful deletion
-- are not met.
instance HasServer Delete where
type Server Delete = EitherT (Int, String) IO ()
route Proxy action request respond
| null (pathInfo request) && requestMethod request == methodDelete = do
e <- runEitherT action
respond $ succeedWith $ case e of
Right () ->
responseLBS status204 [] ""
Left (status, message) ->
responseLBS (mkStatus status (cs message)) [] (cs message)
| null (pathInfo request) && requestMethod request /= methodDelete =
respond $ failWith WrongMethod
| otherwise = respond $ failWith NotFound

View file

@ -1,47 +0,0 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Servant.API.Get where
import Control.Monad.Trans.Either
import Data.Aeson
import Data.Proxy
import Data.String.Conversions
import Data.Typeable
import Network.HTTP.Types
import Network.Wai
import Servant.Server
-- | Endpoint for simple GET requests. Serves the result as JSON.
--
-- Example:
--
-- > type MyApi = "books" :> Get [Book]
data Get a
deriving Typeable
-- | When implementing the handler for a 'Get' endpoint,
-- just like for 'Servant.API.Delete.Delete', 'Servant.API.Post.Post'
-- and 'Servant.API.Put.Put', the handler code runs in the
-- @EitherT (Int, String) IO@ monad, where the 'Int' represents
-- the status code and the 'String' a message, returned in case of
-- failure. You can quite handily use 'Control.Monad.Trans.EitherT.left'
-- to quickly fail if some conditions are not met.
--
-- If successfully returning a value, we just require that its type has
-- a 'ToJSON' instance and servant takes care of encoding it for you,
-- yielding status code 200 along the way.
instance ToJSON result => HasServer (Get result) where
type Server (Get result) = EitherT (Int, String) IO result
route Proxy action request respond
| null (pathInfo request) && requestMethod request == methodGet = do
e <- runEitherT action
respond . succeedWith $ case e of
Right output ->
responseLBS ok200 [("Content-Type", "application/json")] (encode output)
Left (status, message) ->
responseLBS (mkStatus status (cs message)) [] (cs message)
| null (pathInfo request) && requestMethod request /= methodGet =
respond $ failWith WrongMethod
| otherwise = respond $ failWith NotFound

View file

@ -1,53 +0,0 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Servant.API.Post where
import Control.Monad.Trans.Either
import Data.Aeson
import Data.Proxy
import Data.String.Conversions
import Data.Typeable
import Network.HTTP.Types
import Network.Wai
import Servant.Server
-- | Endpoint for POST requests. The type variable represents the type of the
-- response body (not the request body, use 'Servant.API.RQBody.RQBody' for
-- that).
--
-- Example:
--
-- > -- POST /books
-- > -- with a JSON encoded Book as the request body
-- > -- returning the just-created Book
-- > type MyApi = "books" :> ReqBody Book :> Post Book
data Post a
deriving Typeable
-- | When implementing the handler for a 'Post' endpoint,
-- just like for 'Servant.API.Delete.Delete', 'Servant.API.Get.Get'
-- and 'Servant.API.Put.Put', the handler code runs in the
-- @EitherT (Int, String) IO@ monad, where the 'Int' represents
-- the status code and the 'String' a message, returned in case of
-- failure. You can quite handily use 'Control.Monad.Trans.EitherT.left'
-- to quickly fail if some conditions are not met.
--
-- If successfully returning a value, we just require that its type has
-- a 'ToJSON' instance and servant takes care of encoding it for you,
-- yielding status code 201 along the way.
instance ToJSON a => HasServer (Post a) where
type Server (Post a) = EitherT (Int, String) IO a
route Proxy action request respond
| null (pathInfo request) && requestMethod request == methodPost = do
e <- runEitherT action
respond . succeedWith $ case e of
Right out ->
responseLBS status201 [("Content-Type", "application/json")] (encode out)
Left (status, message) ->
responseLBS (mkStatus status (cs message)) [] (cs message)
| null (pathInfo request) && requestMethod request /= methodPost =
respond $ failWith WrongMethod
| otherwise = respond $ failWith NotFound

View file

@ -1,52 +0,0 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Servant.API.Put where
import Control.Monad.Trans.Either
import Data.Aeson
import Data.Proxy
import Data.String.Conversions
import Data.Typeable
import Network.HTTP.Types
import Network.Wai
import Servant.Server
-- | Endpoint for PUT requests, usually used to update a ressource.
-- The type @a@ is the type of the response body that's returned.
--
-- Example:
--
-- > -- PUT /books/:isbn
-- > -- with a Book as request body, returning the updated Book
-- > type MyApi = "books" :> Capture "isbn" Text :> ReqBody Book :> Put Book
data Put a
deriving Typeable
-- | When implementing the handler for a 'Put' endpoint,
-- just like for 'Servant.API.Delete.Delete', 'Servant.API.Get.Get'
-- and 'Servant.API.Post.Post', the handler code runs in the
-- @EitherT (Int, String) IO@ monad, where the 'Int' represents
-- the status code and the 'String' a message, returned in case of
-- failure. You can quite handily use 'Control.Monad.Trans.EitherT.left'
-- to quickly fail if some conditions are not met.
--
-- If successfully returning a value, we just require that its type has
-- a 'ToJSON' instance and servant takes care of encoding it for you,
-- yielding status code 200 along the way.
instance ToJSON a => HasServer (Put a) where
type Server (Put a) = EitherT (Int, String) IO a
route Proxy action request respond
| null (pathInfo request) && requestMethod request == methodPut = do
e <- runEitherT action
respond . succeedWith $ case e of
Right out ->
responseLBS ok200 [("Content-Type", "application/json")] (encode out)
Left (status, message) ->
responseLBS (mkStatus status (cs message)) [] (cs message)
| null (pathInfo request) && requestMethod request /= methodPut =
respond $ failWith WrongMethod
| otherwise = respond $ failWith NotFound

View file

@ -1,162 +0,0 @@
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Servant.API.QueryParam where
import Data.Maybe
import Data.Proxy
import Data.String.Conversions
import GHC.TypeLits
import Network.HTTP.Types
import Network.Wai
import Servant.API.Sub
import Servant.Common.Text
import Servant.Server
-- | Lookup the value associated to the @sym@ query string parameter
-- and try to extract it as a value of type @a@.
--
-- Example:
--
-- > -- /books?author=<author name>
-- > type MyApi = "books" :> QueryParam "author" Text :> Get [Book]
data QueryParam sym a
-- | If you use @'QueryParam' "author" Text@ in one of the endpoints for your API,
-- this automatically requires your server-side handler to be a function
-- that takes an argument of type @'Maybe' 'Text'@.
--
-- This lets servant worry about looking it up in the query string
-- and turning it into a value of the type you specify, enclosed
-- in 'Maybe', because it may not be there and servant would then
-- hand you 'Nothing'.
--
-- You can control how it'll be converted from 'Text' to your type
-- by simply providing an instance of 'FromText' for your type.
--
-- Example:
--
-- > type MyApi = "books" :> QueryParam "author" Text :> Get [Book]
-- >
-- > server :: Server MyApi
-- > server = getBooksBy
-- > where getBooksBy :: Maybe Text -> EitherT (Int, String) IO [Book]
-- > getBooksBy Nothing = ...return all books...
-- > getBooksBy (Just author) = ...return books by the given author...
instance (KnownSymbol sym, FromText a, HasServer sublayout)
=> HasServer (QueryParam sym a :> sublayout) where
type Server (QueryParam sym a :> sublayout) =
Maybe a -> Server sublayout
route Proxy subserver request respond = do
let querytext = parseQueryText $ rawQueryString request
param =
case lookup paramname querytext of
Nothing -> Nothing -- param absent from the query string
Just Nothing -> Nothing -- param present with no value -> Nothing
Just (Just v) -> fromText v -- if present, we try to convert to
-- the right type
route (Proxy :: Proxy sublayout) (subserver param) request respond
where paramname = cs $ symbolVal (Proxy :: Proxy sym)
-- | Lookup the values associated to the @sym@ query string parameter
-- and try to extract it as a value of type @[a]@. This is typically
-- meant to support query string parameters of the form
-- @param[]=val1&param[]=val2@ and so on. Note that servant doesn't actually
-- require the @[]@s and will fetch the values just fine with
-- @param=val1&param=val2@, too.
--
-- Example:
--
-- > -- /books?authors[]=<author1>&authors[]=<author2>&...
-- > type MyApi = "books" :> QueryParams "authors" Text :> Get [Book]
data QueryParams sym a
-- | If you use @'QueryParams' "authors" Text@ in one of the endpoints for your API,
-- this automatically requires your server-side handler to be a function
-- that takes an argument of type @['Text']@.
--
-- This lets servant worry about looking up 0 or more values in the query string
-- associated to @authors@ and turning each of them into a value of
-- the type you specify.
--
-- You can control how the individual values are converted from 'Text' to your type
-- by simply providing an instance of 'FromText' for your type.
--
-- Example:
--
-- > type MyApi = "books" :> QueryParams "authors" Text :> Get [Book]
-- >
-- > server :: Server MyApi
-- > server = getBooksBy
-- > where getBooksBy :: [Text] -> EitherT (Int, String) IO [Book]
-- > getBooksBy authors = ...return all books by these authors...
instance (KnownSymbol sym, FromText a, HasServer sublayout)
=> HasServer (QueryParams sym a :> sublayout) where
type Server (QueryParams sym a :> sublayout) =
[a] -> Server sublayout
route Proxy subserver request respond = do
let querytext = parseQueryText $ rawQueryString request
-- if sym is "foo", we look for query string parameters
-- named "foo" or "foo[]" and call fromText on the
-- corresponding values
parameters = filter looksLikeParam querytext
values = catMaybes $ map (convert . snd) parameters
route (Proxy :: Proxy sublayout) (subserver values) request respond
where paramname = cs $ symbolVal (Proxy :: Proxy sym)
looksLikeParam (name, _) = name == paramname || name == (paramname <> "[]")
convert Nothing = Nothing
convert (Just v) = fromText v
-- | Lookup a potentially value-less query string parameter
-- with boolean semantics. If the param @sym@ is there without any value,
-- or if it's there with value "true" or "1", it's interpreted as 'True'.
-- Otherwise, it's interpreted as 'False'.
--
-- Example:
--
-- > -- /books?published
-- > type MyApi = "books" :> QueryFlag "published" :> Get [Book]
data QueryFlag sym
-- | If you use @'QueryFlag' "published"@ in one of the endpoints for your API,
-- this automatically requires your server-side handler to be a function
-- that takes an argument of type 'Bool'.
--
-- Example:
--
-- > type MyApi = "books" :> QueryFlag "published" :> Get [Book]
-- >
-- > server :: Server MyApi
-- > server = getBooks
-- > where getBooks :: Bool -> EitherT (Int, String) IO [Book]
-- > getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument...
instance (KnownSymbol sym, HasServer sublayout)
=> HasServer (QueryFlag sym :> sublayout) where
type Server (QueryFlag sym :> sublayout) =
Bool -> Server sublayout
route Proxy subserver request respond = do
let querytext = parseQueryText $ rawQueryString request
param = case lookup paramname querytext of
Just Nothing -> True -- param is there, with no value
Just (Just v) -> examine v -- param with a value
Nothing -> False -- param not in the query string
route (Proxy :: Proxy sublayout) (subserver param) request respond
where paramname = cs $ symbolVal (Proxy :: Proxy sym)
examine v | v == "true" || v == "1" || v == "" = True
| otherwise = False

View file

@ -1,32 +0,0 @@
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
module Servant.API.Raw where
import Data.Proxy
import Network.Wai
import Servant.Server
-- | Endpoint for plugging in your own Wai 'Application's.
--
-- The given 'Application' will get the request as received by the server, potentially with
-- a modified (stripped) 'pathInfo' if the 'Application' is being routed with 'Servant.API.Sub.:>'.
--
-- In addition to just letting you plug in your existing WAI 'Application's,
-- this can also be used with 'Servant.Utils.StaticFiles.serveDirectory' to serve
-- static files stored in a particular directory on your filesystem, or to serve
-- your API's documentation with 'Servant.Utils.StaticFiles.serveDocumentation'.
data Raw
-- | Just pass the request to the underlying application and serve its response.
--
-- Example:
--
-- > type MyApi = "images" :> Raw
-- >
-- > server :: Server MyApi
-- > server = serveDirectory "/var/www/images"
instance HasServer Raw where
type Server Raw = Application
route Proxy rawApplication request respond =
rawApplication request (respond . succeedWith)

View file

@ -1,49 +0,0 @@
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Servant.API.ReqBody where
import Control.Applicative
import Data.Aeson
import Data.Proxy
import Network.Wai
import Servant.API.Sub
import Servant.Server
-- | Extract the request body as a value of type @a@.
--
-- Example:
--
-- > -- POST /books
-- > type MyApi = "books" :> ReqBody Book :> Post Book
data ReqBody a
-- | If you use 'ReqBody' in one of the endpoints for your API,
-- this automatically requires your server-side handler to be a function
-- that takes an argument of the type specified by 'ReqBody'.
-- This lets servant worry about extracting it from the request and turning
-- it into a value of the type you specify.
--
-- All it asks is for a 'FromJSON' instance.
--
-- Example:
--
-- > type MyApi = "books" :> ReqBody Book :> Post Book
-- >
-- > server :: Server MyApi
-- > server = postBook
-- > where postBook :: Book -> EitherT (Int, String) IO Book
-- > postBook book = ...insert into your db...
instance (FromJSON a, HasServer sublayout)
=> HasServer (ReqBody a :> sublayout) where
type Server (ReqBody a :> sublayout) =
a -> Server sublayout
route Proxy subserver request respond = do
mrqbody <- decode' <$> lazyRequestBody request
case mrqbody of
Nothing -> respond $ failWith InvalidBody
Just v -> route (Proxy :: Proxy sublayout) (subserver v) request respond

View file

@ -1,36 +0,0 @@
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Servant.API.Sub where
import Data.Proxy
import Data.String.Conversions
import GHC.TypeLits
import Network.Wai
import Servant.Server
-- | The contained API (second argument) can be found under @("/" ++ path)@
-- (path being the first argument).
--
-- Example:
--
-- > -- GET /hello/world
-- > -- returning a JSON encoded World value
-- > type MyApi = "hello" :> "world" :> Get World
data (path :: k) :> a = Proxy path :> a
infixr 9 :>
-- | Make sure the incoming request starts with @"/path"@, strip it and
-- pass the rest of the request path to @sublayout@.
instance (KnownSymbol path, HasServer sublayout) => HasServer (path :> sublayout) where
type Server (path :> sublayout) = Server sublayout
route Proxy subserver request respond = case pathInfo request of
(first : rest)
| first == cs (symbolVal proxyPath)
-> route (Proxy :: Proxy sublayout) subserver request{
pathInfo = rest
} respond
_ -> respond $ failWith NotFound
where proxyPath = Proxy :: Proxy path

View file

@ -1,130 +0,0 @@
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Servant.Common.Text
( FromText(..)
, ToText(..)
) where
import Data.String.Conversions
import Data.Int
import Data.Text
import Data.Text.Read
import Data.Word
-- | For getting values from url captures and query string parameters
class FromText a where
fromText :: Text -> Maybe a
-- | For putting values in paths and query string parameters
class ToText a where
toText :: a -> Text
instance FromText Text where
fromText = Just
instance ToText Text where
toText = id
instance FromText String where
fromText = Just . cs
instance ToText String where
toText = cs
-- |
-- > fromText "true" = Just True
-- > fromText "false" = Just False
-- > fromText _ = Nothing
instance FromText Bool where
fromText "true" = Just True
fromText "false" = Just False
fromText _ = Nothing
-- |
-- > toText True = "true"
-- > toText False = "false"
instance ToText Bool where
toText True = "true"
toText False = "false"
instance FromText Int where
fromText = runReader (signed decimal)
instance ToText Int where
toText = cs . show
instance FromText Int8 where
fromText = runReader (signed decimal)
instance ToText Int8 where
toText = cs . show
instance FromText Int16 where
fromText = runReader (signed decimal)
instance ToText Int16 where
toText = cs . show
instance FromText Int32 where
fromText = runReader (signed decimal)
instance ToText Int32 where
toText = cs . show
instance FromText Int64 where
fromText = runReader (signed decimal)
instance ToText Int64 where
toText = cs . show
instance FromText Word where
fromText = runReader decimal
instance ToText Word where
toText = cs . show
instance FromText Word8 where
fromText = runReader decimal
instance ToText Word8 where
toText = cs . show
instance FromText Word16 where
fromText = runReader decimal
instance ToText Word16 where
toText = cs . show
instance FromText Word32 where
fromText = runReader decimal
instance ToText Word32 where
toText = cs . show
instance FromText Word64 where
fromText = runReader decimal
instance ToText Word64 where
toText = cs . show
instance FromText Integer where
fromText = runReader decimal
instance ToText Integer where
toText = cs . show
instance FromText Double where
fromText = runReader rational
instance ToText Double where
toText = cs . show
instance FromText Float where
fromText = runReader rational
instance ToText Float where
toText = cs . show
runReader :: Reader a -> Text -> Maybe a
runReader reader t = either (const Nothing) (Just . fst) $ reader t

View file

@ -1,198 +0,0 @@
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
-- | QuasiQuoting utilities for API types.
--
-- 'sitemap' allows you to write your type in a very natural way:
--
-- @
-- [sitemap|
-- PUT hello String -> ()
-- POST hello/p:Int String -> ()
-- GET hello/?name:String Int
-- |]
-- @
--
-- Will generate:
--
-- @
-- "hello" :> ReqBody String :> Put ()
-- :\<|> "hello" :> Capture "p" Int :> ReqBody String :> Post ()
-- :\<|> "hello" :> QueryParam "name" String :> Get Int
-- @
--
-- Note the @/@ before a @QueryParam@!
module Servant.QQ where
import Control.Monad (void)
import Control.Applicative hiding (many, (<|>), optional)
import Language.Haskell.TH.Quote
import Language.Haskell.TH
import Text.ParserCombinators.Parsec
import Servant.API.Capture
import Servant.API.Get
import Servant.API.Post
import Servant.API.Put
import Servant.API.Delete
import Servant.API.QueryParam
import Servant.API.ReqBody
import Servant.API.Sub
import Servant.API.Alternative
-- | Finally-tagless encoding for our DSL.
-- Keeping 'repr'' and 'repr' distinct when writing functions with an
-- @ExpSYM@ context ensures certain invariants (for instance, that there is
-- only one of 'get', 'post', 'put', and 'delete' in a value), but
-- sometimes requires a little more work.
class ExpSYM repr' repr | repr -> repr', repr' -> repr where
lit :: String -> repr' -> repr
capture :: String -> String -> repr -> repr
reqBody :: String -> repr -> repr
queryParam :: String -> String -> repr -> repr
conj :: repr' -> repr -> repr
get :: String -> repr
post :: String -> repr
put :: String -> repr
delete :: String -> repr
infixr 6 >:
(>:) :: Type -> Type -> Type
(>:) = conj
instance ExpSYM Type Type where
lit name r = LitT (StrTyLit name) >: r
capture name typ r = AppT (AppT (ConT ''Capture) (LitT (StrTyLit name)))
(ConT $ mkName typ) >: r
reqBody typ r = AppT (ConT ''ReqBody) (ConT $ mkName typ) >: r
queryParam name typ r = AppT (AppT (ConT ''QueryParam) (LitT (StrTyLit name)))
(ConT $ mkName typ) >: r
conj x = AppT (AppT (ConT ''(:>)) x)
get typ = AppT (ConT ''Get) (ConT $ mkName typ)
post typ = AppT (ConT ''Post) (ConT $ mkName typ)
put typ = AppT (ConT ''Put) (ConT $ mkName typ)
delete "()" = ConT ''Delete
delete _ = error "Delete does not return a request body"
parseMethod :: ExpSYM repr' repr => Parser (String -> repr)
parseMethod = try (string "GET" >> return get)
<|> try (string "POST" >> return post)
<|> try (string "PUT" >> return put)
<|> try (string "DELETE" >> return delete)
parseUrlSegment :: ExpSYM repr repr => Parser (repr -> repr)
parseUrlSegment = try parseCapture
<|> try parseQueryParam
<|> try parseLit
where
parseCapture = do
cname <- many (noneOf " ?/:")
char ':'
ctyp <- many (noneOf " ?/:")
return $ capture cname ctyp
parseQueryParam = do
char '?'
cname <- many (noneOf " ?/:")
char ':'
ctyp <- many (noneOf " ?/:")
return $ queryParam cname ctyp
parseLit = lit <$> many (noneOf " ?/:")
parseUrl :: ExpSYM repr repr => Parser (repr -> repr)
parseUrl = do
optional $ char '/'
url <- parseUrlSegment `sepBy1` char '/'
return $ foldr1 (.) url
data Typ = Val String
| ReqArgVal String String
parseTyp :: Parser Typ
parseTyp = do
f <- many (noneOf "-{\n\r")
spaces
s <- optionMaybe (try parseRet)
try $ optional inlineComment
try $ optional blockComment
case s of
Nothing -> return $ Val (stripTr f)
Just s' -> return $ ReqArgVal (stripTr f) (stripTr s')
where
parseRet :: Parser String
parseRet = do
string "->"
spaces
many (noneOf "-{\n\r")
stripTr = reverse . dropWhile (== ' ') . reverse
parseEntry :: ExpSYM repr repr => Parser repr
parseEntry = do
met <- parseMethod
spaces
url <- parseUrl
spaces
typ <- parseTyp
case typ of
Val s -> return $ url (met s)
ReqArgVal i o -> return $ url $ reqBody i (met o)
blockComment :: Parser ()
blockComment = do
string "{-"
manyTill anyChar (try $ string "-}")
return ()
inlineComment :: Parser ()
inlineComment = do
string "--"
manyTill anyChar (try $ lookAhead eol)
return ()
eol :: Parser String
eol = try (string "\n\r")
<|> try (string "\r\n")
<|> string "\n"
<|> string "\r"
<?> "end of line"
eols :: Parser ()
eols = skipMany $ void eol <|> blockComment <|> inlineComment
parseAll :: Parser Type
parseAll = do
eols
entries <- parseEntry `endBy` eols
return $ foldr1 union entries
where union :: Type -> Type -> Type
union a = AppT (AppT (ConT ''(:<|>)) a)
-- | The sitemap QuasiQuoter.
--
-- * @.../<var>:<type>/...@ becomes a capture
-- * @.../?<var>:<type>@ becomes a query parameter
-- * @<method> ... <typ>@ becomes a method returning @<typ>@
-- * @<method> ... <typ1> -> <typ2>@ becomes a method with request
-- body of @<typ1>@ and returning @<typ2>@
--
-- Comments are allowed, and have the standard Haskell format
--
-- * @--@ for inline
-- * @{- ... -}@ for block
--
sitemap :: QuasiQuoter
sitemap = QuasiQuoter { quoteExp = undefined
, quotePat = undefined
, quoteType = \x -> case parse parseAll "" x of
Left err -> error $ show err
Right st -> return st
, quoteDec = undefined
}

View file

@ -1,105 +0,0 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
-- | This module lets you implement 'Server's for defined APIs. You'll
-- most likely just need 'serve'.
module Servant.Server where
import Data.Monoid
import Data.Proxy
import Network.HTTP.Types
import Network.Wai
-- * Implementing Servers
-- | 'serve' allows you to implement an API and produce a wai 'Application'.
--
-- Example:
--
-- > type MyApi = "books" :> Get [Book] -- GET /books
-- > :<|> "books" :> ReqBody Book :> Post Book -- POST /books
-- >
-- > server :: Server MyApi
-- > server = listAllBooks :<|> postBook
-- > where listAllBooks = ...
-- > postBook book = ...
-- >
-- > app :: Application
-- > app = serve myApi server
-- >
-- > main :: IO ()
-- > main = Network.Wai.Handler.Warp.run 8080 app
serve :: HasServer layout => Proxy layout -> Server layout -> Application
serve p server = toApplication (route p server)
toApplication :: RoutingApplication -> Application
toApplication ra request respond = do
ra request (routingRespond . routeResult)
where
routingRespond :: Either RouteMismatch Response -> IO ResponseReceived
routingRespond (Left NotFound) =
respond $ responseLBS notFound404 [] "not found"
routingRespond (Left WrongMethod) =
respond $ responseLBS methodNotAllowed405 [] "method not allowed"
routingRespond (Left InvalidBody) =
respond $ responseLBS badRequest400 [] "Invalid JSON in request body"
routingRespond (Right response) =
respond response
-- * Route mismatch
data RouteMismatch =
NotFound -- ^ the usual "not found" error
| WrongMethod -- ^ a more informative "you just got the HTTP method wrong" error
| InvalidBody -- ^ an even more informative "your json request body wasn't valid" error
deriving (Eq, Show)
-- |
-- @
-- > mempty = NotFound
-- >
-- > NotFound `mappend` x = x
-- > WrongMethod `mappend` InvalidBody = InvalidBody
-- > WrongMethod `mappend` _ = WrongMethod
-- > InvalidBody `mappend` _ = InvalidBody
-- @
instance Monoid RouteMismatch where
mempty = NotFound
NotFound `mappend` x = x
WrongMethod `mappend` InvalidBody = InvalidBody
WrongMethod `mappend` _ = WrongMethod
InvalidBody `mappend` _ = InvalidBody
-- | A wrapper around @'Either' 'RouteMismatch' a@.
newtype RouteResult a =
RR { routeResult :: Either RouteMismatch a }
deriving (Eq, Show)
failWith :: RouteMismatch -> RouteResult a
failWith = RR . Left
succeedWith :: a -> RouteResult a
succeedWith = RR . Right
isMismatch :: RouteResult a -> Bool
isMismatch (RR (Left _)) = True
isMismatch _ = False
-- | If we get a `Right`, it has precedence over everything else.
--
-- This in particular means that if we could get several 'Right's,
-- only the first we encounter would be taken into account.
instance Monoid (RouteResult a) where
mempty = RR $ Left mempty
RR (Left x) `mappend` RR (Left y) = RR $ Left (x <> y)
RR (Left _) `mappend` RR (Right y) = RR $ Right y
r `mappend` _ = r
type RoutingApplication =
Request -- ^ the request, the field 'pathInfo' may be modified by url routing
-> (RouteResult Response -> IO ResponseReceived) -> IO ResponseReceived
class HasServer layout where
type Server layout :: *
route :: Proxy layout -> Server layout -> RoutingApplication

View file

@ -1,110 +0,0 @@
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
-- | Type safe internal links.
--
-- Provides the function 'mkLink':
--
-- @
-- type API = Proxy ("hello" :> Get Int
-- :<|> "bye" :> QueryParam "name" String :> Post Bool)
--
-- api :: API
-- api = proxy
--
-- link1 :: Proxy ("hello" :> Get Int)
-- link1 = proxy
--
-- link2 :: Proxy ("hello" :> Delete)
-- link2 = proxy
--
-- mkLink link1 API -- typechecks, returns 'Link "/hello"'
--
-- mkLink link2 API -- doesn't typecheck
-- @
--
-- That is, 'mkLink' takes two arguments, a link proxy and a sitemap, and
-- returns a 'Link', but only typechecks if the link proxy is a valid link,
-- and part of the sitemap.
--
-- __N.B.:__ 'mkLink' assumes a capture matches any string (without slashes).
module Servant.Utils.Links where
import Data.Proxy
import GHC.TypeLits
import Servant.API.Capture
import Servant.API.ReqBody
import Servant.API.QueryParam
import Servant.API.Get
import Servant.API.Post
import Servant.API.Put
import Servant.API.Delete
import Servant.API.Sub
import Servant.API.Alternative
type family Or a b where
Or 'False 'False = 'False
Or 'True b = 'True
Or a 'True = 'True
type family And a b where
And 'True 'True = 'True
And a 'False = 'False
And 'False b = 'False
type family IsElem a s where
IsElem e (sa :<|> sb) = Or (IsElem e sa) (IsElem e sb)
IsElem (e :> sa) (e :> sb) = IsElem sa sb
IsElem (e :> sa) (Capture x y :> sb) = IsElem sa sb
IsElem sa (ReqBody x :> sb) = IsElem sa sb
IsElem sa (QueryParam x y :> sb) = IsElem sa sb
IsElem e e = 'True
IsElem e a = 'False
type family IsLink'' l where
IsLink'' (e :> Get x) = IsLink' e
IsLink'' (e :> Post x) = IsLink' e
IsLink'' (e :> Put x) = IsLink' e
IsLink'' (e :> Delete) = IsLink' e
IsLink'' a = 'False
type family IsLink' e where
IsLink' (f :: Symbol) = 'True
type family IsLink e where
IsLink (a :> b) = Or (And (IsLink' a) (IsLink'' b))
(IsLink'' (a :> b))
-- | The 'ValidLinkIn f s' constraint holds when 's' is an API that
-- contains 'f', and 'f' is a link.
class ValidLinkIn f s where
mkLink :: f -> s -> Link -- ^ This function will only typecheck if `f`
-- is an URI within `s`
instance ( IsElem f s ~ 'True
, IsLink f ~ 'True
, VLinkHelper f) => ValidLinkIn f s where
mkLink _ _ = Link (vlh (Proxy :: Proxy f))
data Link = Link String deriving Show
class VLinkHelper f where
vlh :: forall proxy. proxy f -> String
instance (KnownSymbol s, VLinkHelper e) => VLinkHelper (s :> e) where
vlh _ = "/" ++ symbolVal (Proxy :: Proxy s) ++ vlh (Proxy :: Proxy e)
instance VLinkHelper (Get x) where
vlh _ = ""
instance VLinkHelper (Post x) where
vlh _ = ""

View file

@ -1,36 +0,0 @@
-- | This module defines a sever-side handler that lets you serve static files.
--
-- - 'serveDirectory' lets you serve anything that lives under a particular
-- directory on your filesystem.
module Servant.Utils.StaticFiles (
serveDirectory,
) where
import Filesystem.Path.CurrentOS (decodeString)
import Network.Wai.Application.Static
import Servant.API.Raw
import Servant.Server
-- | Serve anything under the specified directory as a 'Raw' endpoint.
--
-- @
-- type MyApi = "static" :> Raw
--
-- server :: Server MyApi
-- server = serveDirectory "\/var\/www"
-- @
--
-- would capture any request to @\/static\/\<something>@ and look for
-- @\<something>@ under @\/var\/www@.
--
-- It will do its best to guess the MIME type for that file, based on the extension,
-- and send an appropriate /Content-Type/ header if possible.
--
-- If your goal is to serve HTML, CSS and Javascript files that use the rest of the API
-- as a webapp backend, you will most likely not want the static files to be hidden
-- behind a /\/static\// prefix. In that case, remember to put the 'serveDirectory'
-- handler in the last position, because /servant/ will try to match the handlers
-- in order.
serveDirectory :: FilePath -> Server Raw
serveDirectory documentRoot =
staticApp (defaultFileServerSettings (decodeString (documentRoot ++ "/")))

5
src/hscolour.css Normal file
View file

@ -0,0 +1,5 @@
.hs-keyglyph, .hs-layout {color: red;}
.hs-keyword {color: blue;}
.hs-comment, .hs-comment a {color: green;}
.hs-str, .hs-chr {color: teal;}
.hs-keyword, .hs-conid, .hs-varid, .hs-conop, .hs-varop, .hs-num, .hs-cpp, .hs-sel, .hs-definition {}

BIN
synopsis.png Normal file

Binary file not shown.

After

(image error) Size: 11 KiB

View file

@ -1,177 +0,0 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Servant.QQSpec where
import Test.Hspec
import Servant.API
--------------------------------------------------------------------------
-- Types for testing
--------------------------------------------------------------------------
-- Methods ---------------------------------------------------------------
type SimpleGet = [sitemap|
GET hello ()
|]
type SimpleGet' = "hello" :> Get ()
type SimpleGet'' = "hello" :> Get Bool
type SimpleGet2 = [sitemap|
GET hello Bool
|]
type SimpleGet2' = "hello" :> Get Bool
type SimpleGet2'' = "hello" :> Get Int
type SimplePost = [sitemap|
POST hello ()
|]
type SimplePost' = "hello" :> Post ()
type SimplePost'' = "hello" :> Post Bool
type SimplePost2 = [sitemap|
POST hello Bool
|]
type SimplePost2' = "hello" :> Post Bool
type SimplePost2'' = "hello" :> Post ()
type SimplePut = [sitemap|
PUT hello ()
|]
type SimplePut' = "hello" :> Put ()
type SimplePut'' = "hello" :> Put Bool
type SimplePut2 = [sitemap|
PUT hello Bool
|]
type SimplePut2' = "hello" :> Put Bool
type SimplePut2'' = "hello" :> Put ()
-- Parameters ------------------------------------------------------------
type SimpleReqBody = [sitemap|
POST hello () -> Bool
|]
type SimpleReqBody' = "hello" :> ReqBody () :> Post Bool
type SimpleReqBody'' = "hello" :> ReqBody Bool :> Post ()
type SimpleCapture = [sitemap|
POST hello/p:Int Bool
|]
type SimpleCapture' = "hello" :> Capture "p" Int :> Post Bool
type SimpleCapture'' = "hello" :> Capture "r" Int :> Post Bool
type SimpleCapture''' = "hello" :> Capture "p" Bool :> Post Bool
type SimpleQueryParam = [sitemap|
POST hello/?p:Int Bool
|]
type SimpleQueryParam' = "hello" :> QueryParam "p" Int :> Post Bool
type SimpleQueryParam'' = "hello" :> QueryParam "r" Int :> Post Bool
type SimpleQueryParam''' = "hello" :> QueryParam "p" Bool :> Post Bool
-- Combinations ----------------------------------------------------------
type TwoPaths = [sitemap|
POST hello Bool
GET hello Bool
|]
type TwoPaths' = ("hello" :> Post Bool) :<|> ("hello" :> Get Bool)
type WithInlineComments = [sitemap|
GET hello Bool -- This is a comment
|]
type WithInlineComments' = "hello" :> Get Bool
type WithInlineComments2 = [sitemap|
GET hello Bool
-- This is a comment
|]
type WithInlineComments2' = "hello" :> Get Bool
type WithBlockComments = [sitemap|
GET hello Bool {-
POST hello Bool
-}
|]
type WithBlockComments' = "hello" :> Get Bool
type WithBlockComments2 = [sitemap|
GET hello Bool {-
POST hello Bool
-}
POST hello Bool
|]
type WithBlockComments2' = ("hello" :> Get Bool) :<|> ("hello" :> Post Bool)
--------------------------------------------------------------------------
-- Spec
--------------------------------------------------------------------------
spec :: Spec
spec = do
describe "'sitemap' QuasiQuoter" $ do
it "Handles simple GET types" $ do
(u::SimpleGet) ~= (u::SimpleGet' ) ~> True
(u::SimpleGet) ~= (u::SimpleGet'' ) ~> False
(u::SimpleGet2) ~= (u::SimpleGet2' ) ~> True
(u::SimpleGet2) ~= (u::SimpleGet2'') ~> False
it "Handles simple POST types" $ do
(u::SimplePost) ~= (u::SimplePost' ) ~> True
(u::SimplePost) ~= (u::SimplePost'' ) ~> False
(u::SimplePost2) ~= (u::SimplePost2' ) ~> True
(u::SimplePost2) ~= (u::SimplePost2'') ~> False
it "Handles simple PUT types" $ do
(u::SimplePut) ~= (u::SimplePut' ) ~> True
(u::SimplePut) ~= (u::SimplePut'' ) ~> False
(u::SimplePut2) ~= (u::SimplePut2' ) ~> True
(u::SimplePut2) ~= (u::SimplePut2'') ~> False
it "Handles simple request body types" $ do
(u::SimpleReqBody) ~= (u::SimpleReqBody' ) ~> True
(u::SimpleReqBody) ~= (u::SimpleReqBody'') ~> False
it "Handles simple captures" $ do
(u::SimpleCapture) ~= (u::SimpleCapture' ) ~> True
(u::SimpleCapture) ~= (u::SimpleCapture'') ~> False
(u::SimpleCapture) ~= (u::SimpleCapture''') ~> False
it "Handles simple querystring parameters" $ do
(u::SimpleQueryParam) ~= (u::SimpleQueryParam' ) ~> True
(u::SimpleQueryParam) ~= (u::SimpleQueryParam'') ~> False
(u::SimpleQueryParam) ~= (u::SimpleQueryParam''') ~> False
it "Handles multiples paths" $ do
(u::TwoPaths) ~= (u::TwoPaths') ~> True
it "Ignores inline comments" $ do
(u::WithInlineComments) ~= (u::WithInlineComments') ~> True
(u::WithInlineComments2) ~= (u::WithInlineComments2') ~> True
it "Ignores inline comments" $ do
(u::WithBlockComments) ~= (u::WithBlockComments') ~> True
(u::WithBlockComments2) ~= (u::WithBlockComments2') ~> True
--------------------------------------------------------------------------
-- Utilities
--------------------------------------------------------------------------
data HTrue
data HFalse
-- Kiselyov's Type Equality predicate
class TypeEq x y b | x y -> b where { areEq :: x -> y -> Bool }
instance TypeEq x x HTrue where { areEq _ _ = True }
instance b ~ HFalse => TypeEq x y b where { areEq _ _ = False}
infix 4 ~=
(~=) :: TypeEq x y b => x -> y -> Bool
(~=) = areEq
u :: a
u = undefined
infix 3 ~>
(~>) :: (Show a, Eq a) => a -> a -> Expectation
(~>) = shouldBe

View file

@ -1,258 +0,0 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Servant.ServerSpec where
import Control.Monad.Trans.Either
import Data.Aeson
import Data.Char
import Data.Proxy
import Data.String
import Data.String.Conversions
import GHC.Generics
import Network.HTTP.Types
import Network.Wai
import Network.Wai.Test
import Test.Hspec
import Test.Hspec.Wai
import Servant.API.Capture
import Servant.API.Get
import Servant.API.ReqBody
import Servant.API.Post
import Servant.API.QueryParam
import Servant.API.Raw
import Servant.API.Sub
import Servant.API.Alternative
import Servant.Server
-- * test data types
data Person = Person {
name :: String,
age :: Integer
}
deriving (Eq, Show, Generic)
instance ToJSON Person
instance FromJSON Person
alice :: Person
alice = Person "Alice" 42
data Animal = Animal {
species :: String,
numberOfLegs :: Integer
}
deriving (Eq, Show, Generic)
instance ToJSON Animal
instance FromJSON Animal
jerry :: Animal
jerry = Animal "Mouse" 4
tweety :: Animal
tweety = Animal "Bird" 2
-- * specs
spec :: Spec
spec = do
captureSpec
getSpec
queryParamSpec
postSpec
rawSpec
unionSpec
type CaptureApi = Capture "legs" Integer :> Get Animal
captureApi :: Proxy CaptureApi
captureApi = Proxy
captureServer :: Integer -> EitherT (Int, String) IO Animal
captureServer legs = case legs of
4 -> return jerry
2 -> return tweety
_ -> left (404, "not found")
captureSpec :: Spec
captureSpec = do
describe "Servant.API.Capture" $ do
with (return (serve captureApi captureServer)) $ do
it "can capture parts of the 'pathInfo'" $ do
response <- get "/2"
liftIO $ do
decode' (simpleBody response) `shouldBe` Just tweety
with (return (serve
(Proxy :: Proxy (Capture "captured" String :> Raw))
(\ "captured" request respond ->
respond $ responseLBS ok200 [] (cs $ show $ pathInfo request)))) $ do
it "strips the captured path snippet from pathInfo" $ do
get "/captured/foo" `shouldRespondWith` (fromString (show ["foo" :: String]))
type GetApi = Get Person
getApi :: Proxy GetApi
getApi = Proxy
getSpec :: Spec
getSpec = do
describe "Servant.API.Get" $ do
with (return (serve getApi (return alice))) $ do
it "allows to GET a Person" $ do
response <- get "/"
return response `shouldRespondWith` 200
liftIO $ do
decode' (simpleBody response) `shouldBe` Just alice
it "throws 405 (wrong method) on POSTs" $ do
post "/" "" `shouldRespondWith` 405
type QueryParamApi = QueryParam "name" String :> Get Person
:<|> "a" :> QueryParams "names" String :> Get Person
:<|> "b" :> QueryFlag "capitalize" :> Get Person
queryParamApi :: Proxy QueryParamApi
queryParamApi = Proxy
qpServer :: Server QueryParamApi
qpServer = queryParamServer :<|> qpNames :<|> qpCapitalize
where qpNames (_:name2:_) = return alice { name = name2 }
qpNames _ = return alice
qpCapitalize False = return alice
qpCapitalize True = return alice { name = map toUpper (name alice) }
queryParamServer (Just name) = return alice{name = name}
queryParamServer Nothing = return alice
queryParamSpec :: Spec
queryParamSpec = do
describe "Servant.API.QueryParam" $ do
it "allows to retrieve simple GET parameters" $
(flip runSession) (serve queryParamApi qpServer) $ do
let params1 = "?name=bob"
response1 <- Network.Wai.Test.request defaultRequest{
rawQueryString = params1,
queryString = parseQuery params1
}
liftIO $ do
decode' (simpleBody response1) `shouldBe` Just alice{
name = "bob"
}
it "allows to retrieve lists in GET parameters" $
(flip runSession) (serve queryParamApi qpServer) $ do
let params2 = "?names[]=bob&names[]=john"
response2 <- Network.Wai.Test.request defaultRequest{
rawQueryString = params2,
queryString = parseQuery params2,
pathInfo = ["a"]
}
liftIO $
decode' (simpleBody response2) `shouldBe` Just alice{
name = "john"
}
it "allows to retrieve value-less GET parameters" $
(flip runSession) (serve queryParamApi qpServer) $ do
let params3 = "?capitalize"
response3 <- Network.Wai.Test.request defaultRequest{
rawQueryString = params3,
queryString = parseQuery params3,
pathInfo = ["b"]
}
liftIO $
decode' (simpleBody response3) `shouldBe` Just alice{
name = "ALICE"
}
let params3' = "?capitalize="
response3' <- Network.Wai.Test.request defaultRequest{
rawQueryString = params3',
queryString = parseQuery params3',
pathInfo = ["b"]
}
liftIO $
decode' (simpleBody response3') `shouldBe` Just alice{
name = "ALICE"
}
type PostApi = ReqBody Person :> Post Integer
postApi :: Proxy PostApi
postApi = Proxy
postSpec :: Spec
postSpec = do
describe "Servant.API.Post and .ReqBody" $ do
with (return (serve postApi (return . age))) $ do
it "allows to POST a Person" $ do
post "/" (encode alice) `shouldRespondWith` "42"{
matchStatus = 201
}
it "correctly rejects invalid request bodies with status 400" $ do
post "/" "some invalid body" `shouldRespondWith` 400
type RawApi = "foo" :> Raw
rawApi :: Proxy RawApi
rawApi = Proxy
rawApplication :: Show a => (Request -> a) -> Application
rawApplication f request respond = respond $ responseLBS ok200 [] (cs $ show $ f request)
rawSpec :: Spec
rawSpec = do
describe "Servant.API.Raw" $ do
it "runs applications" $ do
(flip runSession) (serve rawApi (rawApplication (const (42 :: Integer)))) $ do
response <- Network.Wai.Test.request defaultRequest{
pathInfo = ["foo"]
}
liftIO $ do
simpleBody response `shouldBe` "42"
it "gets the pathInfo modified" $ do
(flip runSession) (serve rawApi (rawApplication pathInfo)) $ do
response <- Network.Wai.Test.request defaultRequest{
pathInfo = ["foo", "bar"]
}
liftIO $ do
simpleBody response `shouldBe` cs (show ["bar" :: String])
type AlternativeApi =
"foo" :> Get Person
:<|> "bar" :> Get Animal
unionApi :: Proxy AlternativeApi
unionApi = Proxy
unionServer :: Server AlternativeApi
unionServer =
return alice
:<|> return jerry
unionSpec :: Spec
unionSpec = do
describe "Servant.API.Alternative" $ do
with (return $ serve unionApi unionServer) $ do
it "unions endpoints" $ do
response <- get "/foo"
liftIO $ do
decode' (simpleBody response) `shouldBe`
Just alice
response <- get "/bar"
liftIO $ do
decode' (simpleBody response) `shouldBe`
Just jerry

View file

@ -1,52 +0,0 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
module Servant.Utils.LinksSpec where
import Test.Hspec
import Servant.API
import Servant.QQSpec ( (~>) )
import Servant.Utils.Links (IsElem, IsLink)
type TestApi =
"hello" :> Capture "name" String :> QueryParam "capital" Bool :> Get Bool
:<|> "greet" :> ReqBody 'True :> Post Bool
type TestLink = "hello" :> "hi" :> Get Bool
type TestLink2 = "greet" :> Post Bool
type BadTestLink = "hallo" :> "hi" :> Get Bool
type BadTestLink2 = "greet" :> Get Bool
type NotALink = "hello" :> Capture "x" Bool :> Get Bool
type NotALink2 = "hello" :> ReqBody 'True :> Get Bool
data Proxy x = Proxy
class ReflectT (x::Bool) where { reflected :: Proxy x -> Bool }
instance ReflectT 'True where { reflected _ = True }
instance ReflectT 'False where { reflected _ = False }
spec :: Spec
spec = describe "Servant.API.Elem" $ do
isElem
isLink
isElem :: Spec
isElem = describe "IsElem" $ do
it "is True when the first argument is an url within the second" $ do
reflected (Proxy::Proxy (IsElem TestLink TestApi)) ~> True
reflected (Proxy::Proxy (IsElem TestLink2 TestApi)) ~> True
it "is False when the first argument is not an url within the second" $ do
reflected (Proxy::Proxy (IsElem BadTestLink TestApi)) ~> False
reflected (Proxy::Proxy (IsElem BadTestLink2 TestApi)) ~> False
isLink :: Spec
isLink = describe "IsLink" $ do
it "is True when all Subs are paths and the last is a method" $ do
reflected (Proxy::Proxy (IsLink TestLink)) ~> True
reflected (Proxy::Proxy (IsLink TestLink2)) ~> True
it "is False of anything with captures" $ do
reflected (Proxy::Proxy (IsLink NotALink)) ~> False
reflected (Proxy::Proxy (IsLink NotALink2)) ~> False

View file

@ -1,64 +0,0 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Servant.Utils.StaticFilesSpec where
import Control.Exception
import Data.Proxy
import Network.Wai
import System.Directory
import System.IO.Temp
import Test.Hspec hiding (pending)
import Test.Hspec.Wai
import Servant.API.Alternative
import Servant.API.Capture
import Servant.API.Get
import Servant.API.Raw
import Servant.API.Sub
import Servant.Server
import Servant.ServerSpec
import Servant.Utils.StaticFiles
type Api =
"dummy_api" :> Capture "person_name" String :> Get Person
:<|> "static" :> Raw
api :: Proxy Api
api = Proxy
app :: Application
app = serve api server
server :: Server Api
server =
(\ name -> return (Person name 42))
:<|> serveDirectory "static"
withStaticFiles :: IO () -> IO ()
withStaticFiles action = withSystemTempDirectory "servant-test" $ \ tmpDir ->
bracket (setup tmpDir) teardown (const action)
where
setup tmpDir = do
outer <- getCurrentDirectory
setCurrentDirectory tmpDir
createDirectory "static"
writeFile "static/foo.txt" "bar"
writeFile "static/index.html" "index"
return outer
teardown outer = do
setCurrentDirectory outer
spec :: Spec
spec = do
around_ withStaticFiles $ with (return app) $ do
describe "serveDirectory" $ do
it "successfully serves files" $ do
get "/static/foo.txt" `shouldRespondWith` "bar"
it "serves the contents of index.html when requesting the root of a directory" $ do
get "/static" `shouldRespondWith` "index"

View file

@ -1 +0,0 @@
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}