Name: nested-routes Version: 0.3 Author: Athan Clark Maintainer: Athan Clark License: BSD3 License-File: LICENSE Synopsis: Declarative, compositional Wai responses Description: A method to writing Wai responses . This library attempts to make it easier to write nice Wai response handlers by giving us a Sinatra/ -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 & , but we can also embed parsers /directly/ in our routes, with our handlers reflecting their results. As an example: . > router :: Application > router = route handlers > where > handlers = do > handleLit o > (Left $ get $ text "home") > Nothing > handleLit (l "foo" l "bar" o) > (Left $ get $ text "foobar") $ Just $ > handleParse (p ("baz",double) o) > (\d -> Right $ get $ textOnly $ LT.pack (show d) `LT.append` " bazs") > Nothing > handleParse (p ("num",double) o) > (\d -> Right $ get $ textOnly $ LT.pack $ show d) $ Just $ > handleLit (l "bar" o) > (\d -> Left $ get $ text $ (LT.pack $ show d) `LT.append` " bars") > Nothing . 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 - that's where the @Either@ stuff comes in to play. 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@. . We use the @Either@ for a subtle reason - literal url strings may have a file extension, while url strings ending with a parser would not. @get@, @post@, etc. are all monadic expressions, accumulating a @Map@ for HTTP verbs, likewise with @text@, @lucid@, @json@, @bytestring@ etc., where they may also match a particular file extension. @textOnly@ and the other @-Only@ variants are not monadic, and simply give us a convenient unwrapper. Basically, url paths ending with a literal chunk are @Left@ and contain a @VerbListenerT z (FileExtListenerT Response m ()) m ()@, while paths ending with a parser are @Right@ and contain @VerbListenerT z Response m ()@. . When we test our application: . > λ> curl localhost:3000/ > ↪ "home" . requests may end with index . > λ> curl localhost:3000/index > ↪ "home" . and specify the file extension . > λ> curl localhost:3000/index.txt > ↪ "home" . each responding with the "closest" available file type . > λ> curl localhost:3000/index.html > ↪ "home" . > λ> curl localhost:3000/foo/bar > ↪ "foobar" . > λ> curl localhost:3000/foo/bar.txt > ↪ "foobar" . > λ> curl localhost:3000/foo/bar/5678.5678 > ↪ "5678.5678 bazs" . > λ> curl localhost:3000/1234.1234 > ↪ "1234.1234" . > λ> curl localhost:3000/2e5 > ↪ "200000.0" . > λ> curl localhost:3000/1234.1234/bar > ↪ "1234.1234 bars" Cabal-Version: >= 1.10 Build-Type: Simple Library Default-Language: Haskell2010 HS-Source-Dirs: src GHC-Options: -Wall Exposed-Modules: Web.Routes.Nested Web.Routes.Nested.Types Web.Routes.Nested.Types.UrlChunks Web.Routes.Nested.VerbListener Web.Routes.Nested.FileExtListener Build-Depends: base >= 4.6 && < 5 , wai , wai-extra , http-types , mtl , transformers , semigroups , constraints , containers , text , aeson , blaze-html , lucid , bytestring , attoparsec , pred-trie >= 0.0.12 , poly-arity >= 0.0.3 Test-Suite spec Type: exitcode-stdio-1.0 Default-Language: Haskell2010 Hs-Source-Dirs: src , test Ghc-Options: -Wall Main-Is: Spec.hs Build-Depends: base , hspec , QuickCheck , quickcheck-instances Source-Repository head Type: git Location: git://github.com/athanclark/nested-routes.git