A method to writing Wai responses
This library attempts to make it easier to write nice Wai response handlers
by giving us a Sinatra/
Scotty-like syntax for declaring HTTP-verb oriented
routes, in addition to file-extension handling and rose-tree like composition.
Not only do we have literal route specification, like
Scotty &
Spock, but we
can also embed
Attoparsec
parsers and Regular Expressions
directly in our routes, with our handlers
reflecting their results. As an example:
router :: Application
router = route handlers
where
handlers = do
handle o
(get $ text "home")
Nothing
handle ("foo" </> "bar")
(get $ text "foobar") $ Just $
handle (p ("baz", double) </> o)
(\d -> get $ text $ LT.pack (show d) <> " bazs")
Nothing
handle (p ("num",double) </> o)
(\d -> get $ text $ LT.pack $ show d) $ Just $ do
handle "bar"
(\d -> get $ do
text $ (LT.pack $ show d) <> " bars")
json $ (LT.pack $ show d) <> " bars!")
Nothing
handle (r ("email", mkRegex "(^[-a-zA-Z0-9_.]+@[-a-zA-Z0-9]+\\.[-a-zA-Z0-9.]+$)") </> o)
(\d e -> get $ textOnly $ (LT.pack $ show d) <> " " <> (LT.pack $ show e)
The route specification syntax is a little strange right now - l
specifies
a "literal chunk" of a handlable url (ie - l "foo" </> l "bar" </> o
would
represent the url /foo/bar
), while p
represents a "parsable" url chunk,
which expects a pair - the left element being merely a reference name for the
parser during internal plumbing, and the right being the actual Parser
. o
represents
the end of a url string, and can be used alone in a handler to capture requests
to the root path.
Each route being handled needs some kind of content. For every parsed url chunk,
the route expects a function
of arity matching 1-for-1 with the parsed contents. For example, d -> ...
in the
demonstration above is such a function, where d :: Double
.
Internally, we match against both the file extension and Accept headers in the
HTTP request - the Accept header may override the file extension.
When we test our application:
λ> curl localhost:3000/ -H "Accept: text/plain, */*"
↪ "home"
requests may end with index
λ> curl localhost:3000/index -H "Accept: text/plain, */*"
↪ "home"
and specify the file extension
λ> curl localhost:3000/index.txt -H "Accept: text/plain, */*"
↪ "home"
each responding with the "closest" available file type
λ> curl localhost:3000/index.html -H "Accept: text/html, */*"
↪ "home"
λ> curl localhost:3000/foo/bar -H "Accept: text/plain, */*"
↪ "foobar"
λ> curl localhost:3000/foo/bar.txt -H "Accept: text/plain, */*"
↪ "foobar"
λ> curl localhost:3000/foo/bar/5678.5678 -H "Accept: text/plain, */*"
↪ "5678.5678 bazs"
λ> curl localhost:3000/1234.1234 -H "Accept: text/plain, */*"
↪ "1234.1234"
λ> curl localhost:3000/2e5 -H "Accept: text/plain, */*"
↪ "200000.0"
λ> curl localhost:3000/1234.1234/bar -H "Accept: text/plain, */*"
↪ "1234.1234 bars"