How to create "ActionCtxT" in Spock?

132 Views Asked by At

I want to extract a value from a json object. And I have this:

    post "/test" $ do
        a <- jsonBody'
        let b = show (a :: Object) -- works well
        myVal <- (a :: Object) .: "some_key" -- error
        text "test123"

And the error:

• Couldn't match type ‘aeson-1.0.2.1:Data.Aeson.Types.Internal.Parser’
                     with ‘ActionCtxT () (WebStateM () MySession MyAppState)’
      Expected type: ActionCtxT () (WebStateM () MySession MyAppState) a0
        Actual type: aeson-1.0.2.1:Data.Aeson.Types.Internal.Parser a0
    • In a stmt of a 'do' block:
        myVal <- (a :: Aeson.Object) Aeson..: "some_key"

I know what it means: the line with myVal must return something of type ActionCtxT as well as all other lines. Or a pure value. Thus, how to fix it?

1

There are 1 best solutions below

1
On
jsonBody' :: (MonadIO m, FromJSON a) => ActionCtxT ctx m a

jsonBody' gives you way to parse the body of the request using an Aeson FromJSON instance.

It's usually easier to use Aeson by mapping your JSON data to a custom data type, and then providing a FromJSON instance for that data type.

Paraphrasing the example you can find in the Aeson documentation, If your JSON looks like this :

 { "name": "Joe", "age": 12 }

Then you can create a data type :

data Person = Person {
      name :: Text
    , age  :: Int
    } deriving Show

and manually create the FromJSON instance:

{-# LANGUAGE OverloadedStrings #-}

instance FromJSON Person where
    parseJSON (Object v) = Person <$>
                           v .: "name" <*>
                           v .: "age"
    -- A non-Object value is of the wrong type, so fail.
    parseJSON _          = empty

Your could alternatively automatically derive the FromJSON instance from your data type.