Sending a generic content type in a service

I am trying to pass a part of ByteString back to the client (browser). The client will not know the content type of the requested document, so I am trying to send the appropriate content type response back to the client. The document may be an image or a document in pdf format or words, etc.

For example, the client will request /document?id=55 , and the server will respond with the appropriate content type and associated ByteString .

I followed suit here : and I created something for the image.

  data IMAGE instance Accept IMAGE where contentType _ = "image" M.// "jpeg" instance MimeRender IMAGE LBS.ByteString where mimeRender _ = id 

The problem is that the client will not send a request with a specific Accept: header, so I don’t need to react with the corresponding Mime type, how it is done. Plus, the above will work only for images (provided that browsers display png even I send jpeg back), but not for pdf , docx , etc.

I was thinking of a parameterized type of type MyDynamicContent String , and I will pass the content type at runtime, but I'm not sure how I will declare my API, that is, what I will use instead of '[JSON] . Not sure if such a thing is even possible, because examples are just a simple data type.

So my question is: if I want to send some ByteString as an answer and dynamically set the Content-Type header, what would be the best way to do this using servant

Update: I opened issue

+6
source share
1 answer

Perhaps, but a little hack:

 {-# 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 hc) = 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 

Testing:

  % curl localhost:8000 -v ... < HTTP/1.1 200 OK ... < Content-Type: example < ... somecontent% 

The idea is to override normal behavior by declaring an overlapping instance for AllCTRender . Please note that you may also have to do additional footwork for servant-client , servant-docs , etc., if you also use them. Given this, you can open a problem in the repo about it for more complete support.

+3
source

All Articles