Custom JSON errors for Servant-server

前端 未结 3 1112
温柔的废话
温柔的废话 2021-01-12 20:13

When using servant, I\'d like to return all errors as JSON. Currently, if a request fails to parse, I see an error message like this, returned as plain text

         


        
3条回答
  •  一个人的身影
    2021-01-12 21:19

    Taking inspiration from @codedmart I also use a middleware, but it does not construct the json, it only changes the content type of the response when there is an error, and keep the original error message.

    startApp :: IO ()
    startApp = run 8081 . (modifyResponse errorHeadersToJson) $ serve api server
    
    errorHeadersToJson :: Response -> Response
    errorHeadersToJson r
      | responseStatus r == status200 = r
      | otherwise = mapResponseHeaders text2json r
    
    text2json :: ResponseHeaders -> ResponseHeaders
    text2json h = Map.assocs (Map.fromList [("Content-Type", "application/json")] `Map.union` Map.fromList h)
    

    The json is built beforehand with a function overriding the Servant throwError function.

    data ServerError = ServerError
      { statusCode        :: Int
      , error :: String
      , message  :: String
      } deriving (Eq, Show)
    
    $(deriveJSON defaultOptions ''ServerError)
    
    throwJsonError :: ServantErr -> String -> Servant.Handler b
    throwJsonError err "" = throwError $ err { errBody = encode $ ServerError (errHTTPCode err) ("Server error"::String) (show $ errBody err) }
    throwJsonError err message = throwError $ err { errBody = encode $ ServerError (errHTTPCode err) ("Server error"::String) message }
    

    then I can throw any error with a custom message, it will be served as a json with the correct content-type :

    throwJsonError err500 "Oh no !"
    

提交回复
热议问题