Haskell Servant: GET 带有任意请求数据的请求

Haskell Servant: GET Requests with arbitrary request data

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

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

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

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

感谢您的帮助!

如果您想要与 JSON post 主体相同级别的自动推导,一个简单的解决方案是将查询参数发送为 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