packages feed

servant-swagger 0.0.0.1 → 0.1

raw patch · 10 files changed

+1100/−1115 lines, 10 filesdep +aeson-qqdep +hspecdep +http-mediadep −containersdep −hashabledep −uuiddep ~basedep ~servantnew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: aeson-qq, hspec, http-media, servant-swagger, swagger2, time

Dependencies removed: containers, hashable, uuid

Dependency ranges changed: base, servant

API changes (from Hackage documentation)

- Servant.Swagger: APIDescription :: Text -> APIDescription
- Servant.Swagger: APILicense :: Text -> Maybe Text -> APILicense
- Servant.Swagger: APITitle :: Text -> APITitle
- Servant.Swagger: APIVersion :: Text -> APIVersion
- Servant.Swagger: ArraySwagParam :: SwaggerParamType
- Servant.Swagger: BasePath :: Text -> BasePath
- Servant.Swagger: BinarySwag :: SwaggerType
- Servant.Swagger: BooleanSwag :: SwaggerType
- Servant.Swagger: BooleanSwagParam :: SwaggerParamType
- Servant.Swagger: ByteSwag :: SwaggerType
- Servant.Swagger: Code :: Int -> Code
- Servant.Swagger: Contact :: ContactName -> ContactURL -> ContactEmail -> Contact
- Servant.Swagger: ContactEmail :: Text -> ContactEmail
- Servant.Swagger: ContactName :: Text -> ContactName
- Servant.Swagger: ContactURL :: Text -> ContactURL
- Servant.Swagger: DateSwag :: SwaggerType
- Servant.Swagger: DateTimeSwag :: SwaggerType
- Servant.Swagger: Delete :: Verb
- Servant.Swagger: Description :: Text -> Description
- Servant.Swagger: DoubleSwag :: SwaggerType
- Servant.Swagger: FileSwagParam :: SwaggerParamType
- Servant.Swagger: FloatSwag :: SwaggerType
- Servant.Swagger: FormUrlEncoded :: ContentType
- Servant.Swagger: Get :: Verb
- Servant.Swagger: HTML :: ContentType
- Servant.Swagger: Head :: Verb
- Servant.Swagger: Http :: Scheme
- Servant.Swagger: Https :: Scheme
- Servant.Swagger: Info :: APITitle -> APIVersion -> APIDescription -> Maybe APILicense -> Maybe Contact -> Maybe TermsOfService -> Info
- Servant.Swagger: IntegerSwag :: SwaggerType
- Servant.Swagger: IntegerSwagParam :: SwaggerParamType
- Servant.Swagger: JSON :: ContentType
- Servant.Swagger: LongSwag :: SwaggerType
- Servant.Swagger: Model :: ModelSwag -> SwaggerType
- Servant.Swagger: ModelName :: Text -> ModelName
- Servant.Swagger: ModelSwag :: ModelName -> Bool -> ModelSwag
- Servant.Swagger: NumberSwagParam :: SwaggerParamType
- Servant.Swagger: OctetStream :: ContentType
- Servant.Swagger: Operation :: PathSummary -> [Param] -> HashMap Code Response -> [ContentType] -> [ContentType] -> [Tag] -> Maybe OperationId -> PathDescription -> Maybe Deprecated -> Operation
- Servant.Swagger: OperationId :: Text -> OperationId
- Servant.Swagger: Options :: Verb
- Servant.Swagger: PasswordSwag :: SwaggerType
- Servant.Swagger: Patch :: Verb
- Servant.Swagger: PathDescription :: Text -> PathDescription
- Servant.Swagger: PathSummary :: Text -> PathSummary
- Servant.Swagger: PlainText :: ContentType
- Servant.Swagger: Post :: Verb
- Servant.Swagger: Put :: Verb
- Servant.Swagger: Response :: Text -> ModelName -> HashMap Text SwaggerHeader -> Bool -> Code -> Response
- Servant.Swagger: StringSwag :: SwaggerType
- Servant.Swagger: StringSwagParam :: SwaggerParamType
- Servant.Swagger: SwaggerAPI :: Info -> HashMap PathName SwaggerOperation -> Maybe [Scheme] -> HashMap ModelName SwaggerModel -> Maybe [Tag] -> Maybe BasePath -> Maybe HostName -> Maybe [SecurityDefinition] -> Maybe ExternalDocs -> SwaggerAPI
- Servant.Swagger: SwaggerHeader :: Text -> SwaggerParamType -> Text -> SwaggerHeader
- Servant.Swagger: SwaggerModel :: ModelName -> [(Text, SwaggerType)] -> Maybe Description -> Maybe Value -> [Text] -> SwaggerModel
- Servant.Swagger: SwaggerOperation :: HashMap Verb Operation -> SwaggerOperation
- Servant.Swagger: SwaggerRouteInfo :: SwagResult -> SwaggerRouteInfo a
- Servant.Swagger: Tag :: TagName -> TagDescription -> Tag
- Servant.Swagger: TagDescription :: Text -> TagDescription
- Servant.Swagger: TagName :: Text -> TagName
- Servant.Swagger: TermsOfService :: Text -> TermsOfService
- Servant.Swagger: Ws :: Scheme
- Servant.Swagger: Wss :: Scheme
- Servant.Swagger: XML :: ContentType
- Servant.Swagger: [_consumes] :: Operation -> [ContentType]
- Servant.Swagger: [_contactEmail] :: Contact -> ContactEmail
- Servant.Swagger: [_contactName] :: Contact -> ContactName
- Servant.Swagger: [_contactURL] :: Contact -> ContactURL
- Servant.Swagger: [_contact] :: Info -> Maybe Contact
- Servant.Swagger: [_deprecated] :: Operation -> Maybe Deprecated
- Servant.Swagger: [_description] :: Operation -> PathDescription
- Servant.Swagger: [_licenseName] :: APILicense -> Text
- Servant.Swagger: [_licenseUrl] :: APILicense -> Maybe Text
- Servant.Swagger: [_license] :: Info -> Maybe APILicense
- Servant.Swagger: [_operationId] :: Operation -> Maybe OperationId
- Servant.Swagger: [_params] :: Operation -> [Param]
- Servant.Swagger: [_paths] :: SwaggerOperation -> HashMap Verb Operation
- Servant.Swagger: [_produces] :: Operation -> [ContentType]
- Servant.Swagger: [_responseCode] :: Response -> Code
- Servant.Swagger: [_responseDescription] :: Response -> Text
- Servant.Swagger: [_responseHeaders] :: Response -> HashMap Text SwaggerHeader
- Servant.Swagger: [_responseIsArray] :: Response -> Bool
- Servant.Swagger: [_responseModelName] :: Response -> ModelName
- Servant.Swagger: [_responses] :: Operation -> HashMap Code Response
- Servant.Swagger: [_summary] :: Operation -> PathSummary
- Servant.Swagger: [_swagDescription] :: SwaggerModel -> Maybe Description
- Servant.Swagger: [_swagModelExample] :: SwaggerModel -> Maybe Value
- Servant.Swagger: [_swagModelName] :: SwaggerModel -> ModelName
- Servant.Swagger: [_swagModelRequired] :: SwaggerModel -> [Text]
- Servant.Swagger: [_swagProperties] :: SwaggerModel -> [(Text, SwaggerType)]
- Servant.Swagger: [_swaggerAPIDescription] :: Info -> APIDescription
- Servant.Swagger: [_swaggerBasePath] :: SwaggerAPI -> Maybe BasePath
- Servant.Swagger: [_swaggerDefinitions] :: SwaggerAPI -> HashMap ModelName SwaggerModel
- Servant.Swagger: [_swaggerExternalDocs] :: SwaggerAPI -> Maybe ExternalDocs
- Servant.Swagger: [_swaggerHostName] :: SwaggerAPI -> Maybe HostName
- Servant.Swagger: [_swaggerInfoTitle] :: Info -> APITitle
- Servant.Swagger: [_swaggerInfo] :: SwaggerAPI -> Info
- Servant.Swagger: [_swaggerPaths] :: SwaggerAPI -> HashMap PathName SwaggerOperation
- Servant.Swagger: [_swaggerSchemes] :: SwaggerAPI -> Maybe [Scheme]
- Servant.Swagger: [_swaggerSecurityDefintions] :: SwaggerAPI -> Maybe [SecurityDefinition]
- Servant.Swagger: [_swaggerTags] :: SwaggerAPI -> Maybe [Tag]
- Servant.Swagger: [_swaggerVersion] :: Info -> APIVersion
- Servant.Swagger: [_tagDescription] :: Tag -> TagDescription
- Servant.Swagger: [_tagName] :: Tag -> TagName
- Servant.Swagger: [_tags] :: Operation -> [Tag]
- Servant.Swagger: [_termsOfService] :: Info -> Maybe TermsOfService
- Servant.Swagger: [_unApiDesc] :: APIDescription -> Text
- Servant.Swagger: [headerDescription] :: SwaggerHeader -> Text
- Servant.Swagger: [headerName] :: SwaggerHeader -> Text
- Servant.Swagger: [headerType] :: SwaggerHeader -> SwaggerParamType
- Servant.Swagger: [modelSwagIsArray] :: ModelSwag -> Bool
- Servant.Swagger: [modelSwagName] :: ModelSwag -> ModelName
- Servant.Swagger: [unDescription] :: Description -> Text
- Servant.Swagger: [unModelName] :: ModelName -> Text
- Servant.Swagger: class ToHeader a
- Servant.Swagger: class ToHeaderDescription a
- Servant.Swagger: class ToModelExample model
- Servant.Swagger: class ToSwaggerDescription a
- Servant.Swagger: class ToSwaggerModel a where toSwagModelName = _swagModelName . toSwagModel toSwagModel = undefined
- Servant.Swagger: class ToSwaggerParamType a
- Servant.Swagger: contact :: Lens' Info (Maybe Contact)
- Servant.Swagger: createSwaggerJson :: SwaggerAPI -> IO ()
- Servant.Swagger: data APILicense
- Servant.Swagger: data Contact
- Servant.Swagger: data ContentType
- Servant.Swagger: data Info
- Servant.Swagger: data ModelSwag
- Servant.Swagger: data Operation
- Servant.Swagger: data Response
- Servant.Swagger: data Scheme
- Servant.Swagger: data SwaggerAPI
- Servant.Swagger: data SwaggerHeader
- Servant.Swagger: data SwaggerModel
- Servant.Swagger: data SwaggerOperation
- Servant.Swagger: data SwaggerParamType
- Servant.Swagger: data SwaggerType
- Servant.Swagger: data Tag
- Servant.Swagger: data Verb
- Servant.Swagger: defResponse :: Response
- Servant.Swagger: defSwaggerInfo :: Info
- Servant.Swagger: emptyModel :: SwaggerModel
- Servant.Swagger: emptyRouteDescription :: SwaggerRouteDescription
- Servant.Swagger: license :: Lens' Info (Maybe APILicense)
- Servant.Swagger: newtype APIDescription
- Servant.Swagger: newtype APITitle
- Servant.Swagger: newtype APIVersion
- Servant.Swagger: newtype BasePath
- Servant.Swagger: newtype Code
- Servant.Swagger: newtype ContactEmail
- Servant.Swagger: newtype ContactName
- Servant.Swagger: newtype ContactURL
- Servant.Swagger: newtype Description
- Servant.Swagger: newtype ModelName
- Servant.Swagger: newtype OperationId
- Servant.Swagger: newtype PathDescription
- Servant.Swagger: newtype PathSummary
- Servant.Swagger: newtype SwaggerRouteInfo a
- Servant.Swagger: newtype TagDescription
- Servant.Swagger: newtype TagName
- Servant.Swagger: newtype TermsOfService
- Servant.Swagger: responseCode :: Lens' Response Code
- Servant.Swagger: responseDescription :: Lens' Response Text
- Servant.Swagger: responseHeaders :: Lens' Response (HashMap Text SwaggerHeader)
- Servant.Swagger: responseIsArray :: Lens' Response Bool
- Servant.Swagger: responseModelName :: Lens' Response ModelName
- Servant.Swagger: swagDescription :: Lens' SwaggerModel (Maybe Description)
- Servant.Swagger: swagModelExample :: Lens' SwaggerModel (Maybe Value)
- Servant.Swagger: swagModelName :: Lens' SwaggerModel ModelName
- Servant.Swagger: swagModelRequired :: Lens' SwaggerModel [Text]
- Servant.Swagger: swagProperties :: Lens' SwaggerModel [(Text, SwaggerType)]
- Servant.Swagger: swagRouteDescription :: Lens' SwaggerRouteDescription PathDescription
- Servant.Swagger: swagRouteModels :: Lens' SwaggerRouteDescription (HashMap ModelName SwaggerModel)
- Servant.Swagger: swagRouteOperationId :: Lens' SwaggerRouteDescription (Maybe OperationId)
- Servant.Swagger: swagRouteResponses :: Lens' SwaggerRouteDescription (HashMap Code Response)
- Servant.Swagger: swagRouteSummary :: Lens' SwaggerRouteDescription PathSummary
- Servant.Swagger: swagRouteTags :: Lens' SwaggerRouteDescription [Tag]
- Servant.Swagger: swagger :: HasSwagger swagger => Proxy swagger -> SwaggerRouteInfo swagger -> BasePath -> Info -> [Scheme] -> Maybe HostName -> [SecurityDefinition] -> SwaggerAPI
- Servant.Swagger: swaggerAPIDescription :: Lens' Info APIDescription
- Servant.Swagger: swaggerInfoTitle :: Lens' Info APITitle
- Servant.Swagger: swaggerPathInfo :: (IsElem endpoint layout, HasLink endpoint, HasSwagger endpoint, HasSwagger layout) => Proxy endpoint -> Proxy layout -> SwaggerRouteDescription -> SwaggerRouteInfo layout
- Servant.Swagger: swaggerVersion :: Lens' Info APIVersion
- Servant.Swagger: tagDescription :: Lens' Tag TagDescription
- Servant.Swagger: tagName :: Lens' Tag TagName
- Servant.Swagger: termsOfService :: Lens' Info (Maybe TermsOfService)
- Servant.Swagger: toExample :: ToModelExample model => Proxy model -> Maybe Value
- Servant.Swagger: toHeader :: ToHeader a => Proxy a -> SwaggerHeader
- Servant.Swagger: toHeaderDescription :: ToHeaderDescription a => Proxy a -> Text
- Servant.Swagger: toSwagModel :: ToSwaggerModel a => Proxy a -> SwaggerModel
- Servant.Swagger: toSwagModelName :: ToSwaggerModel a => Proxy a -> ModelName
- Servant.Swagger: toSwaggerDescription :: ToSwaggerDescription a => Proxy a -> Text
- Servant.Swagger: toSwaggerDocs :: HasSwagger h => Proxy h -> SwaggerRoute -> SwagResult
- Servant.Swagger: toSwaggerParamType :: ToSwaggerParamType a => Proxy a -> SwaggerParamType
+ Servant.Swagger: addTag :: TagName -> Operation -> Operation
+ Servant.Swagger: class AllAccept cs
+ Servant.Swagger: class AllToResponseHeader hs
+ Servant.Swagger: class ToResponseHeader h
+ Servant.Swagger: setResponse :: HttpStatusCode -> Response -> Operation -> Operation
+ Servant.Swagger: subOperations :: (IsSubAPI sub api, HasSwagger sub) => Proxy sub -> Proxy api -> Traversal' Swagger Operation
+ Servant.Swagger: toResponseHeader :: ToResponseHeader h => Proxy h -> (HeaderName, Header)
+ Servant.Swagger: toSwagger :: HasSwagger api => Proxy api -> Swagger
+ Servant.Swagger.Internal: (</>) :: FilePath -> FilePath -> FilePath
+ Servant.Swagger.Internal: addConsumes :: [MediaType] -> Swagger -> Swagger
+ Servant.Swagger.Internal: addDefaultResponse400 :: ParamName -> Swagger -> Swagger
+ Servant.Swagger.Internal: addDefaultResponse404 :: ParamName -> Swagger -> Swagger
+ Servant.Swagger.Internal: addParam :: Param -> Swagger -> Swagger
+ Servant.Swagger.Internal: addResponse :: HttpStatusCode -> Response -> Swagger -> Swagger
+ Servant.Swagger.Internal: addResponseWith :: (Response -> Response -> Response) -> HttpStatusCode -> Response -> Swagger -> Swagger
+ Servant.Swagger.Internal: addTag :: TagName -> Operation -> Operation
+ Servant.Swagger.Internal: allContentType :: AllAccept cs => Proxy cs -> [MediaType]
+ Servant.Swagger.Internal: class AllAccept cs
+ Servant.Swagger.Internal: class AllToResponseHeader hs
+ Servant.Swagger.Internal: class HasSwagger api
+ Servant.Swagger.Internal: class ToResponseHeader h
+ Servant.Swagger.Internal: instance (Data.Swagger.Internal.Schema.ToSchema a, Servant.Swagger.Internal.AllAccept cs) => Servant.Swagger.Internal.HasSwagger (Servant.API.Delete.Delete cs a)
+ Servant.Swagger.Internal: instance (Data.Swagger.Internal.Schema.ToSchema a, Servant.Swagger.Internal.AllAccept cs) => Servant.Swagger.Internal.HasSwagger (Servant.API.Get.Get cs a)
+ Servant.Swagger.Internal: instance (Data.Swagger.Internal.Schema.ToSchema a, Servant.Swagger.Internal.AllAccept cs) => Servant.Swagger.Internal.HasSwagger (Servant.API.Patch.Patch cs a)
+ Servant.Swagger.Internal: instance (Data.Swagger.Internal.Schema.ToSchema a, Servant.Swagger.Internal.AllAccept cs) => Servant.Swagger.Internal.HasSwagger (Servant.API.Post.Post cs a)
+ Servant.Swagger.Internal: instance (Data.Swagger.Internal.Schema.ToSchema a, Servant.Swagger.Internal.AllAccept cs) => Servant.Swagger.Internal.HasSwagger (Servant.API.Put.Put cs a)
+ Servant.Swagger.Internal: instance (Data.Swagger.Internal.Schema.ToSchema a, Servant.Swagger.Internal.AllAccept cs, Servant.Swagger.Internal.AllToResponseHeader hs) => Servant.Swagger.Internal.HasSwagger (Servant.API.Delete.Delete cs (Servant.API.ResponseHeaders.Headers hs a))
+ Servant.Swagger.Internal: instance (Data.Swagger.Internal.Schema.ToSchema a, Servant.Swagger.Internal.AllAccept cs, Servant.Swagger.Internal.AllToResponseHeader hs) => Servant.Swagger.Internal.HasSwagger (Servant.API.Get.Get cs (Servant.API.ResponseHeaders.Headers hs a))
+ Servant.Swagger.Internal: instance (Data.Swagger.Internal.Schema.ToSchema a, Servant.Swagger.Internal.AllAccept cs, Servant.Swagger.Internal.AllToResponseHeader hs) => Servant.Swagger.Internal.HasSwagger (Servant.API.Patch.Patch cs (Servant.API.ResponseHeaders.Headers hs a))
+ Servant.Swagger.Internal: instance (Data.Swagger.Internal.Schema.ToSchema a, Servant.Swagger.Internal.AllAccept cs, Servant.Swagger.Internal.AllToResponseHeader hs) => Servant.Swagger.Internal.HasSwagger (Servant.API.Post.Post cs (Servant.API.ResponseHeaders.Headers hs a))
+ Servant.Swagger.Internal: instance (Data.Swagger.Internal.Schema.ToSchema a, Servant.Swagger.Internal.AllAccept cs, Servant.Swagger.Internal.AllToResponseHeader hs) => Servant.Swagger.Internal.HasSwagger (Servant.API.Put.Put cs (Servant.API.ResponseHeaders.Headers hs a))
+ Servant.Swagger.Internal: instance (GHC.TypeLits.KnownSymbol sym, Data.Swagger.Internal.ParamSchema.ToParamSchema a) => Servant.Swagger.Internal.ToResponseHeader (Servant.API.Header.Header sym a)
+ Servant.Swagger.Internal: instance (Servant.Swagger.Internal.HasSwagger a, Servant.Swagger.Internal.HasSwagger b) => Servant.Swagger.Internal.HasSwagger (a Servant.API.Alternative.:<|> b)
+ Servant.Swagger.Internal: instance Servant.Swagger.Internal.AllAccept '[]
+ Servant.Swagger.Internal: instance Servant.Swagger.Internal.AllAccept cs => Servant.Swagger.Internal.HasSwagger (Servant.API.Delete.Delete cs ())
+ Servant.Swagger.Internal: instance Servant.Swagger.Internal.AllAccept cs => Servant.Swagger.Internal.HasSwagger (Servant.API.Get.Get cs ())
+ Servant.Swagger.Internal: instance Servant.Swagger.Internal.AllAccept cs => Servant.Swagger.Internal.HasSwagger (Servant.API.Patch.Patch cs ())
+ Servant.Swagger.Internal: instance Servant.Swagger.Internal.AllAccept cs => Servant.Swagger.Internal.HasSwagger (Servant.API.Post.Post cs ())
+ Servant.Swagger.Internal: instance Servant.Swagger.Internal.AllAccept cs => Servant.Swagger.Internal.HasSwagger (Servant.API.Put.Put cs ())
+ Servant.Swagger.Internal: instance Servant.Swagger.Internal.AllToResponseHeader '[]
+ Servant.Swagger.Internal: instance Servant.Swagger.Internal.AllToResponseHeader hs => Servant.Swagger.Internal.AllToResponseHeader (Servant.API.ResponseHeaders.HList hs)
+ Servant.Swagger.Internal: instance Servant.Swagger.Internal.HasSwagger Servant.API.Raw.Raw
+ Servant.Swagger.Internal: instance forall (k :: BOX) (c :: k) (cs :: [k]). (Servant.API.ContentTypes.Accept c, Servant.Swagger.Internal.AllAccept cs) => Servant.Swagger.Internal.AllAccept (c : cs)
+ Servant.Swagger.Internal: instance forall (k :: BOX) (cs :: [*]) a (sub :: k). (Data.Swagger.Internal.Schema.ToSchema a, Servant.Swagger.Internal.AllAccept cs, Servant.Swagger.Internal.HasSwagger sub) => Servant.Swagger.Internal.HasSwagger (Servant.API.ReqBody.ReqBody cs a Servant.API.Sub.:> sub)
+ Servant.Swagger.Internal: instance forall (k :: BOX) (h :: k) (hs :: [k]). (Servant.Swagger.Internal.ToResponseHeader h, Servant.Swagger.Internal.AllToResponseHeader hs) => Servant.Swagger.Internal.AllToResponseHeader (h : hs)
+ Servant.Swagger.Internal: instance forall (k :: BOX) (sym :: GHC.TypeLits.Symbol) (sub :: k). (GHC.TypeLits.KnownSymbol sym, Servant.Swagger.Internal.HasSwagger sub) => Servant.Swagger.Internal.HasSwagger (Servant.API.QueryParam.QueryFlag sym Servant.API.Sub.:> sub)
+ Servant.Swagger.Internal: instance forall (k :: BOX) (sym :: GHC.TypeLits.Symbol) (sub :: k). (GHC.TypeLits.KnownSymbol sym, Servant.Swagger.Internal.HasSwagger sub) => Servant.Swagger.Internal.HasSwagger (sym Servant.API.Sub.:> sub)
+ Servant.Swagger.Internal: instance forall (k :: BOX) (sym :: GHC.TypeLits.Symbol) a (sub :: k). (GHC.TypeLits.KnownSymbol sym, Data.Swagger.Internal.ParamSchema.ToParamSchema a, Servant.Swagger.Internal.HasSwagger sub) => Servant.Swagger.Internal.HasSwagger (Servant.API.Capture.Capture sym a Servant.API.Sub.:> sub)
+ Servant.Swagger.Internal: instance forall (k :: BOX) (sym :: GHC.TypeLits.Symbol) a (sub :: k). (GHC.TypeLits.KnownSymbol sym, Data.Swagger.Internal.ParamSchema.ToParamSchema a, Servant.Swagger.Internal.HasSwagger sub) => Servant.Swagger.Internal.HasSwagger (Servant.API.Header.Header sym a Servant.API.Sub.:> sub)
+ Servant.Swagger.Internal: instance forall (k :: BOX) (sym :: GHC.TypeLits.Symbol) a (sub :: k). (GHC.TypeLits.KnownSymbol sym, Data.Swagger.Internal.ParamSchema.ToParamSchema a, Servant.Swagger.Internal.HasSwagger sub) => Servant.Swagger.Internal.HasSwagger (Servant.API.QueryParam.QueryParam sym a Servant.API.Sub.:> sub)
+ Servant.Swagger.Internal: instance forall (k :: BOX) (sym :: GHC.TypeLits.Symbol) a (sub :: k). (GHC.TypeLits.KnownSymbol sym, Data.Swagger.Internal.ParamSchema.ToParamSchema a, Servant.Swagger.Internal.HasSwagger sub) => Servant.Swagger.Internal.HasSwagger (Servant.API.QueryParam.QueryParams sym a Servant.API.Sub.:> sub)
+ Servant.Swagger.Internal: mkEndpoint :: (ToSchema a, AllAccept cs, AllToResponseHeader hs) => FilePath -> Lens' PathItem (Maybe Operation) -> HttpStatusCode -> proxy (_verb cs (Headers hs a)) -> Swagger
+ Servant.Swagger.Internal: mkEndpointWithSchemaRef :: (AllAccept cs, AllToResponseHeader hs) => Maybe (Referenced Schema) -> FilePath -> Lens' PathItem (Maybe Operation) -> HttpStatusCode -> proxy (verb cs (Headers hs a)) -> Swagger
+ Servant.Swagger.Internal: noContentEndpoint :: (AllAccept cs) => FilePath -> Lens' PathItem (Maybe Operation) -> proxy (verb cs ()) -> Swagger
+ Servant.Swagger.Internal: prependPath :: FilePath -> Swagger -> Swagger
+ Servant.Swagger.Internal: setResponse :: HttpStatusCode -> Response -> Operation -> Operation
+ Servant.Swagger.Internal: subOperations :: (IsSubAPI sub api, HasSwagger sub) => Proxy sub -> Proxy api -> Traversal' Swagger Operation
+ Servant.Swagger.Internal: toAllResponseHeaders :: AllToResponseHeader hs => Proxy hs -> HashMap HeaderName Header
+ Servant.Swagger.Internal: toResponseHeader :: ToResponseHeader h => Proxy h -> (HeaderName, Header)
+ Servant.Swagger.Internal: toSwagger :: HasSwagger api => Proxy api -> Swagger
- Servant.Swagger: class HasSwagger h
+ Servant.Swagger: class HasSwagger api

