rfc-0.0.0.18: src/RFC/Servant/ApiDoc.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RecordWildCards #-}
module RFC.Servant.ApiDoc
( apiToHtml
, apiToAscii
, apiToSwagger
, apiApplication
) where
import Data.Aeson.Types (fromEncoding, toEncoding)
import qualified Data.Binary.Builder as Builder
import Data.Char as Char
import Data.Default (def)
import Network.HTTP.Types.Header (hContentType)
import Network.HTTP.Types.Status
import Network.Wai
import RFC.Prelude
import RFC.Servant
import RFC.String
import Servant.Swagger
import qualified Text.Blaze.Html.Renderer.String as Blaze
import qualified Text.Markdown as MD
apiToHtml :: (HasDocs a) => Proxy a -> Html
apiToHtml = preEscapedToHtml . (MD.markdown mdSettings) . cs . markdown . docs
where
mdSettings = def
{ MD.msLinkNewTab = False
, MD.msAddHeadingId = True
}
apiToAscii :: (ConvertibleString String s, HasDocs a) => Proxy a -> s
apiToAscii = cs . markdown . docs
apiToSwagger :: (HasSwagger a) => Proxy a -> Swagger
apiToSwagger = toSwagger
apiApplication :: (HasDocs a, HasSwagger a) => Proxy a -> Application
apiApplication api request callback =
case reqMethod of
"GET" -> checkPath
_ -> failMethodNotAllowed
where
html = Blaze.renderHtml $ apiToHtml api
ascii :: LazyByteString
ascii = apiToAscii api
swaggerToLbs :: Swagger -> LazyByteString
swaggerToLbs = Builder.toLazyByteString . fromEncoding . toEncoding
swagger = swaggerToLbs $ apiToSwagger api
reqMethod :: String
reqMethod = map Char.toUpper $ cs $ requestMethod request
pathInfo :: String
pathInfo = map Char.toLower $ cs $ rawPathInfo request
checkPath =
case pathInfo of
"swagger.json" -> serveSwagger
"/swagger.json" -> serveSwagger
"api.html" -> serveHtml
"/api.html" -> serveHtml
"api.txt" -> serveTxt
"/api.txt" -> serveTxt
_ -> failPathNotFound
response ::
(ConvertibleStrings contentType StrictByteString, ConvertibleStrings body LazyByteString) =>
contentType -> body -> IO ResponseReceived
response contentType body = callback $
responseLBS status200 [(hContentType, cs contentType)] (cs body)
serveHtml = response "text/html" html
serveTxt = response "text/plain" ascii
serveSwagger = response "application/json" swagger
failMethodNotAllowed :: IO ResponseReceived
failMethodNotAllowed = callback $
responseLBS status405 [(hContentType, cs "text/plain")] (cs $ "Unsupported HTTP method: " ++ reqMethod)
failPathNotFound :: IO ResponseReceived
failPathNotFound = callback $
responseLBS status404 [(hContentType, cs "text/plain")] (cs $ "Path not found: " ++ pathInfo)