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)