Files

LICENSE view
@@ -0,0 +1,28 @@+Copyright (c) 2015-2016, David Johnson+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++* Redistributions of source code must retain the above copyright notice, this+  list of conditions and the following disclaimer.++* Redistributions in binary form must reproduce the above copyright notice,+  this list of conditions and the following disclaimer in the documentation+  and/or other materials provided with the distribution.++* Neither the name of servant-swagger nor the names of its+  contributors may be used to endorse or promote products derived from+  this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ README.md view
@@ -0,0 +1,166 @@+<h1 align="center">+    <a href="https://github.com/dmjio/servant-swagger">+        servant-swagger+    </a>+    <br/>+    <a href="http://hackage.haskell.org/package/servant-swagger">+      <img alt="Hackage" src="https://img.shields.io/hackage/v/servant-swagger.svg" />+    </a>+</h1>++<p align="center">+  This project converts <a href="https://github.com/haskell-servant/servant">servant</a> APIs into Swagger 2.0 conforming JSON.+</p>++<p align="center">+  <img src="http://s16.postimg.org/rndz1wbyt/servant.png" />+</p>++<hr>++Given the following `servant` API, `servant-swagger` generates the following json.++### [Input](example/File.hs)++```haskell+{-# LANGUAGE DataKinds                  #-}+{-# LANGUAGE DeriveGeneric              #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE TypeOperators              #-}+module Main where++import Control.Lens+import Data.Aeson+import qualified Data.ByteString.Lazy.Char8 as BL8+import Data.Proxy+import Data.Swagger+import GHC.Generics+import Servant+import Servant.Swagger++-- Types+data Todo = Todo+  { created     :: Int+  , description :: String+  } deriving (Show, Eq, Generic)++instance ToJSON Todo++newtype TodoId = TodoId String deriving (FromText, Generic)++-- API+type API = "todo" :> Capture "id" TodoId :> Get '[JSON] Todo++-- Swagger Doc+swagDoc :: Swagger+swagDoc = toSwagger (Proxy :: Proxy API)+  & info.infoTitle   .~ "Todo API"+  & info.infoVersion .~ "1.0"+  & info.infoDescription ?~ "This is an API that tests servant-swagger support for a Todo"+  & info.infoLicense ?~ License "MIT" (Just (URL "http://mit.com"))++-- Documentation and annotations+instance ToParamSchema TodoId++instance ToSchema Todo where+  declareNamedSchema proxy = do+    (name, schema) <- genericDeclareNamedSchema defaultSchemaOptions proxy+    return (name, schema+      & schemaDescription ?~ "This is some real Todo right here"+      & schemaExample ?~ toJSON (Todo 100 "get milk"))++-- Main, create swaggger.json+main :: IO ()+main = BL8.writeFile "swagger.json" (encode swagDoc)+```++### Output++```json+{+   "swagger":"2.0",+   "info":{+      "version":"1.0",+      "title":"Todo API",+      "license":{+         "url":"http://mit.com",+         "name":"MIT"+      },+      "description":"This is an API that tests servant-swagger support for a Todo"+   },+   "definitions":{+      "Todo":{+         "example":{+            "created":100,+            "description":"get milk"+         },+         "required":[+            "created",+            "description"+         ],+         "type":"object",+         "description":"This is some real Todo right here",+         "properties":{+            "created":{+               "maximum":9223372036854775807,+               "minimum":-9223372036854775808,+               "type":"integer"+            },+            "description":{+               "type":"string"+            }+         }+      }+   },+   "paths":{+      "/todo/{id}":{+         "get":{+            "responses":{+               "404":{+                  "description":"id not found"+               },+               "200":{+                  "schema":{+                     "$ref":"#/definitions/Todo"+                  },+                  "description":""+               }+            },+            "produces":[+               "application/json"+            ],+            "parameters":[+               {+                  "required":true,+                  "in":"path",+                  "name":"id",+                  "type":"string"+               }+            ]+         }+      }+   }+}+```++## Try it out++All generated swagger specifications can be interactively viewed on [Swagger Editor](http://editor.swagger.io/).++Ready-to-use specification can be served as JSON and interactive API documentation+can be displayed using [Swagger UI](https://github.com/swagger-api/swagger-ui).++Many Swagger tools, including server and client code generation for many languages, can be found on+[Swagger's Tools and Integrations page](http://swagger.io/open-source-integrations/).++## FAQ+- Q: How is this project different from the `swagger` package on `hackage` ?+  - A: This package is based on the latest Swagger 2.0 API++## Contributing++We are happy to receive bug reports, fixes, documentation enhancements, and other improvements.++Please report bugs via the [github issue tracker](https://github.com/dmjio/servant-swagger/issues).+
+ example/File.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE DataKinds                  #-}+{-# LANGUAGE DeriveGeneric              #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE TypeOperators              #-}+module Main where++import Control.Lens+import Data.Aeson+import qualified Data.ByteString.Lazy.Char8 as BL8+import Data.Proxy+import Data.Swagger+import GHC.Generics+import Servant+import Servant.Swagger++-- Types+data Todo = Todo+  { created     :: Int+  , description :: String+  } deriving (Show, Eq, Generic)++instance ToJSON Todo++newtype TodoId = TodoId String deriving (FromText, Generic)++-- API+type API = "todo" :> Capture "id" TodoId :> Get '[JSON] Todo++-- Swagger Doc+swagDoc :: Swagger+swagDoc = toSwagger (Proxy :: Proxy API)+  & info.infoTitle   .~ "Todo API"+  & info.infoVersion .~ "1.0"+  & info.infoDescription ?~ "This is an API that tests servant-swagger support for a Todo"+  & info.infoLicense ?~ License "MIT" (Just (URL "http://mit.com"))++-- Documentation and annotations+instance ToParamSchema TodoId++instance ToSchema Todo where+  declareNamedSchema proxy = do+    (name, schema) <- genericDeclareNamedSchema defaultSchemaOptions proxy+    return (name, schema+      & schemaDescription ?~ "This is some real Todo right here"+      & schemaExample ?~ toJSON (Todo 100 "get milk"))++-- Main, create swaggger.json+main :: IO ()+main = BL8.writeFile "swagger.json" (encode swagDoc)+
+ example/Server.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE DataKinds                  #-}+{-# LANGUAGE DeriveGeneric              #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE TypeOperators              #-}+module Main where++import Control.Lens+import Control.Monad.Trans.Either+import Data.Aeson+import qualified Data.ByteString.Lazy.Char8 as BL8+import Data.Proxy+import Data.Swagger+import GHC.Generics+import Network.Wai.Handler.Warp+import Servant+import Servant.Swagger++-- Test API+type TodoAPI+    = "todo" :> Capture "id" TodoId :> Get '[JSON] Todo+ :<|> "todo" :> Capture "id" TodoId :> ReqBody '[JSON] Todo :> Put '[JSON] (Maybe Todo)+ :<|> "todo" :> "count" :> Get '[JSON] Todo+ :<|> "todo" :> ReqBody '[JSON] Todo :> Post '[JSON] Todo++type TestAPI = "todo" :> Capture "id" TodoId :> Get '[JSON] Todo++swagDoc :: Swagger+swagDoc = toSwagger (Proxy :: Proxy TestAPI)+  & info.infoTitle   .~ "Todo API"+  & info.infoVersion .~ "1.0"+  & info.infoDescription ?~ "This is an API that tests servant-swagger support for a Todo"+  & info.infoLicense ?~ License "MIT" (Just (URL "http://mit.com"))++type DocsAPI = Get '[JSON] Swagger++type API = DocsAPI :<|> TodoAPI++-- Data+data Todo = Todo { created :: Int, description :: String }+     deriving (Show, Eq, Generic)++instance ToJSON Todo+instance FromJSON Todo++newtype TodoId = TodoId String deriving (FromText, Generic)+newtype TodoCount = TodoCount Int deriving (FromText, Generic)+newtype Completed = Completed Bool deriving (FromText, Generic)++api :: Proxy TodoAPI+api = Proxy++-- Generate Swagger Docs+main :: IO ()+main = do+  putStrLn "Running on port 8000"+  run 8000 $ serve (Proxy :: Proxy API) endpoints+  where+    endpoints = swagHandler :<|> undefined+                  undefined :<|> undefined :<|> undefined+                  undefined :<|> undefined++swagHandler :: EitherT ServantErr IO Swagger+swagHandler = pure $ toSwagger api+  & info.infoTitle   .~ "Todo API"+  & info.infoVersion .~ "1.0"+  & info.infoDescription ?~ "This is an API that tests swagger integration"+  & info.infoLicense ?~ License "MIT" (Just (URL "http://mit.com"))++-- Instances+instance ToSchema Todo where+  declareNamedSchema proxy = do+    (name, schema) <- genericDeclareNamedSchema defaultSchemaOptions proxy+    return (name, schema+      & schemaDescription ?~ "This is some real Todo right here"+      & schemaExample ?~ toJSON (Todo 100 "get milk"))++instance ToParamSchema TodoId++instance ToParamSchema Completed+
+ example/example.cabal view
@@ -0,0 +1,42 @@+name:                example+version:             0.1.0.0+synopsis:            Example usage+description:         Example usage+license:             BSD3+license-file:        LICENSE+author:              David Johnson+maintainer:          djohnson.m@gmail.com+copyright:           David Johnson (c) 2015-2016+category:            Web+build-type:          Simple+cabal-version:       >=1.10++executable swagger-server+  main-is: Server.hs+  build-depends:+                    base+                , aeson+                , bytestring == 0.10.*+                , servant+                , either+                , servant-server+                , servant-swagger+                , swagger2+                , lens+                , wai+                , warp+  default-language: Haskell2010++executable swagger-file+  main-is: File.hs+  build-depends:+                    base+                , aeson+                , bytestring == 0.10.*+                , servant+                , swagger2+                , either+                , servant-server+                , servant-swagger+                , lens+  default-language: Haskell2010
servant-swagger.cabal view
@@ -1,7 +1,9 @@ name:                servant-swagger-version:             0.0.0.1-synopsis:            Swagger-description:         Swagger+version:             0.1+synopsis:            Generate Swagger specification for your servant API.+description:         Please see README.md+homepage:            https://github.com/dmjio/servant-swagger+bug-reports:         https://github.com/dmjio/servant-swagger/issues license:             BSD3 license-file:        LICENSE author:              David Johnson@@ -10,40 +12,48 @@ category:            Web build-type:          Simple cabal-version:       >=1.10-description:         This is an experimental release, this API is subject to change at any moment.+extra-source-files:+    README.md+  , example/*.hs+  , example/*.cabal  source-repository head   type:     git-  location: git://github.com/dmjio/servant-swagger.git+  location: https://github.com/dmjio/servant-swagger.git  library   ghc-options:         -Wall-  exposed-modules:     Servant.Swagger-  other-modules:       Servant.Swagger.Internal-  default-extensions:-             FlexibleContexts-           , DeriveGeneric-           , DeriveDataTypeable-           , GeneralizedNewtypeDeriving-           , RecordWildCards-           , FlexibleInstances-           , OverloadedLists-           , PolyKinds-           , OverloadedStrings-           , TypeFamilies-           , KindSignatures-           , TypeOperators-           , CPP-           , DataKinds+  exposed-modules:+    Servant.Swagger+    Servant.Swagger.Internal   hs-source-dirs:      src   build-depends:       aeson                      , base >=4.7 && <5                      , bytestring-                     , containers-                     , hashable+                     , http-media                      , lens-                     , text-                     , uuid                      , servant+                     , swagger2+                     , text                      , unordered-containers   default-language:    Haskell2010++test-suite spec+  ghc-options:      -Wall+  type:             exitcode-stdio-1.0+  hs-source-dirs:   test+  main-is:          Spec.hs+  build-depends:    base  == 4.*+                  , aeson+                  , aeson-qq+                  , hspec+                  , lens+                  , servant+                  , servant-swagger+                  , swagger2+                  , text+                  , time+  other-modules:+    Servant.SwaggerSpec+  default-language: Haskell2010+
src/Servant/Swagger.hs view
@@ -1,108 +1,14 @@-module Servant.Swagger -  (-  -- * Classes-    HasSwagger           (..)-  , ToSwaggerDescription (..)-  , ToHeader             (..)-  , ToSwaggerParamType   (..)-  , SwaggerParamType     (..)-  , ToSwaggerModel       (..)-  , ToHeaderDescription  (..)-  , ToModelExample       (..)-  -- * Types-  , APIDescription       (..)-  , Contact              (..)-  , ContactName          (..)-  , ContactURL           (..)-  , ContactEmail         (..)-  , TermsOfService       (..)-  , SwaggerAPI           (..)-  , SwaggerOperation     (..)-  , SwaggerRouteInfo     (..)-  , Operation            (..)-  , Code                 (..)-  , Verb                 (..)-  , PathSummary          (..)-  , SwaggerType          (..)-  , SwaggerModel         (..)-  , Info                 (..)-  , ModelName            (..)-  , ContentType          (..)-  , APIVersion           (..)-  , APITitle             (..)-  , APILicense           (..)-  , Scheme               (..)-  , Description          (..)-  , BasePath             (..)-  , Response             (..)-  , ModelSwag            (..)-  , SwaggerHeader        (..)-  , responseDescription-  , responseModelName-  , responseHeaders-  , responseIsArray-  , responseCode-  , defResponse-  , Tag                  (..)-  , TagName              (..)-  , TagDescription       (..)-  , tagName-  , tagDescription-  -- * Swaggadelic-  , swagger-  , emptyModel-  , swaggerPathInfo-  , emptyRouteDescription-  -- * Lenses-  , swagModelName-  , swagModelExample-  , swagProperties-  , swagModelRequired-  , swagDescription-  , swagRouteTags-  , swagRouteSummary-  , swagRouteResponses-  , swagRouteModels-  , PathDescription (..)-  , swagRouteDescription-  , OperationId (..)-  , swagRouteOperationId-  , defSwaggerInfo-  , createSwaggerJson-  , swaggerInfoTitle-  , swaggerVersion-  , swaggerAPIDescription-  , license-  , contact-  , termsOfService-  ) where--import Servant.Swagger.Internal-import Data.Proxy-import Data.Monoid-import Control.Lens--swagger-  :: HasSwagger swagger-  => Proxy swagger-  -> SwaggerRouteInfo swagger-  -> BasePath-  -> Info-  -> [Scheme]-  -> Maybe HostName-  -> [SecurityDefinition]-  -> SwaggerAPI-swagger proxy (SwaggerRouteInfo routeInfo) basePath info schemes hostName secDefs = do-  let result@SwagResult{..} = routeInfo <> toSwaggerDocs proxy defSwaggerRoute-  defSwaggerAPI info-     & swaggerPaths .~ _resultPaths-     & swaggerSchemes ?~ schemes-     & swaggerDefinitions .~ _resultModels-     & swaggerTags ?~ getAllTags result-     & swaggerBasePath ?~ basePath-     & swaggerHostName .~ hostName-     & swaggerSecurityDefintions ?~ secDefs+module Servant.Swagger (+  HasSwagger(..), +  addTag,+  subOperations,+  setResponse, +  ToResponseHeader(..),+  AllAccept,+  AllToResponseHeader,+) where +import Servant.Swagger.Internal 
src/Servant/Swagger/Internal.hs view
@@ -1,985 +1,362 @@-{-# LANGUAGE ScopedTypeVariables        #-}-{-# LANGUAGE DefaultSignatures          #-}-{-# LANGUAGE TemplateHaskell            #-}-{-# LANGUAGE FlexibleContexts           #-}-{-# LANGUAGE CPP                        #-}-{-# LANGUAGE DeriveGeneric              #-}-{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE RecordWildCards            #-}-{-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE OverloadedLists            #-}-{-# LANGUAGE PolyKinds                  #-}-{-# LANGUAGE OverloadedStrings          #-}-{-# LANGUAGE TypeFamilies               #-}-{-# LANGUAGE KindSignatures             #-}-{-# LANGUAGE TypeOperators              #-}-{-# LANGUAGE DataKinds                  #-}-{-# LANGUAGE ConstraintKinds            #-}-#if !MIN_VERSION_base(4,8,0)-{-# LANGUAGE OverlappingInstances       #-}-#endif--------------------------------------------------------------------------------module Servant.Swagger.Internal  where--------------------------------------------------------------------------------#if !MIN_VERSION_base(4,8,0)-import           Control.Applicative-#endif-import           Data.Text (Text)-import           Data.Aeson-import           Data.Aeson.Types ( typeMismatch )-import qualified Data.Set as S-import           Data.Hashable-import           Data.List-import           Data.Maybe-import           Data.Data-import qualified Data.ByteString.Lazy.Char8 as BL8-import qualified Data.ByteString.Char8 as B8-import           Data.Bool-import           GHC.Generics-import           Data.String-import           Control.Lens hiding ((.=))-import qualified Data.HashMap.Strict as HM-import           Data.Monoid-import qualified Data.Text as T-import qualified Data.Text.Lazy as L-import           GHC.TypeLits-import           Servant.API hiding (Header)-import qualified Servant.API.Header as H-import qualified Data.UUID as UUID---- | Helper to generate swagger.json file-createSwaggerJson :: SwaggerAPI -> IO ()-createSwaggerJson = BL8.writeFile "swagger.json" . encode---- | This is the root document object for the API specification.-data SwaggerAPI = SwaggerAPI {-     _swaggerInfo               :: Info -- ^ Required, provides metadata about the API-  ,  _swaggerPaths              :: HM.HashMap PathName SwaggerOperation -- ^ Required-  ,  _swaggerSchemes            :: Maybe [Scheme] -- ^ Schemes for this API (i.e HTTP/HTTPS) -  ,  _swaggerDefinitions        :: HM.HashMap ModelName SwaggerModel -- ^ -  ,  _swaggerTags               :: Maybe [Tag] -- ^ A list of tags that provide additional metadat-  ,  _swaggerBasePath           :: Maybe BasePath -- ^ The base path upon which this API is served -  ,  _swaggerHostName           :: Maybe HostName -- ^ Host name or IP -  ,  _swaggerSecurityDefintions :: Maybe [SecurityDefinition] -     -- ^ Security scheme definitions that can be used across the specification.-  ,  _swaggerExternalDocs       :: Maybe ExternalDocs -  } deriving Show---- | Smart Constructor for `SwaggerAPI`-defSwaggerAPI :: Info -> SwaggerAPI -defSwaggerAPI info = SwaggerAPI info mempty mempty mempty mempty mempty mempty mempty mempty---- | `ToJSON` for `SwaggerAPI`-instance ToJSON SwaggerAPI where-  toJSON SwaggerAPI{..} =-    object $ [-        "swagger"     .= ("2.0" :: Text)-      , "info"        .= _swaggerInfo-      , "paths"       .= do Object $ HM.fromList $ map f $ HM.toList _swaggerPaths-      , "definitions" .= do Object $ HM.fromList $ map g $ HM.toList _swaggerDefinitions-      ] ++-      [ "host" .= _swaggerHostName | isJust _swaggerHostName ] ++-      [ "schemes" .= _swaggerSchemes | isJust _swaggerSchemes ] ++-      [ "basePath" .= _swaggerBasePath | isJust _swaggerBasePath ] ++-      [ "externalDocs" .= _swaggerExternalDocs | isJust _swaggerExternalDocs ] ++-      [ "tags" .=  _swaggerTags | isJust _swaggerTags ]-    where-      f (PathName pathName, sp) = (T.toLower pathName, toJSON sp)-      g (ModelName modelName, model) = (modelName, toJSON model)--data ExternalDocs = ExternalDocs {-    _externalDescription :: Maybe ExternalDescription -- ^ Optional Description-  , _externalURL :: ExternalURL -- ^ Required URL that links supporting documentation-  } deriving (Show, Eq)--instance ToJSON ExternalDocs where-  toJSON ExternalDocs{..} =-    object $ [ "url" .= _externalURL ] ++-             [ "description" .=  _externalDescription-             | isJust _externalDescription-             ]--instance Monoid ExternalDocs where-  mempty = ExternalDocs mempty mempty-  (ExternalDocs a1 b1) `mappend` (ExternalDocs a2 b2)-    = ExternalDocs (a1 <> a2) (b1 <> b2)---- | External Description for External Documentation API-newtype ExternalDescription = ExternalDescription Text-  deriving (Show, Eq, Monoid, ToJSON)---- | External Description for External Documentation API-newtype ExternalURL = ExternalURL Text-  deriving (Show, Eq, Monoid, ToJSON)---- | Type used to accumulate information of a Servant path-data SwaggerRoute = SwaggerRoute {-    _routePathName    :: PathName -- ^ Accumulated `PathName`-  , _routeConsumes    :: [ContentType]  -- ^ Content Types a route consumes-  , _routeModels      :: HM.HashMap ModelName SwaggerModel  -- ^ Models present in route-  , _routeParams      :: [Param]  -- ^ Params present in route-  , _routeVerb        :: Verb  -- ^ Verb of route-  , _routePathSummary :: PathSummary -- ^ Summary of path-  , _routeResponses   :: HM.HashMap Text Response -- ^ Additional responses for a Route-  , _routeTags        :: [Tag]  -- ^ Tags present for this Route-  } deriving Show---- | Default Route used to build up-defSwaggerRoute :: SwaggerRoute-defSwaggerRoute = SwaggerRoute mempty [] [] [] Get mempty [] []---- | Default --- <http://swagger.io/specification/#contactObject contact>-defSwaggerInfo :: Info-defSwaggerInfo =-  Info (APITitle mempty)-    (APIVersion "2.0") (APIDescription mempty) Nothing Nothing Nothing---- | Contact name of `Contact` object-newtype ContactName = ContactName Text-  deriving (Show, Eq, ToJSON, FromJSON, Ord, Monoid)---- | Contact URL of `Contact` object-newtype ContactURL = ContactURL Text-  deriving (Show, Eq, ToJSON, FromJSON, Ord, Monoid)---- | Contact Email of `Contact` object-newtype ContactEmail = ContactEmail Text-  deriving (Show, Eq, ToJSON, FromJSON, Ord, Monoid)---- | Contact Object-data Contact = Contact {-    _contactName :: ContactName-  , _contactURL :: ContactURL-  , _contactEmail :: ContactEmail-  } deriving (Show, Eq, Ord)--instance Monoid Contact where-  mempty = Contact mempty mempty mempty-  (Contact a1 b1 c1) `mappend` (Contact a2 b2 c2) =-     Contact (a1 <> a2) (b1 <> b2) (c1 <> c2)---- | Contact Object-instance ToJSON Contact where-  toJSON Contact{..} =-    object [-        "name"  .= _contactName-      , "url"   .= _contactURL-      , "email" .= _contactEmail-      ]---- | Description of API-newtype APIDescription = APIDescription { _unApiDesc :: Text }-   deriving (Show, Eq, ToJSON, Monoid)---- | Terms of Service of API located in `Info`-newtype TermsOfService = TermsOfService Text-   deriving (Show, Eq, ToJSON, Monoid)---- | A Swagger metadata for a Servant header-data SwaggerHeader = SwaggerHeader {-    headerDescription :: Text -- ^ Header description-  , headerType :: SwaggerParamType  -- ^ Type of Header-  , headerName :: Text   -- ^ Name of Header-  } deriving (Show, Eq)---- | A container for the expected responses of an operation. -data Response = Response {-    _responseDescription :: Text -- ^ Description of Response-  , _responseModelName :: ModelName  -- ^ `Model` this Response returns-  , _responseHeaders :: HM.HashMap Text SwaggerHeader  -- ^ HashMap of headers-  , _responseIsArray :: Bool -- ^ Does the response return an Array?-  , _responseCode :: Code -- ^ Response code this route returns-  } deriving (Show, Eq)---- | Default Response for a Path-defResponse :: Response-defResponse = Response mempty (ModelName mempty) mempty False (Code 200)---- | Name of `Tag`, that can be applied to an operation-newtype TagName = TagName Text deriving (Show, Eq, Ord, ToJSON, FromJSON)---- | Description of `Tag`-newtype TagDescription = TagDescription Text deriving (Show, Eq, Ord, ToJSON, FromJSON)---- | Allows adding meta data to a single tag that is used by the Operation Object-data Tag = Tag {-    _tagName        :: TagName -- ^ Name of `Tag`-  , _tagDescription :: TagDescription  -- ^ Description of `Tag`-  } deriving (Show, Eq, Ord)---- | `ToJSON` `Tag` instance-instance ToJSON Tag where-  toJSON Tag{..} = object [ "name" .= _tagName, "description" .= _tagDescription ]---- | `FromJSON` `Tag` instance-instance FromJSON Tag where-  parseJSON (Object o) = Tag <$> o .: "name" <*> o .:  "description"-  parseJSON x = typeMismatch "Tag" x---- | A declaration of the security schemes available to be used in the specification-data SecurityDefinition =-    OAuthDef OAuth -- ^ OAuth -  | APIKeyDef APIKey -- ^ APIKey-  | BasicAuthDef BasicAuth  -- ^ BasicAuth-  deriving Show---- | Basic Authentication-data BasicAuth = BasicAuth deriving Show---- ^ OAuth Flow-data OAuthFlow = Implicit | Password | Application | AccessCode deriving (Show) --- ^ OAuth URL-data OAuthURL = OAuthURL deriving (Show) -data TokenURL = TokenURL deriving (Show) -data Scopes = Scopes deriving (Show) ---- | OAuth Authentication-data OAuth = OAuth {-    oauthDescription :: Maybe Description -- ^ Optional description for Swagger OAuth object-  , oauthFlow        :: OAuthFlow         -- ^ OAuth Flow-  , oauthURL         :: OAuthURL          -- ^ OAuth URL-  , oauthTokenURL    :: TokenURL          -- ^ Token URL-  , scopes           :: Scopes            -- ^ OAuth Scopes-  } deriving Show---- | API Key-newtype APIKeyName =-  APIKeyName Text deriving (Show, Eq)---- | API Location (i.e. is it located in a Query Param or a Header)-data APIKeyIn = APIKeyQueryParam-              | APIKeyHeader deriving (Show, Eq)---- | API Key Object-data APIKey = APIKey {-    apiKeyDescription :: Maybe Description -- ^ Optional `Description`-  , apiKeyName        :: APIKeyName  -- ^ Optional `Description`-  , apiKeyIn          :: APIKeyIn-  } deriving Show---- | API Key `ToJSON`-instance ToJSON APIKey where-  toJSON APIKey{..} =-    object [ "api_key" .= ([] :: [Int]) ]---- | HostName -newtype HostName = HostName Text-  deriving (Show, Eq, IsString, ToJSON, FromJSON, Monoid)---- | BasePath -newtype BasePath = BasePath Text-   deriving (Show, Eq, ToJSON, FromJSON, Monoid)---- | Info Objet -data Info = Info {-    _swaggerInfoTitle      :: APITitle -- ^ API Title-  , _swaggerVersion        :: APIVersion -- ^ API Version-  , _swaggerAPIDescription :: APIDescription -- ^ API Description-  , _license               :: Maybe APILicense -- ^ API Description-  , _contact               :: Maybe Contact-  , _termsOfService        :: Maybe TermsOfService-  } deriving (Show, Eq)--instance Monoid Info where-  mempty = Info mempty mempty mempty mempty mempty mempty -  (Info a1 b1 c1 d1 e1 f1) `mappend` (Info a2 b2 c2 d2 e2 f2)-    = Info (a1 <> a2) (b1 <> b2) (c1 <> c2) (d1 <> d2) (e1 <> e2) (f1 <> f2)--data APILicense = APILicense {-     _licenseName :: Text-  ,  _licenseUrl  :: Maybe Text-  } deriving (Show, Eq)--instance Monoid APILicense where-  mempty = APILicense mempty mempty-  (APILicense a1 b1) `mappend` (APILicense a2 b2) = APILicense (a1 <> a2) (b1 <> b2)--data SwaggerOperation = SwaggerOperation {-     _paths :: HM.HashMap Verb Operation-  } deriving Show--data SwagResult = SwagResult {-    _resultPaths  :: HM.HashMap PathName SwaggerOperation-  , _resultModels :: HM.HashMap ModelName SwaggerModel-  } deriving (Show)--data Verb = Post | Get | Put | Options | Head | Delete | Patch-  deriving (Show, Eq, Read, Generic)--newtype PathSummary = PathSummary Text-    deriving (Show, Eq, ToJSON, FromJSON, Monoid, IsString)--data Operation = Operation {-     _summary   :: PathSummary-   , _params    :: [Param]-   , _responses :: HM.HashMap Code Response-   , _produces  :: [ContentType]-   , _consumes  :: [ContentType]-   , _tags      :: [Tag]-   , _operationId :: Maybe OperationId-   , _description :: PathDescription-   , _deprecated :: Maybe Deprecated-  } deriving Show--instance Monoid Operation where-  mempty = Operation mempty mempty mempty mempty mempty mempty mempty mempty mempty-  (Operation a1 b1 c1 d1 e1 f1 g1 h1 i1) `mappend` -    (Operation a2 b2 c2 d2 e2 f2 g2 h2 i2) =-       Operation (a1 <> a2) (b1 <> b2) (c1 <> c2) (d1 <> d2) (e1 <> e2) (f1 <> f2) (g1 <> g2)-          (h1 <> h2) (i1 <> i2) --newtype Deprecated = Deprecated Bool deriving (Show, Eq, ToJSON)--instance Monoid Deprecated where-  mempty = Deprecated False-  (Deprecated False) `mappend` (Deprecated False) = Deprecated False-  _ `mappend` _ = Deprecated True--newtype OperationId = OperationId Text deriving (Show, Eq, ToJSON, Monoid)-newtype PathDescription = PathDescription Text deriving (Show, Eq, ToJSON, Monoid)--newtype Code = Code Int deriving (Show, Eq, Ord, ToJSON, Hashable, Num)--data SwaggerParamType =-    StringSwagParam-  | NumberSwagParam-  | IntegerSwagParam-  | BooleanSwagParam-  | ArraySwagParam -  | FileSwagParam-  deriving (Show, Eq)--data SwaggerType =-    IntegerSwag-  | LongSwag-  | FloatSwag-  | DoubleSwag-  | StringSwag-  | ByteSwag-  | BinarySwag-  | BooleanSwag-  | DateSwag-  | DateTimeSwag-  | PasswordSwag-  | Model ModelSwag-  deriving (Show, Eq)--data ModelSwag = ModelSwag {-    modelSwagName :: ModelName-  , modelSwagIsArray :: Bool-  } deriving (Show, Eq)--data ContentType = JSON | HTML | XML | FormUrlEncoded | PlainText | OctetStream-  deriving (Show, Eq)--data In = PathUrl | Query | Header | FormData | Body deriving Show-data Scheme = Http | Https | Ws | Wss deriving Show--data Param = Param {-    _in               :: In-  , _name             :: Text-  , _type             :: Maybe SwaggerParamType-  , _items            :: Maybe ItemObject-  , _paramDescription :: Text-  , _allowEmptyValue  :: Bool-  , _required         :: Bool-  , _default          :: Maybe Value-  , _isArray          :: Bool-  } deriving Show--data ItemObject = ItemObject {-     _itemsType :: SwaggerParamType-  } deriving Show--newtype APIVersion = APIVersion Text deriving (Show, Eq, ToJSON, Monoid)-newtype APITitle = APITitle Text deriving (Show, Eq, ToJSON, Monoid)-newtype PathName = PathName { unPathName :: Text }-  deriving (Show, Eq, Hashable, Monoid)--newtype ModelName = ModelName { unModelName :: Text }-   deriving (Show, Eq, Hashable, Monoid)--newtype Description =-  Description { unDescription :: Text } deriving (Show, Eq, ToJSON, Monoid)--data SwaggerModel = SwaggerModel {-     _swagModelName    :: ModelName-   , _swagProperties   :: [(Text, SwaggerType)]-   , _swagDescription  :: Maybe Description-   , _swagModelExample :: Maybe Value-   , _swagModelRequired :: [Text]-   } deriving (Show, Eq)--emptyModel :: SwaggerModel-emptyModel = SwaggerModel (ModelName mempty) mempty mempty Nothing mempty--data SwaggerRouteDescription = SwaggerRouteDescription {-    _swagRouteTags      :: [Tag]       -- ^ Tags-  , _swagRouteSummary   :: PathSummary -- ^ Description of this endpoint-  , _swagRouteResponses :: HM.HashMap Code Response  -- ^ Additional responses for this endpoint-  , _swagRouteModels    :: HM.HashMap ModelName SwaggerModel-  , _swagRouteOperationId :: Maybe OperationId-  , _swagRouteDescription :: PathDescription-  } deriving Show--emptyRouteDescription :: SwaggerRouteDescription-emptyRouteDescription = SwaggerRouteDescription mempty mempty mempty mempty mempty mempty--$(makeLenses ''SwaggerModel)-$(makeLenses ''ExternalDocs)-$(makeLenses ''SwaggerRouteDescription)-$(makeLenses ''SwagResult)-$(makeLenses ''SwaggerRoute)-$(makeLenses ''SwaggerAPI)-$(makeLenses ''Info)-$(makeLenses ''Contact)-$(makeLenses ''APILicense)-$(makeLenses ''Operation)-$(makeLenses ''Tag)-$(makeLenses ''Response)--defExternalDocs :: ExternalURL -> ExternalDocs-defExternalDocs url = mempty & externalURL .~ url----------------------------------------------------------------------------------- | Swaggin'-class HasSwagger h where-  toSwaggerDocs :: Proxy h -> SwaggerRoute -> SwagResult--------------------------------------------------------------------------------class ToSwaggerDescription a where toSwaggerDescription :: Proxy a -> Text-class ToHeader a where toHeader :: Proxy a -> SwaggerHeader-class ToResponseHeaders as where toResponseHeaders :: Proxy as -> HM.HashMap Text SwaggerHeader-instance ToResponseHeaders '[] where toResponseHeaders Proxy = []--instance (ToHeader x, ToResponseHeaders xs) => ToResponseHeaders (x ': xs)  where-  toResponseHeaders Proxy = HM.union header' (toResponseHeaders (Proxy :: Proxy xs))-    where-      header' = transHeader (toHeader (Proxy :: Proxy x))--transHeader :: SwaggerHeader -> HM.HashMap Text SwaggerHeader-transHeader r@SwaggerHeader{..} = HM.fromList [(headerName, r)]---------------------------------------------------------------------------------instance (HasSwagger rest, KnownSymbol sym) => HasSwagger (sym :> rest) where-  toSwaggerDocs Proxy swagRoute =-     toSwaggerDocs (Proxy :: Proxy rest) $ swagRoute & routePathName %~ flip (<>) path-   where path = PathName $ "/" <> T.pack (symbolVal (Proxy :: Proxy sym))--instance (HasSwagger left, HasSwagger right) => HasSwagger (left :<|> right) where-  toSwaggerDocs Proxy swagRoute =-    let swagLeft = toSwaggerDocs (Proxy :: Proxy left) swagRoute-        swagRight = toSwaggerDocs (Proxy :: Proxy right) swagRoute-        paths  = HM.unionWith f (swagLeft ^. resultPaths) (swagRight ^. resultPaths)-        models = HM.union (swagLeft ^. resultModels) (swagRight ^. resultModels)-    in SwagResult paths models-      where f (SwaggerOperation l) (SwaggerOperation r) = SwaggerOperation (HM.union l r)--class ToSwaggerParamType a where toSwaggerParamType :: Proxy a -> SwaggerParamType-instance ToSwaggerParamType Int where toSwaggerParamType = const IntegerSwagParam-instance ToSwaggerParamType Integer where toSwaggerParamType = const IntegerSwagParam-instance ToSwaggerParamType UUID.UUID where toSwaggerParamType = const StringSwagParam-instance ToSwaggerParamType String where toSwaggerParamType = const StringSwagParam-instance ToSwaggerParamType Text where toSwaggerParamType = const StringSwagParam-instance ToSwaggerParamType L.Text where toSwaggerParamType = const StringSwagParam-instance ToSwaggerParamType BL8.ByteString where toSwaggerParamType = const StringSwagParam-instance ToSwaggerParamType B8.ByteString where toSwaggerParamType = const StringSwagParam-instance ToSwaggerParamType Double where toSwaggerParamType = const NumberSwagParam-instance ToSwaggerParamType Float where toSwaggerParamType = const NumberSwagParam-instance ToSwaggerParamType Bool where toSwaggerParamType Proxy = BooleanSwagParam--instance-  ToSwaggerParamType a => ToSwaggerParamType [a] where-    toSwaggerParamType _ = ArraySwagParam--class ToHeaderDescription a where-  toHeaderDescription :: Proxy a -> Text--instance ( ToSwaggerParamType headerType-         , KnownSymbol headerName-         , ToHeaderDescription headerName-         ) => ToHeader (H.Header headerName headerType) where-  toHeader Proxy = SwaggerHeader desc ht hn-      where-        desc = T.pack . symbolVal $ (Proxy :: Proxy headerName)-        hn = T.pack . symbolVal $ (Proxy :: Proxy headerName)-        ht = toSwaggerParamType (Proxy :: Proxy headerType)--class SwaggerAccept a where toSwaggerAccept :: Proxy a -> ContentType-instance SwaggerAccept JSON where toSwaggerAccept Proxy = JSON-instance SwaggerAccept HTML where toSwaggerAccept Proxy = HTML-instance SwaggerAccept XML where toSwaggerAccept Proxy = XML-instance SwaggerAccept FormUrlEncoded where toSwaggerAccept Proxy = FormUrlEncoded-instance SwaggerAccept PlainText where toSwaggerAccept Proxy = PlainText-instance SwaggerAccept OctetStream where toSwaggerAccept Proxy = OctetStream--------------------------------------------------------------------------------class SwaggerAcceptTypes (xs :: [*]) where toSwaggerAcceptTypes :: Proxy xs -> [ContentType]-instance SwaggerAcceptTypes '[] where toSwaggerAcceptTypes Proxy = []-instance (SwaggerAccept x, SwaggerAcceptTypes xs) => SwaggerAcceptTypes (x ': xs) where-  toSwaggerAcceptTypes Proxy =-    toSwaggerAccept (Proxy :: Proxy x) : toSwaggerAcceptTypes (Proxy :: Proxy xs)--------------------------------------------------------------------------------class ToVerb a where toVerb :: Proxy a -> Verb-instance ToVerb Get where toVerb Proxy   = Get-instance ToVerb Put where toVerb Proxy   = Put-instance ToVerb Patch where toVerb Proxy = Patch-instance ToVerb Post where toVerb Proxy  = Post-instance ToVerb Delete where toVerb Proxy  = Delete-instance ToVerb Options where toVerb Proxy  = Options--class ToSwaggerModel a where-  toSwagModel  :: Proxy a -> SwaggerModel-  toSwagModelName :: Proxy a -> ModelName-  toSwagModelName = _swagModelName . toSwagModel-  default toSwagModel :: (Generic a, GToSwaggerModel (Rep a)) => Proxy a -> SwaggerModel-  toSwagModel = undefined--class GToSwaggerModel a where-  gToSwaggerModel :: Proxy a -> f a -> SwaggerModel --instance ToSwaggerModel () where-  toSwagModel Proxy = emptyModel--instance ToSwaggerModel SwaggerAPI where-  toSwagModel Proxy = emptyModel--instance-#if MIN_VERSION_base(4,8,0)-  {-# OVERLAPPABLe #-}-#endif-  (ToSwaggerModel returnType, ToVerb verb, SwaggerAcceptTypes xs)-      => HasSwagger (verb xs returnType) where-  toSwaggerDocs Proxy swagRoute =-    let swagPath = SwaggerOperation [(toVerb (Proxy :: Proxy verb), path)]-        path = mempty & summary .~ swagRoute ^. routePathSummary-                      & params .~ swagRoute ^. routeParams-                      & responses .~ [(_responseCode response, response)]-                      & produces .~ toSwaggerAcceptTypes (Proxy :: Proxy xs)-                      & consumes .~ swagRoute ^. routeConsumes-    in SwagResult [(pathName, swagPath)] newModels-      where-        response = Response "OK" (swagModel ^. swagModelName) [] False 200-        pathName | swagRoute ^. routePathName == PathName "" = PathName "/"-                 | otherwise = swagRoute ^. routePathName-        swagModel@SwaggerModel{..} = toSwagModel (Proxy :: Proxy returnType)-        newModels = bool (swagRoute ^. routeModels)-                         (HM.insert _swagModelName swagModel (swagRoute ^. routeModels))-                         (swagModel /= emptyModel)--instance-#if MIN_VERSION_base(4,8,0)-  {-# OVERLAPPABLe #-}-#endif-  (ToSwaggerModel returnType, ToVerb verb, SwaggerAcceptTypes xs) -      => HasSwagger (verb xs [returnType]) where-  toSwaggerDocs Proxy swagRoute =-    let swagPath = SwaggerOperation [(toVerb (Proxy :: Proxy verb), path)]-        path = mempty & summary .~ swagRoute ^. routePathSummary-                      & params .~ swagRoute ^. routeParams-                      & responses .~ [(_responseCode response, response)]-                      & produces .~ toSwaggerAcceptTypes (Proxy :: Proxy xs)-                      & consumes .~ swagRoute ^. routeConsumes-    in SwagResult [(pathName, swagPath)] newModels-      where-        response = Response "OK" (swagModel ^. swagModelName) [] False 200-        pathName | swagRoute ^. routePathName == PathName "" = PathName "/"-                 | otherwise = swagRoute ^. routePathName-        swagModel@SwaggerModel{..} = toSwagModel (Proxy :: Proxy returnType)-        newModels = bool (swagRoute ^. routeModels)-                         (HM.insert _swagModelName swagModel (swagRoute ^. routeModels))-                         (swagModel /= emptyModel)--instance-#if MIN_VERSION_base(4,8,0)-   {-# OVERLAPPING #-}-#endif- (ToSwaggerModel returnType, ToVerb verb, SwaggerAcceptTypes xs, ToResponseHeaders ls)-    => HasSwagger (verb xs (Headers ls [returnType])) where-  toSwaggerDocs Proxy swagRoute =-    let swagPath = SwaggerOperation [(toVerb (Proxy :: Proxy verb), path)]-        path = mempty & summary .~ swagRoute ^. routePathSummary-                      & params .~ swagRoute ^. routeParams-                      & responses .~ [(_responseCode response, response)]-                      & produces .~ toSwaggerAcceptTypes (Proxy :: Proxy xs)-                      & consumes .~ swagRoute ^. routeConsumes-    in SwagResult [(swagRoute ^. routePathName, swagPath)] newModels-      where-        response = Response "OK" (swagModel ^. swagModelName)-                     (toResponseHeaders (Proxy :: Proxy ls)) True 200-        swagModel@SwaggerModel{..} = toSwagModel (Proxy :: Proxy returnType)-        newModels = bool (swagRoute ^. routeModels)-                         (HM.insert _swagModelName swagModel (swagRoute ^. routeModels))-                         (swagModel /= emptyModel)--instance-#if MIN_VERSION_base(4,8,0)-   {-# OVERLAPPING #-}-#endif- (ToSwaggerModel returnType, ToVerb verb, SwaggerAcceptTypes xs, ToResponseHeaders ls)-    => HasSwagger (verb xs (Headers ls returnType)) where-  toSwaggerDocs Proxy swagRoute =-    let swagPath = SwaggerOperation [(toVerb (Proxy :: Proxy verb), path)]-        path = mempty & summary .~ swagRoute ^. routePathSummary-                      & params .~ swagRoute ^. routeParams-                      & responses .~ [(_responseCode response, response)]-                      & produces .~ toSwaggerAcceptTypes (Proxy :: Proxy xs)-                      & consumes .~ swagRoute ^. routeConsumes-    in SwagResult [(swagRoute ^. routePathName, swagPath)] newModels-      where-        response = Response "OK" (swagModel ^. swagModelName) rspHeaders False 200-        swagModel@SwaggerModel{..} = toSwagModel (Proxy :: Proxy returnType)-        rspHeaders = (toResponseHeaders (Proxy :: Proxy ls))-        newModels = bool (swagRoute ^. routeModels)-                         (HM.insert _swagModelName swagModel (swagRoute ^. routeModels))-                         (swagModel /= emptyModel)--instance (ToSwaggerDescription typ, ToSwaggerParamType typ, KnownSymbol sym, HasSwagger rest) =>-  HasSwagger (Capture sym typ :> rest) where-    toSwaggerDocs Proxy swagRoute = toSwaggerDocs (Proxy :: Proxy rest) newSwaggerRoute-      where-        pName = T.pack $ symbolVal (Proxy :: Proxy sym)-        newPath = PathName $ mconcat ["/{",pName,"}"]-        newParam = Param PathUrl pName-                     (Just $ toSwaggerParamType (Proxy :: Proxy typ)) Nothing-                       (toSwaggerDescription (Proxy :: Proxy typ)) True True Nothing False-        newSwaggerRoute = swagRoute & routePathName %~ flip (<>) newPath-                                    & routeParams %~ (:) newParam--instance (ToSwaggerDescription typ, ToSwaggerParamType typ, KnownSymbol sym, HasSwagger rest) =>-  HasSwagger (QueryParam sym typ :> rest) where-    toSwaggerDocs Proxy swagRoute = toSwaggerDocs (Proxy :: Proxy rest) newSwaggerRoute-      where-        pName = T.pack $ symbolVal (Proxy :: Proxy sym)-        newParam = Param Query pName-                     (Just $ toSwaggerParamType (Proxy :: Proxy typ)) Nothing-                       (toSwaggerDescription (Proxy :: Proxy typ)) True False Nothing False-        newSwaggerRoute = swagRoute & routeParams %~ (:) newParam--instance (ToSwaggerDescription typ, ToSwaggerParamType typ, KnownSymbol sym, HasSwagger rest) =>-  HasSwagger (QueryParams sym typ :> rest) where-    toSwaggerDocs Proxy swagRoute = toSwaggerDocs (Proxy :: Proxy rest) newSwaggerRoute-      where-        ptyp = toSwaggerParamType (Proxy :: Proxy typ)-        pName = T.pack $ symbolVal (Proxy :: Proxy sym)-        newParam = Param Query pName-                     (Just ArraySwagParam) (Just $ ItemObject ptyp)-                       (toSwaggerDescription (Proxy :: Proxy typ)) True False Nothing True-        newSwaggerRoute = swagRoute & routeParams %~ (:) newParam----------------------------------------------------------------------------------- | Query Flag-instance (ToSwaggerDescription sym, KnownSymbol sym, HasSwagger rest) =>-  HasSwagger (QueryFlag sym :> rest) where-    toSwaggerDocs Proxy swagRoute = toSwaggerDocs (Proxy :: Proxy rest) newSwaggerRoute-      where-        pName = T.pack $ symbolVal (Proxy :: Proxy sym)-        newParam = Param Query pName-                     (Just StringSwagParam) Nothing-                       (toSwaggerDescription (Proxy :: Proxy sym)) True False Nothing False-        newSwaggerRoute = swagRoute & routeParams %~ (:) newParam----------------------------------------------------------------------------------- | Raw holds no verb / body information-instance HasSwagger Raw where-  toSwaggerDocs Proxy swagRoute =-    SwagResult [(swagRoute ^. routePathName, mempty)] []----------------------------------------------------------------------------------- | Swagger doesn't support Raw, bypass-instance HasSwagger rest => HasSwagger (MatrixParam typ :> rest) where-    toSwaggerDocs Proxy swagRoute = toSwaggerDocs (Proxy :: Proxy rest) swagRoute----------------------------------------------------------------------------------- | Swagger doesn't support matrix flags, bypass-instance (ToSwaggerDescription typ, ToSwaggerParamType typ, HasSwagger rest) =>-  HasSwagger (MatrixFlag typ :> rest) where-    toSwaggerDocs Proxy swagRoute = toSwaggerDocs (Proxy :: Proxy rest) swagRoute----------------------------------------------------------------------------------- | Swagger Header-instance (KnownSymbol sym, ToSwaggerDescription typ, ToSwaggerParamType typ, HasSwagger rest) =>-  HasSwagger (H.Header sym typ :> rest) where-    toSwaggerDocs Proxy swagRoute = toSwaggerDocs (Proxy :: Proxy rest) newSwaggerRoute-      where-        newSwaggerRoute = swagRoute & routeParams %~ (:) newParams-        pName = T.pack $ symbolVal (Proxy :: Proxy sym)-        pDesc = toSwaggerDescription (Proxy :: Proxy typ)-        typ = toSwaggerParamType (Proxy :: Proxy typ)-        newParams = Param Header pName (Just typ)-                       Nothing pDesc False True Nothing False----------------------------------------------------------------------------------- | ReqBody Object-instance-#if MIN_VERSION_base(4,8,0)-  {-# OVERLAPPABLe #-}-#endif-  (SwaggerAcceptTypes ctypes, ToSwaggerModel model, HasSwagger rest) =>-  HasSwagger (ReqBody ctypes model :> rest) where-    toSwaggerDocs Proxy swagRoute = toSwaggerDocs (Proxy :: Proxy rest) newSwaggerRoute-      where-         swagModel@SwaggerModel {..} = toSwagModel (Proxy :: Proxy model)-         newSwaggerRoute =-           swagRoute & routeModels %~ model-                     & routeParams %~ (++) newParam-                     & routeConsumes %~ (++) (toSwaggerAcceptTypes (Proxy :: Proxy ctypes))-         model | swagModel == emptyModel = (<> mempty)-               | otherwise = HM.insert _swagModelName (toSwagModel (Proxy :: Proxy model))-         newParam =-            case _swagModelName of-              (ModelName "") -> []-              name -> [ Param Body (unModelName name) Nothing Nothing-                (fromMaybe mempty (unDescription <$> _swagDescription)) True False Nothing False]----------------------------------------------------------------------------------- | ReqBody Array-instance-#if MIN_VERSION_base(4,8,0)-  {-# OVERLAPPING #-}-#endif-  (SwaggerAcceptTypes ctypes, ToSwaggerModel model, HasSwagger rest) =>-  HasSwagger (ReqBody ctypes [model] :> rest) where-    toSwaggerDocs Proxy swagRoute = toSwaggerDocs (Proxy :: Proxy rest) newSwaggerRoute-      where-         swagModel@SwaggerModel {..} = toSwagModel (Proxy :: Proxy model)-         newSwaggerRoute =-           swagRoute & routeModels %~ model-                     & routeParams %~ (++) newParam-                     & routeConsumes %~ (++) (toSwaggerAcceptTypes (Proxy :: Proxy ctypes))-         model | swagModel == emptyModel = (<> mempty)-               | otherwise = HM.insert _swagModelName (toSwagModel (Proxy :: Proxy model))-         newParam =-            case _swagModelName of-              (ModelName "") -> []-              name -> [ Param Body (unModelName name) Nothing Nothing-                (fromMaybe mempty (unDescription <$> _swagDescription)) True False Nothing True]--class ToModelExample model where toExample :: Proxy model -> Maybe Value--instance ToJSON SwaggerHeader where-  toJSON SwaggerHeader{..} = -    object [-         "type" .= headerType-      ,  "description" .= headerDescription-      ]--instance Monoid SwaggerOperation where-  mempty = SwaggerOperation HM.empty-  SwaggerOperation a `mappend` SwaggerOperation b =-    SwaggerOperation ( a <> b )--instance ToJSON APILicense where-  toJSON APILicense{..} =-    object [ "name" .= _licenseName-           , "url"  .= _licenseUrl-           ]--instance Hashable Verb where hash = hash . show--instance ToJSON SwaggerParamType where-  toJSON StringSwagParam = String "string"-  toJSON NumberSwagParam = String "number"-  toJSON IntegerSwagParam = String "integer"-  toJSON BooleanSwagParam = String "boolean"-  toJSON ArraySwagParam   = String "array"-  toJSON FileSwagParam = String "file"--instance ToJSON SwaggerType where-  toJSON x =-    let f typ format = object $ [ "type" .= (typ :: Text) ] ++-               if isJust format-                 then [ "format" .= ((fromJust format) :: Text) ]-                 else []-    in case x of-      IntegerSwag -> f "integer" (Just "int32")-      LongSwag -> f "integer" (Just "int64")-      FloatSwag -> f "number" (Just "float")-      DoubleSwag -> f "number" (Just "double")-      StringSwag -> f "string" Nothing-      ByteSwag -> f "string" (Just "byte")-      BinarySwag -> f "string" (Just "binary")-      BooleanSwag -> f "boolean" Nothing-      DateSwag -> f "string" (Just "date")-      DateTimeSwag -> f "string" (Just "date-time")-      PasswordSwag -> f "string" (Just "password")-      Model ModelSwag{..} -> -         case modelSwagIsArray of-              True ->-                object [ "type" .= ("array" :: Text)-                       , "items" .= object [-                            "$ref" .= ("#/definitions/" <> unModelName modelSwagName)-                             ]-                          ]-              False ->-                object [-                    "$ref".= ("#/definitions/"<> unModelName modelSwagName)-                  ]--instance ToJSON ContentType where-  toJSON JSON        = String "application/json"-  toJSON XML         = String "application/xml"-  toJSON FormUrlEncoded = String "application/x-www-form-urlencoded"-  toJSON HTML        = String "text/html"-  toJSON PlainText   = String "text/plain; charset=utf-8"-  toJSON OctetStream = String "application/octet-stream"--instance ToJSON Scheme where-  toJSON Http  = String "http"-  toJSON Https = String "https"-  toJSON Ws    = String "ws"-  toJSON Wss   = String "wss"--instance ToJSON In where-  toJSON PathUrl  = "path"-  toJSON Query    = "query"-  toJSON Body     = "body"-  toJSON Header   = "header"-  toJSON FormData = "formData"--instance ToJSON PathName where-  toJSON (PathName x) = String (T.toLower x)--instance ToJSON SwaggerModel where-  toJSON SwaggerModel{..} =-    object $ [-        "type" .= ("object" :: Text)-      , "properties" .= HM.fromList _swagProperties-      ] ++ maybeExample ++ maybeDescription ++ requiredList-    where-      requiredList = [ "required" .= _swagModelRequired | not (null _swagModelRequired) ]-      maybeDescription = maybe [] (\(Description x) -> [ "description" .= x ]) _swagDescription-      maybeExample = maybe [] (\x -> [ "example" .= x ]) _swagModelExample--setPath :: BasePath -> BasePath-setPath (BasePath "") = BasePath "/"-setPath (BasePath x) = BasePath x---instance ToJSON SwaggerOperation where-  toJSON (SwaggerOperation paths) =-     Object . HM.fromList . map f . HM.toList $ paths-    where-      f (verb, sp) = (T.toLower $ toTxt verb, toJSON sp)--instance ToJSON Operation where-  toJSON Operation {..} =-    object $ [ "parameters"  .= _params-             , "responses"   .= do Object . HM.fromList . map f . HM.toList $ _responses-             , "produces"    .= _produces-             , "consumes"    .= _consumes-             , "summary"     .= _summary-             , "tags"        .=  map _tagName _tags-             , "description" .= _description-             ] ++ [ "deprecated" .= _deprecated | isJust _deprecated ]-               ++ [ "operationId" .= _operationId | isJust _operationId ]-    where f (Code x, resp) = (toTxt x, toJSON resp)--instance ToJSON Response where-  toJSON Response {..} = object $ [-      "description" .= _responseDescription-    , "headers" .= _responseHeaders-    ] ++ maybeModelName-    where-      maybeModelName =-        case _responseModelName of-          (ModelName "") -> []-          (ModelName name) ->-            case _responseIsArray of-              True -> [ "schema" .= object [-                           "type" .= ("array" :: Text)-                           , "items" .= object [-                              "$ref" .= ("#/definitions/" <> name) -                       ]]]-              False -> ["schema".=object["$ref".=("#/definitions/"<> name)]]--instance ToJSON Param where-  toJSON Param{..} = -    object $ [-        "in"          .= _in-      , "name"        .= _name-      , "description" .= _paramDescription-      , "required"    .= _required-      ]  ++ maybeSchema ++ [ "type" .= _type | isJust _type ]-    where-      maybeSchema =-        case _in of-          Body -> [ "schema" .=-                      case _isArray of-                        False ->-                         object [ "$ref" .= ("#/definitions/" <> _name) ]-                        True ->-                          object [-                              "type" .= ("array" :: Text)-                             , "items" .= object [-                                 "$ref" .= ("#/definitions/" <> _name )-                               ]-                             ]-                         ]-          _ -> []--instance ToSwaggerModel a => ToSwaggerModel (Maybe a) where-  toSwagModel _ = toSwagModel (Proxy :: Proxy a)--instance ToJSON Info where-  toJSON Info{..} =-    object $ [-        "title"   .= _swaggerInfoTitle-      , "version" .= _swaggerVersion-      , "description" .= _swaggerAPIDescription-      ] ++ [ "license" .=  _license | isJust _license ]-        ++ [ "contact" .=  _contact | isJust _contact ]-        ++ [ "termsOfService" .=  _termsOfService | isJust _termsOfService ]--toTxt :: Show a => a -> Text-toTxt = T.pack . show--newtype SwaggerRouteInfo a = SwaggerRouteInfo SwagResult -- deriving Monoid--instance Monoid (SwaggerRouteInfo a) where-  mempty = SwaggerRouteInfo mempty-  SwaggerRouteInfo s1 `mappend` SwaggerRouteInfo s2-    = SwaggerRouteInfo (s1 `mappend` s2)--instance Monoid SwagResult where-  mempty = SwagResult mempty mempty-  SwagResult x1 y1 `mappend` SwagResult x2 y2-    = SwagResult (HM.unionWith mergePaths x1 x2) (HM.union y1 y2)-      where-        mergePaths (SwaggerOperation l) (SwaggerOperation r) = SwaggerOperation (HM.unionWith g l r)-        g p1 p2 =-          p1 & summary %~ (<>) (p2 ^. summary)-             & responses %~ HM.union (p2 ^. responses)-             & tags %~ (++) (p2 ^. tags)-             & operationId .~ p1 ^. operationId <> p2 ^. operationId-             & description .~ p1 ^. description <> p2 ^. description--swaggerPathInfo-  :: ( IsElem endpoint layout, HasLink endpoint, HasSwagger endpoint, HasSwagger layout )-  => Proxy endpoint-  -> Proxy layout-  -> SwaggerRouteDescription-  -> SwaggerRouteInfo layout-swaggerPathInfo pEndpoint pLayout SwaggerRouteDescription{..} = swagResult-  where-    f [(pName, SwaggerOperation swagPath)] =-        [(pName, SwaggerOperation $ HM.fromList . g . HM.toList $ swagPath)]-    f _ = error "Route non-existant, impossible" -    g [(verb, path)] = [(verb, newPath path)] -    g _ = error "Route non-existant, impossible" -    newPath p = p & summary .~ _swagRouteSummary-                  & operationId .~  _swagRouteOperationId-                  & description .~  _swagRouteDescription-                  & responses %~ HM.union _swagRouteResponses-                  & tags %~ (++) _swagRouteTags-    swagResult =-      let finalDocs = toSwaggerDocs pLayout defSwaggerRoute-          SwagResult paths models = toSwaggerDocs pEndpoint defSwaggerRoute-          newModels = _swagRouteModels `HM.union` models -          newPaths = HM.fromList . f . HM.toList $ paths-          pathDocs = SwagResult newPaths newModels-      in SwaggerRouteInfo (finalDocs <> pathDocs)--getAllTags :: SwagResult -> [Tag]-getAllTags (SwagResult paths _) =-    S.toList . S.fromList . _tags =<< HM.elems =<< _paths <$> HM.elems paths+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+module Servant.Swagger.Internal where++import Control.Arrow (first)+import Control.Lens+import Data.Aeson+import Data.Data.Lens (template)+import Data.HashMap.Strict (HashMap)+import qualified Data.HashMap.Strict as HashMap+import Data.List (dropWhileEnd)+import Data.Monoid+import Data.Proxy+import qualified Data.Swagger as Swagger+import Data.Swagger hiding (Header)+import Data.Swagger.Declare+import Data.Text (Text)+import qualified Data.Text as Text+import GHC.TypeLits+import GHC.Exts+import Network.HTTP.Media (MediaType)+import Servant.API++class HasSwagger api where+  toSwagger :: Proxy api -> Swagger++instance HasSwagger Raw where+  toSwagger _ = mempty & paths.pathsMap.at "/" ?~ mempty++-- | All operations of sub API.+subOperations :: forall sub api. (IsSubAPI sub api, HasSwagger sub) =>+  Proxy sub -> Proxy api -> Traversal' Swagger Operation+subOperations sub _ = paths.pathsMap.itraversed.indices (`elem` ps).template+  where+    ps = toSwagger sub ^. paths.pathsMap.to HashMap.keys++-- | Tag an operation.+addTag :: TagName -> Operation -> Operation+addTag tag = operationTags %~ (tag:)++-- | Set a response for an operation.+setResponse :: HttpStatusCode -> Response -> Operation -> Operation+setResponse code res = operationResponses.responsesResponses.at code ?~ Inline res++(</>) :: FilePath -> FilePath -> FilePath+x </> y = case trim y of+  "" -> "/" <> trim x+  y' -> "/" <> trim x <> "/" <> y'+  where+    trim = dropWhile (== '/') . dropWhileEnd (== '/')++mkEndpoint :: forall a cs hs proxy _verb. (ToSchema a, AllAccept cs, AllToResponseHeader hs)+  => FilePath+  -> Lens' PathItem (Maybe Operation)+  -> HttpStatusCode+  -> proxy (_verb cs (Headers hs a))+  -> Swagger+mkEndpoint path verb code proxy+  = mkEndpointWithSchemaRef (Just ref) path verb code proxy+      & definitions .~ defs+  where+    (defs, ref) = runDeclare (declareSchemaRef (Proxy :: Proxy a)) mempty++noContentEndpoint :: forall cs proxy verb. (AllAccept cs)+  => FilePath+  -> Lens' PathItem (Maybe Operation)+  -> proxy (verb cs ())+  -> Swagger+noContentEndpoint path verb _ = mkEndpointWithSchemaRef Nothing path verb 204 (Proxy :: Proxy (verb cs (Headers '[] ())))++mkEndpointWithSchemaRef :: forall cs hs proxy verb a. (AllAccept cs, AllToResponseHeader hs)+  => Maybe (Referenced Schema)+  -> FilePath+  -> Lens' PathItem (Maybe Operation)+  -> HttpStatusCode+  -> proxy (verb cs (Headers hs a))+  -> Swagger+mkEndpointWithSchemaRef mref path verb code _ = mempty+  & paths.pathsMap.at path ?~+    (mempty & verb ?~ (mempty+      & operationProduces ?~ MimeList (allContentType (Proxy :: Proxy cs))+      & operationResponses .~ (mempty+        & responsesResponses . at code ?~ Inline (mempty+            & responseSchema  .~ mref+            & responseHeaders .~ toAllResponseHeaders (Proxy :: Proxy hs)))))++-- | Prepend path to all API endpoints.+prependPath :: FilePath -> Swagger -> Swagger+prependPath path spec = spec & paths.pathsMap %~ f+  where+    f = HashMap.fromList . map (first (path </>)) . HashMap.toList++-- | Add parameter to every operation in the spec.+addParam :: Param -> Swagger -> Swagger+addParam param spec = spec & template.operationParameters %~ (Inline param :)++-- | Add accepted content types to every operation in the spec.+addConsumes :: [MediaType] -> Swagger -> Swagger+addConsumes cs spec = spec & template.operationConsumes %~ (<> Just (MimeList cs))++-- | Add/modify response for every operation in the spec.+addResponseWith :: (Response -> Response -> Response) -> HttpStatusCode -> Response -> Swagger -> Swagger+addResponseWith f code new spec = spec+  & paths.template.responsesResponses . at code %~ Just . Inline . combine+  where+    combine (Just (Ref (Reference name))) = case spec ^. responses.at name of+      Just old -> f old new+      Nothing  -> new -- FIXME: what is the right choice here?+    combine (Just (Inline old)) = f old new+    combine Nothing = new++-- | Add/overwrite response for every operation in the spec.+addResponse :: HttpStatusCode -> Response -> Swagger -> Swagger+addResponse = addResponseWith (\_old new -> new)++addDefaultResponse404 :: ParamName -> Swagger -> Swagger+addDefaultResponse404 name = addResponseWith (\old _new -> alter404 old) 404 response404+  where+    description404 = name <> " not found"+    alter404 = description %~ ((name <> " or ") <>)+    response404 = mempty & description .~ description404++addDefaultResponse400 :: ParamName -> Swagger -> Swagger+addDefaultResponse400 name = addResponseWith (\old _new -> alter400 old) 400 response400+  where+    description400 = "Invalid " <> name+    alter400 = description %~ (<> (" or " <> name))+    response400 = mempty & description .~ description400++-- -----------------------------------------------------------------------+-- DELETE+-- -----------------------------------------------------------------------++instance {-# OVERLAPPABLE #-} (ToSchema a, AllAccept cs) => HasSwagger (Delete cs a) where+  toSwagger _ = toSwagger (Proxy :: Proxy (Delete cs (Headers '[] a)))++instance (ToSchema a, AllAccept cs, AllToResponseHeader hs) => HasSwagger (Delete cs (Headers hs a)) where+  toSwagger = mkEndpoint "/" pathItemDelete 200++instance AllAccept cs => HasSwagger (Delete cs ()) where+  toSwagger = noContentEndpoint "/" pathItemDelete++-- -----------------------------------------------------------------------+-- GET+-- -----------------------------------------------------------------------++instance {-# OVERLAPPABLE #-} (ToSchema a, AllAccept cs) => HasSwagger (Get cs a) where+  toSwagger _ = toSwagger (Proxy :: Proxy (Get cs (Headers '[] a)))++instance (ToSchema a, AllAccept cs, AllToResponseHeader hs) => HasSwagger (Get cs (Headers hs a)) where+  toSwagger = mkEndpoint "/" pathItemGet 200++instance AllAccept cs => HasSwagger (Get cs ()) where+  toSwagger = noContentEndpoint "/" pathItemGet++-- -----------------------------------------------------------------------+-- PATCH+-- -----------------------------------------------------------------------++instance {-# OVERLAPPABLE #-} (ToSchema a, AllAccept cs) => HasSwagger (Patch cs a) where+  toSwagger _ = toSwagger (Proxy :: Proxy (Patch cs (Headers '[] a)))++instance (ToSchema a, AllAccept cs, AllToResponseHeader hs) => HasSwagger (Patch cs (Headers hs a)) where+  toSwagger = mkEndpoint "/" pathItemPatch 200++instance AllAccept cs => HasSwagger (Patch cs ()) where+  toSwagger = noContentEndpoint "/" pathItemPatch++-- -----------------------------------------------------------------------+-- PUT+-- -----------------------------------------------------------------------++instance {-# OVERLAPPABLE #-} (ToSchema a, AllAccept cs) => HasSwagger (Put cs a) where+  toSwagger _ = toSwagger (Proxy :: Proxy (Put cs (Headers '[] a)))++instance (ToSchema a, AllAccept cs, AllToResponseHeader hs) => HasSwagger (Put cs (Headers hs a)) where+  toSwagger = mkEndpoint "/" pathItemPut 200++instance AllAccept cs => HasSwagger (Put cs ()) where+  toSwagger = noContentEndpoint "/" pathItemPut++-- -----------------------------------------------------------------------+-- POST+-- -----------------------------------------------------------------------++instance {-# OVERLAPPABLE #-} (ToSchema a, AllAccept cs) => HasSwagger (Post cs a) where+  toSwagger _ = toSwagger (Proxy :: Proxy (Post cs (Headers '[] a)))++instance (ToSchema a, AllAccept cs, AllToResponseHeader hs) => HasSwagger (Post cs (Headers hs a)) where+  toSwagger = mkEndpoint "/" pathItemPost 201++instance AllAccept cs => HasSwagger (Post cs ()) where+  toSwagger = noContentEndpoint "/" pathItemPost+++instance (HasSwagger a, HasSwagger b) => HasSwagger (a :<|> b) where+  toSwagger _ = toSwagger (Proxy :: Proxy a) <> toSwagger (Proxy :: Proxy b)++instance (KnownSymbol sym, HasSwagger sub) => HasSwagger (sym :> sub) where+  toSwagger _ = prependPath piece (toSwagger (Proxy :: Proxy sub))+    where+      piece = symbolVal (Proxy :: Proxy sym)++instance (KnownSymbol sym, ToParamSchema a, HasSwagger sub) => HasSwagger (Capture sym a :> sub) where+  toSwagger _ = toSwagger (Proxy :: Proxy sub)+    & addParam param+    & prependPath capture+    & addDefaultResponse404 (Text.pack name)+    where+      name = symbolVal (Proxy :: Proxy sym)+      capture = "{" <> name <> "}"+      param = mempty+        & paramName .~ Text.pack name+        & paramRequired ?~ True+        & paramSchema .~ ParamOther (mempty+            & paramOtherSchemaIn .~ ParamPath+            & parameterSchema .~ toParamSchema (Proxy :: Proxy a))++instance (KnownSymbol sym, ToParamSchema a, HasSwagger sub) => HasSwagger (QueryParam sym a :> sub) where+  toSwagger _ = toSwagger (Proxy :: Proxy sub)+    & addParam param+    & addDefaultResponse400 (Text.pack name)+    where+      name = symbolVal (Proxy :: Proxy sym)+      param = mempty+        & paramName .~ Text.pack name+        & paramSchema .~ ParamOther (mempty+            & paramOtherSchemaIn .~ ParamQuery+            & parameterSchema .~ toParamSchema (Proxy :: Proxy a))++instance (KnownSymbol sym, ToParamSchema a, HasSwagger sub) => HasSwagger (QueryParams sym a :> sub) where+  toSwagger _ = toSwagger (Proxy :: Proxy sub)+    & addParam param+    & addDefaultResponse400 (Text.pack name)+    where+      name = symbolVal (Proxy :: Proxy sym)+      param = mempty+        & paramName .~ Text.pack name+        & paramSchema .~ ParamOther (mempty+            & paramOtherSchemaIn .~ ParamQuery+            & parameterSchema .~ (mempty+                & schemaType .~ SwaggerArray+                & schemaItems ?~ SwaggerItemsPrimitive (Just CollectionMulti) (toParamSchema (Proxy :: Proxy a))))++instance (KnownSymbol sym, HasSwagger sub) => HasSwagger (QueryFlag sym :> sub) where+  toSwagger _ = toSwagger (Proxy :: Proxy sub)+    & addParam param+    & addDefaultResponse400 (Text.pack name)+    where+      name = symbolVal (Proxy :: Proxy sym)+      param = mempty+        & paramName .~ Text.pack name+        & paramSchema .~ ParamOther (mempty+            & paramOtherSchemaIn .~ ParamQuery+            & paramOtherSchemaAllowEmptyValue ?~ True+            & parameterSchema .~ (toParamSchema (Proxy :: Proxy Bool)+                & schemaDefault ?~ toJSON False))++instance (KnownSymbol sym, ToParamSchema a, HasSwagger sub) => HasSwagger (Header sym a :> sub) where+  toSwagger _ = toSwagger (Proxy :: Proxy sub)+    & addParam param+    & addDefaultResponse400 (Text.pack name)+    where+      name = symbolVal (Proxy :: Proxy sym)+      param = mempty+        & paramName .~ Text.pack name+        & paramSchema .~ ParamOther (mempty+            & paramOtherSchemaIn .~ ParamHeader+            & parameterSchema .~ toParamSchema (Proxy :: Proxy Bool))++instance (ToSchema a, AllAccept cs, HasSwagger sub) => HasSwagger (ReqBody cs a :> sub) where+  toSwagger _ = toSwagger (Proxy :: Proxy sub)+    & addParam param+    & addConsumes (allContentType (Proxy :: Proxy cs))+    & addDefaultResponse400 name+    & definitions %~ (<> defs)+    where+      name = "body"+      (defs, ref) = runDeclare (declareSchemaRef (Proxy :: Proxy a)) mempty+      param = mempty+        & paramName   .~ "body"+        & paramSchema .~ ParamBody ref++-- =======================================================================+-- Below are the definitions that should be in Servant.API.ContentTypes+-- =======================================================================++class AllAccept cs where+  allContentType :: Proxy cs -> [MediaType]++instance AllAccept '[] where+  allContentType _ = []++instance (Accept c, AllAccept cs) => AllAccept (c ': cs) where+  allContentType _ = contentType (Proxy :: Proxy c) : allContentType (Proxy :: Proxy cs)++class ToResponseHeader h where+  toResponseHeader :: Proxy h -> (HeaderName, Swagger.Header)++instance (KnownSymbol sym, ToParamSchema a) => ToResponseHeader (Header sym a) where+  toResponseHeader _ = (hname, Swagger.Header Nothing schema)+    where+      hname = Text.pack (symbolVal (Proxy :: Proxy sym))+      schema = toParamSchema (Proxy :: Proxy a)++class AllToResponseHeader hs where+  toAllResponseHeaders :: Proxy hs -> HashMap HeaderName Swagger.Header++instance AllToResponseHeader '[] where+  toAllResponseHeaders _ = mempty++instance (ToResponseHeader h, AllToResponseHeader hs) => AllToResponseHeader (h ': hs) where+  toAllResponseHeaders _ = HashMap.insert name header headers+    where+      (name, header) = toResponseHeader (Proxy :: Proxy h)+      headers = toAllResponseHeaders (Proxy :: Proxy hs)++instance AllToResponseHeader hs => AllToResponseHeader (HList hs) where+  toAllResponseHeaders _ = toAllResponseHeaders (Proxy :: Proxy hs)++-- | Check that every element of @xs@ is an endpoint of @api@.+type family AllIsElem xs api :: Constraint where+  AllIsElem '[] api = ()+  AllIsElem (x ': xs) api = (IsIn x api, AllIsElem xs api)++-- | Apply @(e :>)@ to every API in @xs@.+type family MapSub e xs where+  MapSub e '[] = '[]+  MapSub e (x ': xs) = (e :> x) ': MapSub e xs++-- | Append two type-level lists.+type family AppendList xs ys where+  AppendList '[]       ys = ys+  AppendList (x ': xs) ys = x ': AppendList xs ys++-- | Build a list of endpoints from an API.+type family EndpointsList api where+  EndpointsList (a :<|> b) = AppendList (EndpointsList a) (EndpointsList b)+  EndpointsList (e :> a)   = MapSub e (EndpointsList a)+  EndpointsList a = '[a]++-- | Check whether @sub@ is a sub API of @api@.+type family IsSubAPI sub api :: Constraint where+  IsSubAPI sub api = AllIsElem (EndpointsList sub) api++type family Or (a :: Constraint) (b :: Constraint) :: Constraint where+  Or () b = ()+  Or a () = ()++type family IsIn sub api :: Constraint where+  IsIn e (a :<|> b) = Or (IsIn e a) (IsIn e b)+  IsIn (e :> a) (e :> b) = IsIn a b+  IsIn e e = ()+
+ test/Servant/SwaggerSpec.hs view
@@ -0,0 +1,323 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE QuasiQuotes #-}+module Servant.SwaggerSpec where++import Control.Lens+import Data.Aeson+import qualified Data.Aeson.Types as JSON+import Data.Aeson.QQ+import Data.Char (toLower)+import Data.Proxy+import Data.Swagger+import Data.Text (Text)+import qualified Data.Text as Text+import Data.Time+import GHC.Generics+import Servant.API+import Servant.Swagger+import Test.Hspec++checkAPI :: HasSwagger api => Proxy api -> Value -> IO ()+checkAPI proxy = checkSwagger (toSwagger proxy)++checkSwagger :: Swagger -> Value -> IO ()+checkSwagger swag js = toJSON swag `shouldBe` js++spec :: Spec+spec = describe "HasSwagger" $ do+  it "Todo API" $ checkAPI (Proxy :: Proxy TodoAPI) todoAPI+  it "Hackage API (with tags)" $ checkSwagger hackageSwaggerWithTags hackageAPI++main :: IO ()+main = hspec spec++-- =======================================================================+-- Todo API+-- =======================================================================++data Todo = Todo+  { created     :: UTCTime+  , title       :: String+  , description :: Maybe String+  } deriving (Generic, FromJSON, ToSchema)++newtype TodoId = TodoId String deriving (Generic, ToParamSchema)++type TodoAPI = "todo" :> Capture "id" TodoId :> Get '[JSON] Todo++todoAPI :: Value+todoAPI = [aesonQQ|+{+  "swagger":"2.0",+  "info":+    {+      "title": "",+      "version": ""+    },+  "definitions":+    {+      "Todo":+        {+          "type": "object",+          "required": [ "created", "title" ],+          "properties":+            {+              "created": { "$ref": "#/definitions/UTCTime" },+              "title": { "type": "string" },+              "description": { "type": "string" }+            }+        },+      "UTCTime":+        {+          "type": "string",+          "format": "yyyy-mm-ddThh:MM:ssZ"+        }+    },+  "paths":+    {+      "/todo/{id}":+        {+          "get":+            {+              "responses":+                {+                  "200":+                    {+                      "schema": { "$ref":"#/definitions/Todo" },+                      "description": ""+                    },+                  "404": { "description": "id not found" }+                },+              "produces": [ "application/json" ],+              "parameters":+                [+                  {+                    "required": true,+                    "in": "path",+                    "name": "id",+                    "type": "string"+                   }+                ]+            }+        }+    }+}+|]++-- =======================================================================+-- Hackage API+-- =======================================================================++type HackageAPI+    = HackageUserAPI+ :<|> HackagePackagesAPI++type HackageUserAPI =+      "users" :> Get '[JSON] [UserSummary]+ :<|> "user" :> Capture "username" Username :> Get '[JSON] UserDetailed++type HackagePackagesAPI+    = "packages" :> Get '[JSON] [Package]++type Username = Text++data UserSummary = UserSummary+  { summaryUsername :: Username+  , summaryUserid   :: Int+  } deriving (Eq, Show, Generic)++lowerCutPrefix :: String -> String -> String+lowerCutPrefix s = map toLower . drop (length s)++instance ToJSON UserSummary where+  toJSON = genericToJSON JSON.defaultOptions { JSON.fieldLabelModifier = lowerCutPrefix "summary" }++instance ToSchema UserSummary where+  declareNamedSchema proxy = do+    (name, schema) <- genericDeclareNamedSchema defaultSchemaOptions { fieldLabelModifier = lowerCutPrefix "summary" } proxy+    return (name, schema+      & schemaExample ?~ toJSON UserSummary+         { summaryUsername = "JohnDoe"+         , summaryUserid   = 123 })++type Group = Text++data UserDetailed = UserDetailed+  { username :: Username+  , userid   :: Int+  , groups   :: [Group]+  } deriving (Eq, Show, Generic, ToSchema)++newtype Package = Package { packageName :: Text }+  deriving (Eq, Show, Generic, ToSchema)++hackageSwaggerWithTags :: Swagger+hackageSwaggerWithTags = toSwagger (Proxy :: Proxy HackageAPI)+  & host ?~ Host "hackage.haskell.org" Nothing+  & usersOps    %~ addTag "users"+  & packagesOps %~ addTag "packages"+  & tags .~+      [ Tag "users" (Just "Operations about user") Nothing+      , Tag "packages" (Just "Query packages") Nothing+      ]+  where+    usersOps    = subOperations (Proxy :: Proxy HackageUserAPI)     (Proxy :: Proxy HackageAPI)+    packagesOps = subOperations (Proxy :: Proxy HackagePackagesAPI) (Proxy :: Proxy HackageAPI)++hackageAPI :: Value+hackageAPI = [aesonQQ|+{+   "swagger":"2.0",+   "host":"hackage.haskell.org",+   "info":{+      "version":"",+      "title":""+   },+   "definitions":{+      "UserDetailed":{+         "required":[+            "username",+            "userid",+            "groups"+         ],+         "type":"object",+         "properties":{+            "groups":{+               "items":{+                  "type":"string"+               },+               "type":"array"+            },+            "username":{+               "type":"string"+            },+            "userid":{+               "maximum":9223372036854775807,+               "minimum":-9223372036854775808,+               "type":"integer"+            }+         }+      },+      "Package":{+         "required":[+            "packageName"+         ],+         "type":"object",+         "properties":{+            "packageName":{+               "type":"string"+            }+         }+      },+      "UserSummary":{+         "required":[+            "username",+            "userid"+         ],+         "type":"object",+         "properties":{+            "username":{+               "type":"string"+            },+            "userid":{+               "maximum":9223372036854775807,+               "minimum":-9223372036854775808,+               "type":"integer"+            }+         },+         "example":{+            "username": "JohnDoe",+            "userid": 123+         }+      }+   },+   "paths":{+      "/users":{+         "get":{+            "responses":{+               "200":{+                  "schema":{+                     "items":{+                        "$ref":"#/definitions/UserSummary"+                     },+                     "type":"array"+                  },+                  "description":""+               }+            },+            "produces":[+               "application/json"+            ],+            "tags":[+               "users"+            ]+         }+      },+      "/packages":{+         "get":{+            "responses":{+               "200":{+                  "schema":{+                     "items":{+                        "$ref":"#/definitions/Package"+                     },+                     "type":"array"+                  },+                  "description":""+               }+            },+            "produces":[+               "application/json"+            ],+            "tags":[+               "packages"+            ]+         }+      },+      "/user/{username}":{+         "get":{+            "responses":{+               "404":{+                  "description":"username not found"+               },+               "200":{+                  "schema":{+                     "$ref":"#/definitions/UserDetailed"+                  },+                  "description":""+               }+            },+            "produces":[+               "application/json"+            ],+            "parameters":[+               {+                  "required":true,+                  "in":"path",+                  "name":"username",+                  "type":"string"+               }+            ],+            "tags":[+               "users"+            ]+         }+      }+   },+   "tags":[+      {+         "name":"users",+         "description":"Operations about user"+      },+      {+         "name":"packages",+         "description":"Query packages"+      }+   ]+}+|]+
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}