@@ -24,10 +24,14 @@ import qualified Data.Text as T
24import Data.Typeable
24import Data.Typeable
25import GHC.TypeLits (KnownSymbol, symbolVal)
25import GHC.TypeLits (KnownSymbol, symbolVal)
26import Network.HTTP.Types hiding (Header)
26import Network.HTTP.Types hiding (Header)
27−import Network.Wai (Response, Request, ResponseReceived, Application, pathInfo, requestBody,
27+import Network.Wai ( Response, Request, ResponseReceived, Application
28+ , pathInfo, requestBody, strictRequestBody
28− strictRequestBody, lazyRequestBody, requestHeaders, requestMethod,
29+ , lazyRequestBody, requestHeaders, requestMethod,
29 rawQueryString, responseLBS)
30 rawQueryString, responseLBS)
30−import Servant.API (QueryParams, QueryParam, QueryFlag, MatrixParams, MatrixParam, MatrixFlag, ReqBody, Header, Capture, Get, Delete, Put, Post, Patch, Raw, (:>), (:<|>)(..))
31+import Servant.API ( QueryParams, QueryParam, QueryFlag, ReqBody, Header
32+ , MatrixParams, MatrixParam, MatrixFlag,
33+ , Capture, Get, Delete, Put, Post, Patch, Raw, (:>), (:<|>)(..))
34+import Servant.Server.ContentTypes (AllCTRender(..), AcceptHeader(..))
31import Servant.Common.Text (FromText, fromText)
35import Servant.Common.Text (FromText, fromText)
33data ReqBodyState = Uncalled
37data ReqBodyState = Uncalled
@@ -225,7 +229,7 @@ instance (KnownSymbol capture, FromText a, HasServer sublayout)
225 _ -> respond $ failWith NotFound
229 _ -> respond $ failWith NotFound
227 where captureProxy = Proxy :: Proxy (Capture capture a)
231 where captureProxy = Proxy :: Proxy (Capture capture a)
230-- | If you have a 'Delete' endpoint in your API,
234-- | If you have a 'Delete' endpoint in your API,
231-- the handler for this endpoint is meant to delete
235-- the handler for this endpoint is meant to delete
@@ -264,14 +268,19 @@ instance HasServer Delete where
264-- If successfully returning a value, we just require that its type has
268-- If successfully returning a value, we just require that its type has
265-- a 'ToJSON' instance and servant takes care of encoding it for you,
269-- a 'ToJSON' instance and servant takes care of encoding it for you,
266-- yielding status code 200 along the way.
270-- yielding status code 200 along the way.
271+instance ( AllCTRender ctypes a, ToJSON a
267−instance ToJSON result => HasServer (Get result) where
272+ ) => HasServer (Get ctypes a) where
268− type Server (Get result) = EitherT (Int, String) IO result
273+ type Server (Get ctypes a) = EitherT (Int, String) IO a
269 route Proxy action request respond
274 route Proxy action request respond
270 | pathIsEmpty request && requestMethod request == methodGet = do
275 | pathIsEmpty request && requestMethod request == methodGet = do
271 e <- runEitherT action
276 e <- runEitherT action
272 respond . succeedWith $ case e of
277 respond . succeedWith $ case e of
273− Right output ->
278+ Right output -> do
279+ let accH = fromMaybe "*/*" $ lookup hAccept $ requestHeaders request
280+ case handleAcceptH (Proxy :: Proxy ctypes) (AcceptHeader accH) output of
281+ Nothing -> responseLBS (mkStatus 406 "") [] ""
274− responseLBS ok200 [("Content-Type", "application/json")] (encode output)
282+ Just (contentT, body) -> responseLBS ok200 [ ("Content-Type"
283+ , cs contentT)] body
275 Left (status, message) ->
284 Left (status, message) ->
276 responseLBS (mkStatus status (cs message)) [] (cs message)
285 responseLBS (mkStatus status (cs message)) [] (cs message)
277 | pathIsEmpty request && requestMethod request /= methodGet =
286 | pathIsEmpty request && requestMethod request /= methodGet =
@@ -321,15 +330,20 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
321-- If successfully returning a value, we just require that its type has
330-- If successfully returning a value, we just require that its type has
322-- a 'ToJSON' instance and servant takes care of encoding it for you,
331-- a 'ToJSON' instance and servant takes care of encoding it for you,
323-- yielding status code 201 along the way.
332-- yielding status code 201 along the way.
333+instance ( AllCTRender ctypes a, ToJSON a
324−instance ToJSON a => HasServer (Post a) where
334+ )=> HasServer (Post ctypes a) where
325− type Server (Post a) = EitherT (Int, String) IO a
335+ type Server (Post ctypes a) = EitherT (Int, String) IO a
327 route Proxy action request respond
337 route Proxy action request respond
328 | pathIsEmpty request && requestMethod request == methodPost = do
338 | pathIsEmpty request && requestMethod request == methodPost = do
329 e <- runEitherT action
339 e <- runEitherT action
330 respond . succeedWith $ case e of
340 respond . succeedWith $ case e of
331− Right out ->
341+ Right output -> do
342+ let accH = fromMaybe "*/*" $ lookup hAccept $ requestHeaders request
343+ case handleAcceptH (Proxy :: Proxy ctypes) (AcceptHeader accH) output of
344+ Nothing -> responseLBS (mkStatus 406 "") [] ""
332− responseLBS status201 [("Content-Type", "application/json")] (encode out)
345+ Just (contentT, body) -> responseLBS status201 [ ("Content-Type"
346+ , cs contentT)] body
333 Left (status, message) ->
347 Left (status, message) ->
334 responseLBS (mkStatus status (cs message)) [] (cs message)
348 responseLBS (mkStatus status (cs message)) [] (cs message)
335 | pathIsEmpty request && requestMethod request /= methodPost =
349 | pathIsEmpty request && requestMethod request /= methodPost =
@@ -347,15 +361,20 @@ instance ToJSON a => HasServer (Post a) where
347-- If successfully returning a value, we just require that its type has
361-- If successfully returning a value, we just require that its type has
348-- a 'ToJSON' instance and servant takes care of encoding it for you,
362-- a 'ToJSON' instance and servant takes care of encoding it for you,
349-- yielding status code 200 along the way.
363-- yielding status code 200 along the way.
364+instance ( AllCTRender ctypes a, ToJSON a
350−instance ToJSON a => HasServer (Put a) where
365+ ) => HasServer (Put ctypes a) where
351− type Server (Put a) = EitherT (Int, String) IO a
366+ type Server (Put ctypes a) = EitherT (Int, String) IO a
353 route Proxy action request respond
368 route Proxy action request respond
354 | pathIsEmpty request && requestMethod request == methodPut = do
369 | pathIsEmpty request && requestMethod request == methodPut = do
355 e <- runEitherT action
370 e <- runEitherT action
356 respond . succeedWith $ case e of
371 respond . succeedWith $ case e of
357− Right out ->
372+ Right output -> do
358− responseLBS ok200 [("Content-Type", "application/json")] (encode out)
373+ let accH = fromMaybe "*/*" $ lookup hAccept $ requestHeaders request
374+ case handleAcceptH (Proxy :: Proxy ctypes) (AcceptHeader accH) output of
375+ Nothing -> responseLBS (mkStatus 406 "") [] ""
376+ Just (contentT, body) -> responseLBS status200 [ ("Content-Type"
377+ , cs contentT)] body
359 Left (status, message) ->
378 Left (status, message) ->
360 responseLBS (mkStatus status (cs message)) [] (cs message)
379 responseLBS (mkStatus status (cs message)) [] (cs message)
361 | pathIsEmpty request && requestMethod request /= methodPut =
380 | pathIsEmpty request && requestMethod request /= methodPut =
@@ -382,7 +401,7 @@ instance (Typeable a, ToJSON a) => HasServer (Patch a) where
382 e <- runEitherT action
401 e <- runEitherT action
383 respond . succeedWith $ case e of
402 respond . succeedWith $ case e of
384 Right out -> case cast out of
403 Right out -> case cast out of
385− Nothing -> responseLBS status200 [("Content-Type", "application/json")] (encode out)
404+ Nothing -> responseLBS status200 [("Content-Type", "application/json")] (encode out)
386 Just () -> responseLBS status204 [] ""
405 Just () -> responseLBS status204 [] ""
387 Left (status, message) ->
406 Left (status, message) ->
388 responseLBS (mkStatus status (cs message)) [] (cs message)
407 responseLBS (mkStatus status (cs message)) [] (cs message)