{-# LANGUAGE OverloadedStrings #-} module Test.Swagger.Print (Format(..) , requestFormats , responseFormats , printRequest , printResponse) where import Data.Aeson import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS import Data.CaseInsensitive import Data.Maybe import Data.Monoid import qualified Data.Text as T import Data.Text.Encoding import Data.Text.Lazy.Builder import Network.HTTP.Types import Test.Swagger.Types -- |Possible output formats that applies to 'HttpRequest' and 'HttpResponse' -- values data Format = FormatHttp | FormatCurl | FormatNone | FormatJSON deriving (Bounded, Enum) instance Show Format where show FormatHttp = "http" show FormatCurl = "curl" show FormatNone = "none" show FormatJSON = "json" requestFormats, responseFormats :: [Format] -- |Valid output formats for 'HttpRequest' values requestFormats = [minBound..] -- |Valid output formats for 'HttpResponse' values responseFormats = [FormatHttp, FormatJSON, FormatNone] -- |Print a request according to format printRequest :: Format -> HttpRequest -> Builder printRequest FormatJSON r = fromUtf8Bytestring $ LBS.toStrict $ encode r printRequest FormatNone _ = mempty printRequest FormatHttp (HttpRequest _ method path query headers body) = fromUtf8Bytestring method <> fromText " " <> fromText path <> fromUtf8Bytestring (renderQuery True $ queryTextToQuery query) <> fromTextLn " HTTP/1.1" <> mconcat ((\(k,v) -> fromTextLn $ original k <> ": " <> v) <$> headers) <> case body of Just b -> fromText "\n" <> fromUtf8Bytestring (LBS.toStrict b) Nothing -> mempty printRequest FormatCurl (HttpRequest host method path query headers body) = fromText "curl -i" <> if method /= methodGet then fromUtf8Bytestring $ " -X " <> method else mempty <> fromText " '" <> fromText (escapeS host') <> fromText (escape path) <> fromText (escapeBS $ renderQuery True $ queryTextToQuery query) <> singleton '\'' <> mconcat ((\(k,v) -> fromText $ " -H '" <> escape (original k) <> ": " <> escape v <> "'") <$> headers) <> case body of Just b -> fromTextLn $ " -d '" <> escapeLBS b <> "'" Nothing -> singleton '\n' where host' = fromMaybe "http://localhost" host escapeLBS :: LBS.ByteString -> T.Text escapeLBS = escapeBS . LBS.toStrict escapeBS :: BS.ByteString -> T.Text escapeBS = escape . decodeUtf8 escape :: T.Text -> T.Text escape = T.replace "'" "'\\''" escapeS :: String -> T.Text escapeS = escape . T.pack -- |Print a response according to format printResponse :: Format -> HttpResponse -> Builder printResponse FormatCurl _ = error "unsupported format" printResponse FormatJSON r = fromUtf8Bytestring $ LBS.toStrict $ encode r printResponse FormatNone _ = mempty printResponse FormatHttp r = let ver = responseHttpVersion r st = responseStatus r headers = responseHeaders r in fromString ("HTTP/" <> show (httpMajor ver) <> "." <> show (httpMinor ver) <> " ") <> fromString (show (statusCode st) <> " ") <> fromUtf8BytestringLn (statusMessage st) <> mconcat ((\(k,v) -> fromTextLn $ original k <> ": " <> v) <$> headers) <> case responseBody r of Just b -> fromText "\n" <> fromUtf8Bytestring (LBS.toStrict b) Nothing -> mempty fromUtf8Bytestring :: BS.ByteString -> Builder fromUtf8Bytestring = fromText . decodeUtf8 fromUtf8BytestringLn :: BS.ByteString -> Builder fromUtf8BytestringLn = fromTextLn . decodeUtf8 fromTextLn :: T.Text -> Builder fromTextLn t = fromText t <> fromText "\n"