在Servant中发送通用内容类型

时间:2016-02-25 19:43:55

标签: haskell servant

我正在尝试将一些ByteString转发回客户端(浏览器)。客户端将不知道所请求文档的内容类型,因此我尝试将适当的内容类型响应发送回客户端。该文件可以是图像或pdf或word文档等。

例如,客户端将请求/document?id=55,服务器将使用相应的内容类型和关联的ByteString进行响应。

我按照示例here:我为图像创建了一些东西。

 data IMAGE

 instance Accept IMAGE where
     contentType _ = "image" M.// "jpeg"

 instance MimeRender IMAGE LBS.ByteString where
     mimeRender _ = id

挑战是客户端不会使用某个特定的Accept:标头发送请求,因此我无法像使用here那样对适当的Mime类型做出反应。此外,上述内容仅适用于图片(假设浏览器会推断png,即使我发回jpeg),也不会推送pdfdocx等。

我考虑过像MyDynamicContent String这样的参数化类型,我会在运行时传递内容类型,但我不确定如何声明我的API,即我将使用什么代替{{1} }。不确定这样的事情是否可能,因为示例只是一个简单的数据类型。

所以我的问题是,如果我想发送一些'[JSON]作为回复并动态设置ByteString标头,那么使用Content-Type

更新:我打开了issue

1 个答案:

答案 0 :(得分:3)

这是可能的,但有点黑客:

{-# 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-clientservant-docs等进行一些额外的工作。鉴于此,您可能希望在回购中打开一个有关此问题的问题,以获得更完整的支持。