git.iko.soy/typeable/openapi3
on master help sign in
Merge pull request #26 from GetShopTV/docs-#20
5da3f8eNickolay Kudasov
README.md+29
@@ -4,3 +4,32 @@
4[![Build Status](https://travis-ci.org/GetShopTV/swagger2.svg?branch=master)](https://travis-ci.org/GetShopTV/swagger2)
4[![Build Status](https://travis-ci.org/GetShopTV/swagger2.svg?branch=master)](https://travis-ci.org/GetShopTV/swagger2)
5
5
6Swagger 2.0 data model.
6Swagger 2.0 data model.
7+
8+The original Swagger 2.0 specification is available at http://swagger.io/specification/.
9+
10+## Usage
11+
12+This library is inteded to be used for decoding and encoding Swagger 2.0 API specifications as well as manipulating them.
13+
14+Please refer to [haddock documentation](http://hackage.haskell.org/package/swagger2).
15+
16+Some examples can be found in [`examples/` directory](/examples).
17+
18+## Trying out
19+
20+All generated swagger specifications can be interactively viewed on [Swagger Editor](http://editor.swagger.io/).
21+
22+Ready-to-use specification can be served as JSON and interactive API documentation
23+can be displayed using [Swagger UI](https://github.com/swagger-api/swagger-ui).
24+
25+Many Swagger tools, including server and client code generation for many languages, can be found on
26+[Swagger's Tools and Integrations page](http://swagger.io/open-source-integrations/).
27+
28+## Contributing
29+
30+We are happy to receive bug reports, fixes, documentation enhancements, and other improvements.
31+
32+Please report bugs via the [github issue tracker](https://github.com/GetShopTV/swagger2/issues).
33+
34+*GetShopTV Team*
35+
examples/hackage.hsnew file+70
@@ -0,0 +1,70 @@
1+{-# LANGUAGE DeriveGeneric #-}
2+{-# LANGUAGE DeriveAnyClass #-}
3+{-# LANGUAGE OverloadedLists #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+module Main where
6+
7+import Control.Lens
8+import Data.Aeson
9+import Data.Proxy
10+import Data.Text (Text)
11+import GHC.Generics
12+
13+import Data.Swagger
14+import Data.Swagger.Declare
15+import Data.Swagger.Lens
16+
17+type Username = Text
18+
19+data UserSummary = UserSummary
20+ { summaryUsername :: Username
21+ , summaryUserid :: Int
22+ } deriving (Generic, ToSchema)
23+
24+type Group = Text
25+
26+data UserDetailed = UserDetailed
27+ { username :: Username
28+ , userid :: Int
29+ , groups :: [Group]
30+ } deriving (Generic, ToSchema)
31+
32+newtype Package = Package { packageName :: Text }
33+ deriving (Generic, ToSchema)
34+
35+hackageSwagger :: Swagger
36+hackageSwagger = spec & definitions .~ defs
37+ where
38+ (defs, spec) = runDeclare declareHackageSwagger mempty
39+
40+declareHackageSwagger :: Declare Definitions Swagger
41+declareHackageSwagger = do
42+ let usernameParamSchema = toParamSchema (Proxy :: Proxy Username)
43+ userSummarySchemaRef <- declareSchemaRef (Proxy :: Proxy UserSummary)
44+ userDetailedSchemaRef <- declareSchemaRef (Proxy :: Proxy UserDetailed)
45+ packagesSchemaRef <- declareSchemaRef (Proxy :: Proxy [Package])
46+ return $ mempty
47+ & paths.pathsMap .~
48+ [ ("/users", mempty & pathItemGet ?~ (mempty
49+ & operationProduces ?~ MimeList ["application/json"]
50+ & operationResponses .~ (mempty
51+ & responsesResponses . at 200 ?~ Inline (mempty & responseSchema ?~ userSummarySchemaRef))))
52+ , ("/user/{username}", mempty & pathItemGet ?~ (mempty
53+ & operationProduces ?~ MimeList ["application/json"]
54+ & operationParameters .~ [ Inline $ mempty
55+ & paramName .~ "username"
56+ & paramRequired ?~ True
57+ & paramSchema .~ ParamOther (mempty
58+ & paramOtherSchemaIn .~ ParamPath
59+ & paramOtherSchemaParamSchema .~ usernameParamSchema) ]
60+ & operationResponses .~ (mempty
61+ & responsesResponses . at 200 ?~ Inline (mempty & responseSchema ?~ userDetailedSchemaRef))))
62+ , ("/packages", mempty & pathItemGet ?~ (mempty
63+ & operationProduces ?~ MimeList ["application/json"]
64+ & operationResponses .~ (mempty
65+ & responsesResponses . at 200 ?~ Inline (mempty & responseSchema ?~ packagesSchemaRef))))
66+ ]
67+
68+main :: IO ()
69+main = putStrLn . read . show . encode $ hackageSwagger
70+
src/Data/Swagger.hs+141−13
@@ -6,6 +6,20 @@
6-- and Swagger-Codegen to generate clients in various languages.
6-- and Swagger-Codegen to generate clients in various languages.
7-- Additional utilities can also take advantage of the resulting files, such as testing tools.
7-- Additional utilities can also take advantage of the resulting files, such as testing tools.
8module Data.Swagger (
8module Data.Swagger (
9+ -- * How to use this library
10+ -- $howto
11+
12+ -- ** @'Monoid'@ instances
13+ -- $monoids
14+
15+ -- ** Lenses and prisms
16+ -- $lens
17+
18+ -- ** Schema specification
19+ -- $schema
20+
21+ -- * Re-exports
22+ module Data.Swagger.Lens,
9 module Data.Swagger.ParamSchema,
23 module Data.Swagger.ParamSchema,
10 module Data.Swagger.Schema,
24 module Data.Swagger.Schema,
11
25
@@ -14,25 +28,25 @@ module Data.Swagger (
14 Host(..),
28 Host(..),
15 Scheme(..),
29 Scheme(..),
16
30
17− -- * Info types
31+ -- ** Info types
18 Info(..),
32 Info(..),
19 Contact(..),
33 Contact(..),
20 License(..),
34 License(..),
21
35
22− -- * Paths
36+ -- ** Paths
23 Paths(..),
37 Paths(..),
24 PathItem(..),
38 PathItem(..),
25
39
26− -- * Operations
40+ -- ** Operations
27 Tag(..),
41 Tag(..),
28 Operation(..),
42 Operation(..),
29
43
30− -- * Types and formats
44+ -- ** Types and formats
31 SwaggerType(..),
45 SwaggerType(..),
32 Format,
46 Format,
33 CollectionFormat(..),
47 CollectionFormat(..),
34
48
35− -- * Parameters
49+ -- ** Parameters
36 Param(..),
50 Param(..),
37 ParamAnySchema(..),
51 ParamAnySchema(..),
38 ParamOtherSchema(..),
52 ParamOtherSchema(..),
@@ -42,45 +56,159 @@ module Data.Swagger (
42 Header(..),
56 Header(..),
43 Example(..),
57 Example(..),
44
58
45− -- * Schemas
59+ -- ** Schemas
46 ParamSchema(..),
60 ParamSchema(..),
47 Schema(..),
61 Schema(..),
48 SwaggerItems(..),
62 SwaggerItems(..),
49 Xml(..),
63 Xml(..),
50
64
51− -- * Responses
65+ -- ** Responses
52 Responses(..),
66 Responses(..),
53 Response(..),
67 Response(..),
54
68
55− -- * Security
69+ -- ** Security
56 SecurityScheme(..),
70 SecurityScheme(..),
57 SecuritySchemeType(..),
71 SecuritySchemeType(..),
58 SecurityRequirement(..),
72 SecurityRequirement(..),
59
73
60− -- ** API key
74+ -- *** API key
61 ApiKeyParams(..),
75 ApiKeyParams(..),
62 ApiKeyLocation(..),
76 ApiKeyLocation(..),
63
77
64− -- ** OAuth2
78+ -- *** OAuth2
65 OAuth2Params(..),
79 OAuth2Params(..),
66 OAuth2Flow(..),
80 OAuth2Flow(..),
67 AuthorizationURL,
81 AuthorizationURL,
68 TokenURL,
82 TokenURL,
69
83
70− -- * External documentation
84+ -- ** External documentation
71 ExternalDocs(..),
85 ExternalDocs(..),
72
86
73− -- * References
87+ -- ** References
74 Reference(..),
88 Reference(..),
75 Referenced(..),
89 Referenced(..),
76
90
77− -- * Miscellaneous
91+ -- ** Miscellaneous
78 MimeList(..),
92 MimeList(..),
79 URL(..),
93 URL(..),
80) where
94) where
81
95
96+import Data.Swagger.Lens
82import Data.Swagger.ParamSchema
97import Data.Swagger.ParamSchema
83import Data.Swagger.Schema
98import Data.Swagger.Schema
84
99
85import Data.Swagger.Internal
100import Data.Swagger.Internal
86
101
102+-- $setup
103+-- >>> import Control.Lens
104+-- >>> import Data.Aeson
105+-- >>> import Data.Monoid
106+-- >>> import Data.Proxy
107+-- >>> import GHC.Generics
108+-- >>> :set -XDeriveGeneric
109+-- >>> :set -XOverloadedStrings
110+-- >>> :set -XOverloadedLists
111+-- >>> :set -fno-warn-missing-methods
112+
113+-- $howto
114+--
115+-- This section explains how to use this library to work with Swagger specification.
116+
117+-- $monoids
118+--
119+-- Virtually all types representing Swagger specification have @'Monoid'@ instances.
120+-- The @'Monoid'@ type class provides two methods — @'mempty'@ and @'mappend'@.
121+--
122+-- In this library you can use @'mempty'@ for a default/empty value. For instance:
123+--
124+-- >>> encode (mempty :: Swagger)
125+-- "{\"swagger\":\"2.0\",\"info\":{\"version\":\"\",\"title\":\"\"}}"
126+--
127+-- As you can see some spec properties (e.g. @"version"@) are there even when the spec is empty.
128+-- That is because these properties are actually required ones.
129+--
130+-- You /should/ always override the default (empty) value for these properties,
131+-- although it is not strictly necessary:
132+--
133+-- >>> encode mempty { _infoTitle = "Todo API", _infoVersion = "1.0" }
134+-- "{\"version\":\"1.0\",\"title\":\"Todo API\"}"
135+--
136+-- You can merge two values using @'mappend'@ or its infix version @('<>')@:
137+--
138+-- >>> encode $ mempty { _infoTitle = "Todo API" } <> mempty { _infoVersion = "1.0" }
139+-- "{\"version\":\"1.0\",\"title\":\"Todo API\"}"
140+--
141+-- This can be useful for combining specifications of endpoints into a whole API specification:
142+--
143+-- @
144+-- \-\- /account subAPI specification
145+-- accountAPI :: Swagger
146+--
147+-- \-\- /task subAPI specification
148+-- taskAPI :: Swagger
149+--
150+-- \-\- while API specification is just a combination
151+-- \-\- of subAPIs' specifications
152+-- api :: Swagger
153+-- api = accountAPI <> taskAPI
154+-- @
155+
156+-- $lens
157+--
158+-- Since @'Swagger'@ has a fairly complex structure, lenses and prisms are used
159+-- to modify this structure. In combination with @'Monoid'@ instances, lenses
160+-- also make it fairly simple to construct/modify any part of the specification:
161+--
162+-- >>> :{
163+-- encode $ mempty & pathsMap .~
164+-- [ ("/user", mempty & pathItemGet ?~ (mempty
165+-- & operationProduces ?~ MimeList ["application/json"]
166+-- & operationResponses .~ (mempty
167+-- & responsesResponses . at 200 ?~ Inline (mempty & responseSchema ?~ Ref (Reference "#/definitions/User")))))]
168+-- :}
169+-- "{\"/user\":{\"get\":{\"responses\":{\"200\":{\"schema\":{\"$ref\":\"#/definitions/#/definitions/User\"},\"description\":\"\"}},\"produces\":[\"application/json\"]}}}"
170+--
171+-- Since @'ParamSchema'@ is basically the /base schema specification/, a special
172+-- @'HasParamSchema'@ class has been introduced to generalize @'ParamSchema'@ lenses
173+-- and allow them to be used by any type that has a @'ParamSchema'@:
174+--
175+-- >>> :{
176+-- encode $ mempty
177+-- & schemaTitle ?~ "Email"
178+-- & schemaType .~ SwaggerString
179+-- & schemaFormat ?~ "email"
180+-- :}
181+-- "{\"format\":\"email\",\"title\":\"Email\",\"type\":\"string\"}"
182+
183+-- $schema
184+--
185+-- This library provides two classes for schema encoding.
186+-- Both these classes provide means to encode _types_ as Swagger _schemas_.
187+--
188+-- @'ToParamSchema'@ is intended to be used for primitive API endpoint parameters,
189+-- such as query parameters, headers and URL path pieces.
190+-- Its corresponding value-encoding class is @'ToHttpApiData'@ (from @http-api-data@ package).
191+--
192+-- @'ToSchema'@ is used for request and response bodies and mostly differ from
193+-- primitive parameters by allowing objects/mappings in addition to primitive types and arrays.
194+-- Its corresponding value-encoding class is @'ToJSON'@ (from @aeson@ package).
195+--
196+-- While lenses and prisms make it easy to define schemas, it might be that you don't need to:
197+-- @'ToSchema'@ and @'ToParamSchema'@ classes both have default @'Generic'@-based implementations!
198+--
199+-- @'ToSchema'@ default implementation is also aligned with @'ToJSON'@ default implementation with
200+-- the only difference being for sum encoding. @'ToJSON'@ defaults sum encoding to @'defaultTaggedObject'@,
201+-- while @'ToSchema'@ defaults to something which corresponds to @'ObjectWithSingleField'@. This is due to
202+-- @'defaultTaggedObject'@ behavior being hard to specify in Swagger.
203+--
204+-- Here's an example showing @'ToJSON'@–@'ToSchema'@ correspondance:
205+--
206+-- >>> data Person = Person { name :: String, age :: Integer } deriving Generic
207+-- >>> instance ToJSON Person
208+-- >>> instance ToSchema Person
209+-- >>> encode (Person "David" 28)
210+-- "{\"age\":28,\"name\":\"David\"}"
211+-- >>> encode $ toSchema (Proxy :: Proxy Person)
212+-- "{\"required\":[\"name\",\"age\"],\"type\":\"object\",\"properties\":{\"age\":{\"type\":\"integer\"},\"name\":{\"type\":\"string\"}}}"
213+--
214+
src/Data/Swagger/Declare.hs+13
@@ -72,12 +72,18 @@ instance (Monad m, Monoid d) => MonadDeclare d (DeclareT d m) where
72looks :: MonadDeclare d m => (d -> a) -> m a
72looks :: MonadDeclare d m => (d -> a) -> m a
73looks f = f <$> look
73looks f = f <$> look
74
74
75+-- | Evaluate @'DeclareT' d m a@ computation,
76+-- ignoring new output @d@.
75evalDeclareT :: Monad m => DeclareT d m a -> d -> m a
77evalDeclareT :: Monad m => DeclareT d m a -> d -> m a
76evalDeclareT (DeclareT f) d = snd `liftM` f d
78evalDeclareT (DeclareT f) d = snd `liftM` f d
77
79
80+-- | Execute @'DeclateT' d m a@ computation,
81+-- ignoring result and only producing new output @d@.
78execDeclareT :: Monad m => DeclareT d m a -> d -> m d
82execDeclareT :: Monad m => DeclareT d m a -> d -> m d
79execDeclareT (DeclareT f) d = fst `liftM` f d
83execDeclareT (DeclareT f) d = fst `liftM` f d
80
84
85+-- | Evaluate @'DeclareT' d m a@ computation,
86+-- starting with empty output history.
81undeclareT :: (Monad m, Monoid d) => DeclareT d m a -> m a
87undeclareT :: (Monad m, Monoid d) => DeclareT d m a -> m a
82undeclareT = flip evalDeclareT mempty
88undeclareT = flip evalDeclareT mempty
83
89
@@ -91,15 +97,22 @@ undeclareT = flip evalDeclareT mempty
91-- * a writer monad with the extra ability to read all previous output.
97-- * a writer monad with the extra ability to read all previous output.
92type Declare d = DeclareT d Identity
98type Declare d = DeclareT d Identity
93
99
100+-- | Run @'Declare' d a@ computation with output history @d@,
101+-- producing result @a@ and new output @d@.
94runDeclare :: Declare d a -> d -> (d, a)
102runDeclare :: Declare d a -> d -> (d, a)
95runDeclare m = runIdentity . runDeclareT m
103runDeclare m = runIdentity . runDeclareT m
96
104
105+-- | Evaluate @'Declare' d a@ computation, ignoring output @d@.
97evalDeclare :: Declare d a -> d -> a
106evalDeclare :: Declare d a -> d -> a
98evalDeclare m = runIdentity . evalDeclareT m
107evalDeclare m = runIdentity . evalDeclareT m
99
108
109+-- | Execute @'Declate' d a@ computation, ignoring result and only
110+-- producing output @d@.
100execDeclare :: Declare d a -> d -> d
111execDeclare :: Declare d a -> d -> d
101execDeclare m = runIdentity . execDeclareT m
112execDeclare m = runIdentity . execDeclareT m
102
113
114+-- | Evaluate @'DeclareT' d m a@ computation,
115+-- starting with empty output history.
103undeclare :: Monoid d => Declare d a -> a
116undeclare :: Monoid d => Declare d a -> a
104undeclare = runIdentity . undeclareT
117undeclare = runIdentity . undeclareT
105
118
src/Data/Swagger/Internal/ParamSchema.hs+11
@@ -63,6 +63,9 @@ import Data.Swagger.SchemaOptions
63-- @
63-- @
64class ToParamSchema a where
64class ToParamSchema a where
65 -- | Convert a type into a plain parameter schema.
65 -- | Convert a type into a plain parameter schema.
66+ --
67+ -- >>> encode $ toParamSchema (Proxy :: Proxy Integer)
68+ -- "{\"type\":\"integer\"}"
66 toParamSchema :: proxy a -> ParamSchema t
69 toParamSchema :: proxy a -> ParamSchema t
67 default toParamSchema :: (Generic a, GToParamSchema (Rep a)) => proxy a -> ParamSchema t
70 default toParamSchema :: (Generic a, GToParamSchema (Rep a)) => proxy a -> ParamSchema t
68 toParamSchema = genericToParamSchema defaultSchemaOptions
71 toParamSchema = genericToParamSchema defaultSchemaOptions
@@ -89,6 +92,9 @@ instance ToParamSchema Word32 where toParamSchema = toParamSchemaBoundedIntegral
89instance ToParamSchema Word64 where toParamSchema = toParamSchemaBoundedIntegral
92instance ToParamSchema Word64 where toParamSchema = toParamSchemaBoundedIntegral
90
93
91-- | Default plain schema for @'Bounded'@, @'Integral'@ types.
94-- | Default plain schema for @'Bounded'@, @'Integral'@ types.
95+--
96+-- >>> encode $ toParamSchemaBoundedIntegral (Proxy :: Proxy Int8)
97+-- "{\"maximum\":127,\"minimum\":-128,\"type\":\"integer\"}"
92toParamSchemaBoundedIntegral :: forall proxy a t. (Bounded a, Integral a) => proxy a -> ParamSchema t
98toParamSchemaBoundedIntegral :: forall proxy a t. (Bounded a, Integral a) => proxy a -> ParamSchema t
93toParamSchemaBoundedIntegral _ = mempty
99toParamSchemaBoundedIntegral _ = mempty
94 & schemaType .~ SwaggerInteger
100 & schemaType .~ SwaggerInteger
@@ -166,6 +172,11 @@ instance ToParamSchema () where
166 & schemaEnum ?~ ["_"]
172 & schemaEnum ?~ ["_"]
167
173
168-- | A configurable generic @'ParamSchema'@ creator.
174-- | A configurable generic @'ParamSchema'@ creator.
175+--
176+-- >>> :set -XDeriveGeneric
177+-- >>> data Color = Red | Blue deriving Generic
178+-- >>> encode $ genericToParamSchema defaultSchemaOptions (Proxy :: Proxy Color)
179+-- "{\"type\":\"string\",\"enum\":[\"Red\",\"Blue\"]}"
169genericToParamSchema :: forall proxy a t. (Generic a, GToParamSchema (Rep a)) => SchemaOptions -> proxy a -> ParamSchema t
180genericToParamSchema :: forall proxy a t. (Generic a, GToParamSchema (Rep a)) => SchemaOptions -> proxy a -> ParamSchema t
170genericToParamSchema opts _ = gtoParamSchema opts (Proxy :: Proxy (Rep a)) mempty
181genericToParamSchema opts _ = gtoParamSchema opts (Proxy :: Proxy (Rep a)) mempty
171
182
src/Data/Swagger/Internal/Schema.hs+3
@@ -373,6 +373,9 @@ instance ToSchema a => ToSchema (Last a) where declareNamedSchema _ = unname
373instance ToSchema a => ToSchema (Dual a) where declareNamedSchema _ = unname <$> declareNamedSchema (Proxy :: Proxy a)
373instance ToSchema a => ToSchema (Dual a) where declareNamedSchema _ = unname <$> declareNamedSchema (Proxy :: Proxy a)
374
374
375-- | Default schema for @'Bounded'@, @'Integral'@ types.
375-- | Default schema for @'Bounded'@, @'Integral'@ types.
376+--
377+-- >>> encode $ toSchemaBoundedIntegral (Proxy :: Proxy Int16)
378+-- "{\"maximum\":32767,\"minimum\":-32768,\"type\":\"integer\"}"
376toSchemaBoundedIntegral :: forall a proxy. (Bounded a, Integral a) => proxy a -> Schema
379toSchemaBoundedIntegral :: forall a proxy. (Bounded a, Integral a) => proxy a -> Schema
377toSchemaBoundedIntegral _ = mempty
380toSchemaBoundedIntegral _ = mempty
378 & schemaType .~ SwaggerInteger
381 & schemaType .~ SwaggerInteger
test/Data/SwaggerSpec.hs−1
@@ -12,7 +12,6 @@ import Data.HashMap.Strict (HashMap)
12import Data.Text (Text)
12import Data.Text (Text)
13
13
14import Data.Swagger
14import Data.Swagger
15−import Data.Swagger.Lens
16import SpecCommon
15import SpecCommon
17import Test.Hspec
16import Test.Hspec
18
17