Как создать ActionCtxT в Spock?

Я хочу извлечь значение из объекта json. И у меня есть это:

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

И ошибка:

• 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"

Я знаю, что это значит: строка с myVal должна возвращать что-то типа ActionCtxT, как и все остальные строки. Или чистое значение. Таким образом, как это исправить?


person Jodimoro    schedule 09.05.2017    source источник


Ответы (1)


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

jsonBody' дает вам возможность проанализировать тело запроса, используя экземпляр Aeson FromJSON.

Обычно проще использовать Aeson, сопоставив ваши данные JSON с пользовательским типом данных, а затем предоставив экземпляр FromJSON для этого типа данных.

Перефразируя пример, который вы можете найти в документации Aeson, если ваш JSON выглядит так:

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

Затем вы можете создать тип данных:

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

и вручную создайте экземпляр FromJSON:

{-# 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

В качестве альтернативы вы можете автоматически получить экземпляр FromJSON из вашего типа данных.

person Jean-Baptiste Potonnier    schedule 09.05.2017
comment
Я понял ваш вопрос, просто подумал, что вы на неправильном пути. Если вы все еще хотите сохраниться, вы можете получить доступ к значению HashMap, например, используя let myVal = (a :: Object) ! "some_key". - person Jean-Baptiste Potonnier; 10.05.2017