Haskell Servant: GET Запросы с произвольными данными запроса - PullRequest
0 голосов
/ 04 июня 2018

Я обслуживаю API с использованием Servant, все управляется 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 не так легко кэшируются.Даже если я могу их кешировать, я не хочу кешировать все почтовые запросы, так что это будет грязный подход.

Спасибо за любую помощь!

1 Ответ

0 голосов
/ 04 июня 2018

Простое решение, если вам нужен тот же уровень автоматической деривации, что и для тел сообщений 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
...