tsweb: An API binding Web.Spock to Database.Beam

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Warnings:


[Skip to Readme]

Properties

Versions 0.1.0.0, 0.1.0.0, 0.1.1, 0.1.2
Change log ChangeLog.md
Dependencies base (>=4.9 && <4.13), beam-core (>=0.7 && <0.9), beam-postgres (>=0.3 && <0.5), bytestring, http-api-data, hvect, postgresql-simple, pretty-simple, reroute, resource-pool, Spock (>=0.13 && <0.14), Spock-core (>=0.13 && <0.14), stm-containers (>=0.2 && <0.3), superrecord (>=0.5 && <0.6), tagged, text, time, transformers [details]
License BSD-3-Clause
Author Jeremy Groven
Maintainer jeremy.groven@gmail.com
Category Web
Uploaded by tsuraan at 2019-06-18T21:04:15Z

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for tsweb-0.1.0.0

[back to package description]

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 specified in 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 yview)

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)