Haskell Servant:使用任意请求数据获取请求

时间:2018-06-04 01:45:42

标签: haskell haskell-snap-framework servant

我使用Servant提供API,全部由Snap管理。在Servant中,假设它具有FromJSON实例,很容易将任意数据类型包含在POST请求中。例如,我可能有以下端点:

ReqBody '[JSON] RequestData :> Post '[JSON] [ResponseData]

如何对GET请求执行相同的操作?根据我的理解,我需要使用查询参数,但我的请求数据由复杂的数据类型(列表,嵌套字典)组成,这些数据类型似乎不易被读取,例如QueryParam "vals" [Int] :> Post '[JSON] [Int]会导致错误No instance for (FromHttpApiData [Int])

解决方法是使用POST请求,它具有易于阅读的请求体。但是,这会与我在Nginx中的缓存方案发生冲突,因为对POST请求的响应并不容易缓存。即使我可以缓存它们,我也不想缓存所有发布请求,因此它是一种混乱的方法。

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

如果您想要与JSON帖子主体相同级别的自动派生,那么一个简单的解决方案就是将查询参数作为JSON发送

import Data.Aeson
import Servant.API
import qualified Data.Text as T
import Data.Text.Encoding
import qualified Data.ByteString.Lazy as LBS

newtype JSONEncoded a = JSONEncoded { unJSONEncoded :: a }
  deriving (Eq, Show)

instance (FromJSON a) => FromHttpApiData (JSONEncoded a) where
  parseQueryParam x = case eitherDecode $ LBS.fromStrict $ encodeUtf8 x of
    Left err -> Left (T.pack err)
    Right val -> Right (JSONEncoded val)

instance (ToJSON a) => ToHttpApiData (JSONEncoded a) where
  toQueryParam (JSONEncoded x) = decodeUtf8 $ LBS.toStrict $ encode x