@hackage tsweb0.1.2

An API binding Web.Spock to Database.Beam

TsWeb - A very opinionated web API

TsWeb is a binding between the Spock web framework and the Beam database API. It provides convenience functions for running database queries from within Spock actions, a Spock session manager replacement using the Beam API, and type-safe routing including type-checked reverse lookups (URLs are associated with first-class labels which are used for reverse lookup).

Sample Program

Most of the functionality of TsWeb (ideally, all of it) is demonstrated in the example program, which lives under the Example directory of the source tree. Have a look there for a working example of TsWeb.

Restricted Views

TsWeb views run with minimal rights; by default they do not have access to the database nor do they have any user information initialized. A view's type signature enumerates its requirements, and those requirements are granted by the view's routing. For example, a view that needs read-write database access, an admin user, and a route to the index URL might have this type signature:

myview ::
  ( ListContains n0 Admin xs
  , ListContains n1 ReadWritePool xs
  , Has "index" lts (Path '[] 'Open) )
  => TsActionCtxT lts xs sessdata a
myview = do
  db :: ReadOnlyPool <- getExtra
  Admin me <- getExtra
  indexPath <- showPath #index
  ...

And then the view would be routed as:

runroute readonlypool readwritepool $
  path #index root (getpost indexView) .
  path #myview "mine" (dbwrite $ getpost $ auth adminP myview)

See the docs for "TsWeb.Routing" and "TsWeb.Routing.Auth" for more details.

Action Queries

Have a look at "TsWeb.Db" for documentation on running Beam queries from a Spock context. This is just sugar, but it's pretty nice. A small example:

myview :: ListContains n ReadWritePool xs => TsActionCtxT lts xs sessdata a
myview = do
  queryList (select $ all_ (_dbUser db)) >>= \case
    QSimply users -> text $ T.pack $ show users
    QError err -> text $ "Error: " <> Text.pack (show err)

See "TsWeb.Db" for more details.

Session Manager

This is pretty much invisible, but use TsWeb.Session.patchConfig on your Spock config to replace the default session manager with the TsWeb one. Lifted directly from the "TsWeb.Session" documentation:

spockCfg <-
  patchConfig (_dbSession db) ropool rwpool <$>
  defaultSpockCfg sess PCNoDatabase ()
runSpock port (spock spockCfg routes)
where
  sess = ...
  routes = ...

Type-safe URLs with reversing.

TsWeb builds on Spock's reroute library to also add type-checked reverse lookups. There's a pretty complete document on that under "TsWeb.Routing", which I'm simply pasting in here:

index :: Has "users" lts (Path '[] 'Open) => TsActionCtxT lts xs sess a
index = showPath #users >>= text

users :: Has "root" lts (Path '[] 'Open) => TsActionCtxT lts xs sess a
users = do
  root <- showPath #root
  text $ "GET users, root is, " <> root

usersPost :: TsActionCtxT lts xs sess a
usersPost = text "POST to users!"

Then, routing to those views looks like this:

runroute ropool rwpool $
  path #root root (getpost index) .
  path #users "users" (do get users
                          post usersPost)