在 Servant 中发送通用 Content-Type
Sending Generic Content-Type in Servant
我正在尝试将一些 ByteString
中继回客户端(浏览器)。客户端将不知道所请求文档的 content-type,因此我试图将适当的 content-type 响应发送回客户端。文档可以是图片或pdf或word文档等
例如,客户端将请求 /document?id=55
,服务器将以适当的 content-type 和关联的 ByteString
进行响应。
我按照示例 here: 为图像创建了一些东西。
data IMAGE
instance Accept IMAGE where
contentType _ = "image" M.// "jpeg"
instance MimeRender IMAGE LBS.ByteString where
mimeRender _ = id
挑战在于客户端不会发送带有某些特定 Accept:
header 的请求,因此我无法像完成时那样对适当的 Mime 类型做出反应 here.另外,以上仅适用于图像(假设浏览器会推断 png
即使我发回 jpeg
)但不适用于 pdf
、docx
等
我考虑过像 MyDynamicContent String
这样的参数化类型,我将在 run-time 处传入内容类型,但我不确定我将如何声明我的 API 即什么会我使用而不是 '[JSON]
。不确定这样的事情是否可能,因为示例只是一个简单的数据类型。
所以我的问题是,如果我想发送一些 ByteString
作为响应并动态设置 Content-Type
header,使用 servant
更新:我开了一个issue
有可能,但有点麻烦:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverlappingInstances #-}
module DynCT where
import Control.Monad.Trans.Either
import Data.ByteString.Lazy (ByteString)
import Servant
import Servant.API.ContentTypes
import Network.Wai.Handler.Warp
data WithCT = WithCT { header :: ByteString, content :: ByteString }
instance AllCTRender xs WithCT where
handleAcceptH _ _ (WithCT h c) = Just (h, c)
type API = Get '[] WithCT
api :: Proxy API
api = Proxy
server :: Server API
server = return $ WithCT { header = "example", content = "somecontent" }
main :: IO ()
main = run 8000 $ serve api server
正在测试:
% curl localhost:8000 -v
...
< HTTP/1.1 200 OK
...
< Content-Type: example
<
...
somecontent%
这个想法只是通过为 AllCTRender
声明一个重叠实例来覆盖正常行为。请注意,如果您还使用这些,您可能还需要为 servant-client
、servant-docs
等做一些额外的腿部工作。鉴于此,您可能想在回购协议中打开一个关于此的问题以获得更完整的支持。
截至目前,此 hack 有效
data WithCT = WithCT {header :: BS.ByteString, content :: BS.ByteString}
instance AllCTRender '[IMAGE] WithCT where
handleAcceptH _ _ (WithCT h c) = Just (fromStrict h, fromStrict c)
data IMAGE deriving (Typeable)
instance MimeRender IMAGE BS.ByteString where
mimeRender _ content = fromStrict content
instance Accept IMAGE where
contentType _ = ""
type ImageApi = Capture "image_id" ImageId :> Get '[IMAGE] WithCT
我正在尝试将一些 ByteString
中继回客户端(浏览器)。客户端将不知道所请求文档的 content-type,因此我试图将适当的 content-type 响应发送回客户端。文档可以是图片或pdf或word文档等
例如,客户端将请求 /document?id=55
,服务器将以适当的 content-type 和关联的 ByteString
进行响应。
我按照示例 here: 为图像创建了一些东西。
data IMAGE
instance Accept IMAGE where
contentType _ = "image" M.// "jpeg"
instance MimeRender IMAGE LBS.ByteString where
mimeRender _ = id
挑战在于客户端不会发送带有某些特定 Accept:
header 的请求,因此我无法像完成时那样对适当的 Mime 类型做出反应 here.另外,以上仅适用于图像(假设浏览器会推断 png
即使我发回 jpeg
)但不适用于 pdf
、docx
等
我考虑过像 MyDynamicContent String
这样的参数化类型,我将在 run-time 处传入内容类型,但我不确定我将如何声明我的 API 即什么会我使用而不是 '[JSON]
。不确定这样的事情是否可能,因为示例只是一个简单的数据类型。
所以我的问题是,如果我想发送一些 ByteString
作为响应并动态设置 Content-Type
header,使用 servant
更新:我开了一个issue
有可能,但有点麻烦:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverlappingInstances #-}
module DynCT where
import Control.Monad.Trans.Either
import Data.ByteString.Lazy (ByteString)
import Servant
import Servant.API.ContentTypes
import Network.Wai.Handler.Warp
data WithCT = WithCT { header :: ByteString, content :: ByteString }
instance AllCTRender xs WithCT where
handleAcceptH _ _ (WithCT h c) = Just (h, c)
type API = Get '[] WithCT
api :: Proxy API
api = Proxy
server :: Server API
server = return $ WithCT { header = "example", content = "somecontent" }
main :: IO ()
main = run 8000 $ serve api server
正在测试:
% curl localhost:8000 -v
...
< HTTP/1.1 200 OK
...
< Content-Type: example
<
...
somecontent%
这个想法只是通过为 AllCTRender
声明一个重叠实例来覆盖正常行为。请注意,如果您还使用这些,您可能还需要为 servant-client
、servant-docs
等做一些额外的腿部工作。鉴于此,您可能想在回购协议中打开一个关于此的问题以获得更完整的支持。
截至目前,此 hack 有效
data WithCT = WithCT {header :: BS.ByteString, content :: BS.ByteString}
instance AllCTRender '[IMAGE] WithCT where
handleAcceptH _ _ (WithCT h c) = Just (fromStrict h, fromStrict c)
data IMAGE deriving (Typeable)
instance MimeRender IMAGE BS.ByteString where
mimeRender _ content = fromStrict content
instance Accept IMAGE where
contentType _ = ""
type ImageApi = Capture "image_id" ImageId :> Get '[IMAGE] WithCT