Adding a handler
In this example, we'll create a person age validator.
If you have used the Stack template, you will have a handler that is pre-defined in the src/Lib.hs
file.
First, we need to enable some language extensions in order to make working with JSON easier. We'll also import a few required modules:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
module Lib where
import Aws.Lambda
import GHC.Generics
import Data.Aeson
We'll create a basic handler that validates a person's age is positive. Let's create a Person
type to use.
data Person = Person
{ name :: String
, age :: Int
} -- We kindly ask the compiler to autogenerate JSON instances for us
deriving (Generic, FromJSON, ToJSON)
Now, let's implement the actual handler.
A handler is a function with the following type signature:
-- Note that request, error and response must all implement ToJSON and FromJSON
handler :: request -> Context context -> IO (Either error response)
For our person validator usecase this means the following:
handler :: Person -> Context () -> IO (Either String Person)
This means we expect to be given a Person
object and we'll return either some String
as an error or some other Person
object (that passed validation).
You can ignore the Context ()
parameter at this point. This is the Lambda context object which is present in every runtime. By specifying ()
as an inner value, we say we don't want to have anything there.
The implementation of our handler will look like this:
handler :: Person -> Context () -> IO (Either String Person)
handler person _context =
if age person > 0 then
pure (Right person)
else
pure (Left "A person's age must be positive")
Note how we are using Right
to return the value in case everything went right, and Left
if something went wrong.
Now let's see how to register this handler into our runtime.