2016-02-25 6 views
6

ByteStringをクライアント(ブラウザ)に中継しようとしています。クライアントは要求されているドキュメントのコンテンツタイプを知らないので、クライアントに適切なコンテンツタイプの応答を返そうとしています。文書は、画像またはpdfまたはワード文書などであってもよい。サーバントで一般的なコンテンツタイプを送信する

例えば、クライアントは/document?id=55を要求し、サーバは適切なコンテンツタイプおよび関連するByteStringで応答する。

私は例hereに従っており、画像用に何かを作成しました。

data IMAGE 

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

instance MimeRender IMAGE LBS.ByteString where 
    mimeRender _ = id 

課題は、それがhereに行われているように私には、適切なMIMEタイプと反応する方法がないので、クライアントはいくつかの特定のAccept:ヘッダでリクエストを送信することはありませんです。さらに、上記の画像は、pdfdocxなどではなく、ブラウザではpngを返信してもjpegを返信すると仮定しています)。

私はMyDynamicContent Stringようparamaterizedタイプについて考えて、私は、実行時にコンテンツタイプを渡しますが、私はつまり、私は'[JSON]の代わりに何を使用する私のAPIを宣言しますかわかりません。例が単なる単純なデータ型であるため、このようなことも可能ではありません。

だから私の質問は、私は応答として、いくつかのByteStringを送信し、動的にContent-Typeヘッダーを設定したい場合は、何がservant

更新使用してそれを行うための最善の方法となります、である:私はissueを開いた

+0

どのようなコンテンツタイプで応答するかはサーバーがどのように決定しますか? (特に、これを静的に確定することはできません) – user2141650

+0

@ user2141650: 'server'はデータストア(文書ストアサービス)からこの情報を取得します。それはサービスへの呼び出しを行い、サービスはcontent-typeとバイト文字列で応答します。私は、各コンテンツタイプ(またはほとんどは少なくとも使用されるもの)のエンドポイントを作成し、まずコンテンツタイプを送信してから、コンテンツタイプに対応するエンドポイントを使用するようにクライアントに依頼することができます。これはそのような悪いハックであり、このロジックをクライアントに多く移しています。私はそれがサーバーによってうまく処理されるべきだと感じています。 – Ecognium

答えて

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などの余分な足の仕事をしなければならない場合もあるでしょう。それを考えると、より完全なサポートのために、これに関するレポに問題を開くことができます。

+0

ありがとうございました。これは確かに動作します。私は 'servant-docs'を使用しており、タイプエラーが発生しています。あなたはすでにこれが問題になることを知っていました。 '[] 'を使うためにドキュメントを満たすために何を用意する必要があるのか​​不明です。私が得るエラーは、 'Doc.docs 'の使用に起因して'(Servant.API.ContentTypes.IsNonEmpty' [])を推論できませんでした。私は問題を開いて、問題を解決するきれいな方法があるかどうかを確認します。 – Ecognium

+0

私はそれをドキュメントと連携させました。 '[] 'を使う代わりに、私は汎用のカスタムmime型を使いました。 Acceptインスタンスのcontent-typeは 'AllCTRender'によってオーバーライドされていますので、うまく動作します。こうすることで、ドキュメントを使用してカスタムのMIMEタイプを返すことができます。 – Ecognium