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

[ bsd3, library, program, web ] [ Propose Tags ]

[Skip to Readme]
Versions [RSS] [faq], 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, clay, cryptonite, http-api-data, hvect, postgresql-simple, pretty-simple, reroute, resource-pool, Spock (==0.13.*), Spock-core (==0.13.*), stm-containers (==0.2.*), superrecord (==0.5.*), 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-19T01:08:55Z
Distributions NixOS:0.1.2
Executables example
Downloads 951 total (10 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Hackage Matrix CI
Docs available [build log]
Last success reported on 2019-06-19 [all 1 reports]


[Index] [Quick Jump]


Maintainer's Corner

For package maintainers and hackage trustees


Readme for tsweb-0.1.1

[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)
  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)