Setup
Before using Spock, you’ll need to install the Haskell toolchain on your machine. We recommend using the
stack tool to quickly get started! Our guide will be stack
based, but you can
easily translate this to cabal
.
Next, you can prepare a directory for your first Spock powered application:
- Create a new project using
stack new Spock-example
- Jump into the directory
cd Spock-example
Dependencies
First we will add Spock
to our dependencies by opening Spock-example.cabal
and adding Spock >=0.14
, mtl
and text
to build-depends
in the
executable Spock-example-exe
section. Also, the extra-deps:
section in the generated stack.yaml
file to:
extra-deps:
- Spock-0.14.0.0
- Spock-core-0.14.0.0
- reroute-0.6.0.0
- stm-containers-1.2
- focus-1.0.1.4
- stm-hamt-1.2.0.4
- primitive-extras-0.8
- primitive-unlifted-0.1.3.0
Next we build everything once: stack build --fast --pedantic
.
Hello world
Now it is time to write some Haskell code. Open app/Main.hs
in your favorite editor and replace the content with:
Next, run stack build --fast --pedantic
again to build the project. stack exec Spock-example-exe
should start the executable - you may now point your browser to http://localhost:8080
and http://localhost:8080/hello/[YOUR_NAME]
.
Code explained
Let us take a quick look at the interesting parts of the example. First, we import the core Spock modules:
Then, in the main
function, we start out by configuring Spock. To do that, we need to describe what an
empty session for an individual user will look like (in our case, the EmptySession
from our MySession
type),
if and how we would like to use a database (no database, for now, so PCNoDatabase
) and how our initial global
application state will look like. This is very useful to pass around configuration or other globally shared
information. We’ll use it to implement a small hit counter by putting an IORef Int
in our state. Let’s not worry
about the last line in main
just now, and move on to app
.
The definition of a Spock application lives in the SpockM conn sess st a
monad. The conn
type parameter describes
what our database connection looks like (()
for no database), the sess
is the type of our session and st
the
type of our global application state. Thus, for us: SpockM () MySession MyAppState ()
. Inside the SpockM
monad,
we’ll wire URLs to actions. You can think of it as a Writer
monad.
To connect an URL to an action, we use routes. A route is either
- a static route piece, such as
"hello"
or"blog"
orroot
(the/
route) - a route parameter:
var
- or a combination of the above, using the
<//>
operator, such as"hello" <//> var
.
A static route piece will match the exact text counterpart, eg. a route "hello" <//> "world"
would match the URL
/hello/world
and /hello/world/
. A route parameter matches anything that does not contain a /
and parses as the
inferred type of the parameter. The type of the parameter is inferred by the action bound to the route. In the example above, our action is:
This lambda function takes a Text
, integrates it between "Hello "
and "!"
, and returns it to the framework. Thus,
the var
in the route "hello" <//> var
will require the parameter to be a text. If our function would take more than one argument, or our route would not contain a parameter this would result in a type error.
Putting it all together, we first need an HTTP-Verb to match against. In the example, we match GET
requests, so we’ll use the get
function to
wire our action. Next we specify the route (e.g. root
), and then the handler (e.g. text "Hello world!"
). Handlers run in the SpockAction conn sess st a
monad. You can use various functions to read headers and the HTTP body, and return content to the browser. Note that after a function returning content to the browser is called (such as text
), the action is terminated.
After having defined the application, you can create a Wai.Middleware
from it using spock spockCfg app
and then run it using runSpock 8080
(choosing any port you like). Internally, the application is run by the warp web server.
Next Steps
- Read the documentation on Hackage
- Check out and/or contribute to the example project
- Contribute on Github by reporting or pull-requesting missing features and bugs
- Check out the Addons and Works great with section in the pages footer
- Watch our blog
- And of course: build your Spock powered application