Skip to content

Commit

Permalink
Merge pull request #9 from fizruk/swagger2-#8
Browse files Browse the repository at this point in the history
Use swagger2 for data model
  • Loading branch information
fizruk committed Dec 31, 2015
2 parents dbe4569 + 1a2c62b commit d148710
Show file tree
Hide file tree
Showing 11 changed files with 871 additions and 1,289 deletions.
18 changes: 17 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,20 @@
dist/
/foo.json
servant-client-0.4.4/
.stack-work
cabal-dev
*.o
*.hi
*.chi
*.chs.h
*.dyn_o
*.dyn_hi
.virtualenv
.hpc
.hsenv
.cabal-sandbox/
cabal.sandbox.config
*.prof
*.aux
*.hp
.stack-work/
swagger.json
159 changes: 71 additions & 88 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,73 +14,61 @@

<p align="center">
<img src="http://s16.postimg.org/rndz1wbyt/servant.png" />
</p>
</p>

<hr>

Given the following `servant` API, `servant-swagger` generates the following json.

### [Input](example/File.hs)

```haskell
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
module Main where

import Servant.API
import Servant.Server
import Servant.Swagger
import Data.Proxy
import Control.Lens
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as BL8
import Data.Proxy
import Data.Swagger
import GHC.Generics
import Control.Lens
import Servant
import Servant.Swagger

-- Types
data Todo = Todo {
created :: Int
data Todo = Todo
{ created :: Int
, description :: String
} deriving (Show, Eq, Generic)

instance ToJSON Todo
instance FromJSON Todo

newtype TodoId = TodoId String deriving (FromText)
newtype TodoId = TodoId String deriving (FromText, Generic)

-- API
type API = "todo" :> Capture "id" TodoId :> Get '[JSON] Todo

-- Swagger Doc
swagDoc :: SwaggerAPI
swagDoc = swagger (Proxy :: Proxy API) mempty (BasePath "/") info schemes Nothing []
where
schemes = [ Http ]
license' = APILicense "MIT" (Just "http://mit.com")
info =
Info
(APITitle "Todo API") (APIVersion "1.0")
(APIDescription "This is a an API that tests servant-swagger support for a Todo")
(Just license')
Nothing
Nothing
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 ToSwaggerParamType TodoId where toSwaggerParamType = const StringSwagParam
instance ToSwaggerDescription TodoId where toSwaggerDescription = const "TodoId param"

instance ToSwaggerModel Todo where
toSwagModel Proxy =
emptyModel
& swagModelName .~ ModelName "Todo"
& swagProperties .~ [ ("created", IntegerSwag)
, ("description", StringSwag)
, ("extraTodos", Model $ ModelSwag (ModelName "Todo") False)
]
& swagDescription ?~ Description "This is some real Todo right here"
& swagModelExample ?~ toJSON (Todo 100 "get milk")
& swagModelRequired .~ ["description"]
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 ()
Expand All @@ -90,94 +78,89 @@ main = BL8.writeFile "swagger.json" (encode swagDoc)
### Output

```json
{
{
"swagger":"2.0",
"basePath":"/",
"schemes":[
"http"
],
"info":{
"info":{
"version":"1.0",
"title":"Todo API",
"license":{
"license":{
"url":"http://mit.com",
"name":"MIT"
},
"description":"This is a an API that tests servant-swagger support for a Todo"
"description":"This is an API that tests servant-swagger support for a Todo"
},
"definitions":{
"Todo":{
"example":{
"definitions":{
"Todo":{
"example":{
"created":100,
"description":"get milk"
},
"required":[
"required":[
"created",
"description"
],
"type":"object",
"description":"This is some real Todo right here",
"properties":{
"created":{
"format":"int32",
"properties":{
"created":{
"maximum":9223372036854775807,
"minimum":-9223372036854775808,
"type":"integer"
},
"description":{
"description":{
"type":"string"
},
"extraTodos":{
"$ref":"#/definitions/Todo"
}
}
}
},
"paths":{
"/todo/{id}":{
"get":{
"summary":"",
"consumes":[

],
"responses":{
"200":{
"schema":{
"paths":{
"/todo/{id}":{
"get":{
"responses":{
"404":{
"description":"id not found"
},
"200":{
"schema":{
"$ref":"#/definitions/Todo"
},
"headers":{

},
"description":"OK"
"description":""
}
},
"produces":[
"produces":[
"application/json"
],
"parameters":[
{
"parameters":[
{
"required":true,
"in":"path",
"name":"id",
"type":"string",
"description":"TodoId param"
"type":"string"
}
],
"description":"",
"tags":[

]
}
}
},
"tags":[

]
}
}
```

## Try it out
- All generated swagger docs can be interactively viewed on <a href="http://editor.swagger.io/">Swagger Editor</a>

## Limitations
- Quite a few, TODO: add this
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).

64 changes: 26 additions & 38 deletions example/File.hs
Original file line number Diff line number Diff line change
@@ -1,63 +1,51 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
module Main where

import Servant.API
import Servant.Server
import Servant.Swagger
import Data.Proxy
import Control.Lens
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as BL8
import Data.Proxy
import Data.Swagger
import GHC.Generics
import Control.Lens
import Servant
import Servant.Swagger

-- Types
data Todo = Todo {
created :: Int
data Todo = Todo
{ created :: Int
, description :: String
} deriving (Show, Eq, Generic)

instance ToJSON Todo
instance FromJSON Todo

newtype TodoId = TodoId String deriving (FromText)
newtype TodoId = TodoId String deriving (FromText, Generic)

-- API
type API = "todo" :> Capture "id" TodoId :> Get '[JSON] Todo

-- Swagger Doc
swagDoc :: SwaggerAPI
swagDoc = swagger (Proxy :: Proxy API) mempty (BasePath "/") info schemes Nothing []
where
schemes = [ Http ]
license' = APILicense "MIT" (Just "http://mit.com")
info =
Info
(APITitle "Todo API") (APIVersion "1.0")
(APIDescription "This is a an API that tests servant-swagger support for a Todo")
(Just license')
Nothing
Nothing
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 ToSwaggerParamType TodoId where toSwaggerParamType = const StringSwagParam
instance ToSwaggerDescription TodoId where toSwaggerDescription = const "TodoId param"

instance ToSwaggerModel Todo where
toSwagModel Proxy =
emptyModel
& swagModelName .~ ModelName "Todo"
& swagProperties .~ [ ("created", IntegerSwag)
, ("description", StringSwag)
, ("extraTodos", Model $ ModelSwag (ModelName "Todo") False)
]
& swagDescription ?~ Description "This is some real Todo right here"
& swagModelExample ?~ toJSON (Todo 100 "get milk")
& swagModelRequired .~ ["description"]
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)

Loading

0 comments on commit d148710

Please sign in to comment.