git.iko.soy/typeable/openapi3
on master help sign in
Add 'scheme' field for 'http' security scheme type
9ea13c6Uladzimir Stsepchanka
openapi3.cabal+1
@@ -88,6 +88,7 @@ library
88 , uuid-types >=1.0.3 && <1.1
88 , uuid-types >=1.0.3 && <1.1
89 , vector >=0.12.0.1 && <0.13
89 , vector >=0.12.0.1 && <0.13
90 , QuickCheck >=2.10.1 && <2.15
90 , QuickCheck >=2.10.1 && <2.15
91+ , generic-arbitrary >=0.1 && <0.2
91
92
92 default-language: Haskell2010
93 default-language: Haskell2010
93
94
src/Data/OpenApi.hs+3
@@ -94,6 +94,9 @@ module Data.OpenApi (
94 SecurityDefinitions(..),
94 SecurityDefinitions(..),
95 SecurityRequirement(..),
95 SecurityRequirement(..),
96
96
97+ -- ** Http Scheme
98+ HttpScheme(..),
99+
97 -- *** API key
100 -- *** API key
98 ApiKeyParams(..),
101 ApiKeyParams(..),
99 ApiKeyLocation(..),
102 ApiKeyLocation(..),
src/Data/OpenApi/Internal.hs+36−4
@@ -41,6 +41,7 @@ import Network.HTTP.Media (MediaType, mainType, parameters, parseAc
41 (/:))
41 (/:))
42import Network.Socket (HostName, PortNumber)
42import Network.Socket (HostName, PortNumber)
43import Text.Read (readMaybe)
43import Text.Read (readMaybe)
44+import Test.QuickCheck.Arbitrary.Generic
44
45
45import Data.HashMap.Strict.InsOrd (InsOrdHashMap)
46import Data.HashMap.Strict.InsOrd (InsOrdHashMap)
46import qualified Data.HashMap.Strict.InsOrd as InsOrdHashMap
47import qualified Data.HashMap.Strict.InsOrd as InsOrdHashMap
@@ -774,6 +775,20 @@ data Header = Header
774 , _headerSchema :: Maybe (Referenced Schema)
775 , _headerSchema :: Maybe (Referenced Schema)
775 } deriving (Eq, Show, Generic, Data, Typeable)
776 } deriving (Eq, Show, Generic, Data, Typeable)
776
777
778+-- | According to RFC7235
779+data HttpScheme
780+ = Basic
781+ | Bearer
782+ | Digest
783+ | HOBA
784+ | Mutual
785+ | Negotiate
786+ | OAuth
787+ | SCRAM_SHA_1
788+ | SCRAM_SHA_256
789+ | Vapid
790+ deriving (Eq, Show, Generic, Data, Typeable)
791+
777-- | The location of the API key.
792-- | The location of the API key.
778data ApiKeyLocation
793data ApiKeyLocation
779 = ApiKeyQuery
794 = ApiKeyQuery
@@ -839,7 +854,7 @@ data OAuth2Flows = OAuth2Flows
839 } deriving (Eq, Show, Generic, Data, Typeable)
854 } deriving (Eq, Show, Generic, Data, Typeable)
840
855
841data SecuritySchemeType
856data SecuritySchemeType
842− = SecuritySchemeHttp
857+ = SecuritySchemeHttp HttpScheme
843 | SecuritySchemeApiKey ApiKeyParams
858 | SecuritySchemeApiKey ApiKeyParams
844 | SecuritySchemeOAuth2 OAuth2Flows
859 | SecuritySchemeOAuth2 OAuth2Flows
845 | SecuritySchemeOpenIdConnect URL
860 | SecuritySchemeOpenIdConnect URL
@@ -1127,6 +1142,13 @@ instance ToJSON License where
1127instance ToJSON ServerVariable where
1142instance ToJSON ServerVariable where
1128 toJSON = genericToJSON (jsonPrefix "ServerVariable")
1143 toJSON = genericToJSON (jsonPrefix "ServerVariable")
1129
1144
1145+instance ToJSON HttpScheme where
1146+ toJSON scheme = case scheme of
1147+ SCRAM_SHA_1 -> "SCRAM-SHA-1"
1148+ SCRAM_SHA_256 -> "SCRAM-SHA-256"
1149+ Vapid -> "vapid"
1150+ other -> genericToJSON defaultOptions other
1151+
1130instance ToJSON ApiKeyLocation where
1152instance ToJSON ApiKeyLocation where
1131 toJSON = genericToJSON (jsonPrefix "ApiKey")
1153 toJSON = genericToJSON (jsonPrefix "ApiKey")
1132
1154
@@ -1182,6 +1204,13 @@ instance FromJSON License where
1182instance FromJSON ServerVariable where
1204instance FromJSON ServerVariable where
1183 parseJSON = genericParseJSON (jsonPrefix "ServerVariable")
1205 parseJSON = genericParseJSON (jsonPrefix "ServerVariable")
1184
1206
1207+instance FromJSON HttpScheme where
1208+ parseJSON = withText "HttpScheme" $ \txt -> case txt of
1209+ "SCRAM-SHA-1" -> pure SCRAM_SHA_1
1210+ "SCRAM-SHA-256" -> pure SCRAM_SHA_256
1211+ "vapid" -> pure Vapid
1212+ _ -> genericParseJSON defaultOptions $ String txt
1213+
1185instance FromJSON ApiKeyLocation where
1214instance FromJSON ApiKeyLocation where
1186 parseJSON = genericParseJSON (jsonPrefix "ApiKey")
1215 parseJSON = genericParseJSON (jsonPrefix "ApiKey")
1187
1216
@@ -1229,8 +1258,8 @@ instance ToJSON OAuth2Flows where
1229 toEncoding = sopSwaggerGenericToEncoding
1258 toEncoding = sopSwaggerGenericToEncoding
1230
1259
1231instance ToJSON SecuritySchemeType where
1260instance ToJSON SecuritySchemeType where
1232− toJSON SecuritySchemeHttp
1261+ toJSON (SecuritySchemeHttp scheme)
1233− = object [ "type" .= ("http" :: Text) ]
1262+ = object [ "type" .= ("http" :: Text), "scheme" .= toJSON scheme ]
1234 toJSON (SecuritySchemeApiKey params)
1263 toJSON (SecuritySchemeApiKey params)
1235 = toJSON params
1264 = toJSON params
1236 <+> object [ "type" .= ("apiKey" :: Text) ]
1265 <+> object [ "type" .= ("apiKey" :: Text) ]
@@ -1379,7 +1408,7 @@ instance FromJSON SecuritySchemeType where
1379 parseJSON js@(Object o) = do
1408 parseJSON js@(Object o) = do
1380 (t :: Text) <- o .: "type"
1409 (t :: Text) <- o .: "type"
1381 case t of
1410 case t of
1382− "http" -> pure SecuritySchemeHttp
1411+ "http" -> SecuritySchemeHttp <$> o .: "scheme"
1383 "apiKey" -> SecuritySchemeApiKey <$> parseJSON js
1412 "apiKey" -> SecuritySchemeApiKey <$> parseJSON js
1384 "oauth2" -> SecuritySchemeOAuth2 <$> (o .: "flows")
1413 "oauth2" -> SecuritySchemeOAuth2 <$> (o .: "flows")
1385 "openIdConnect" -> SecuritySchemeOpenIdConnect <$> (o .: "openIdConnectUrl")
1414 "openIdConnect" -> SecuritySchemeOpenIdConnect <$> (o .: "openIdConnectUrl")
@@ -1550,3 +1579,6 @@ instance AesonDefaultValue MimeList where defaultValue = Just mempty
1550instance AesonDefaultValue Info
1579instance AesonDefaultValue Info
1551instance AesonDefaultValue ParamLocation
1580instance AesonDefaultValue ParamLocation
1552instance AesonDefaultValue Link
1581instance AesonDefaultValue Link
1582+
1583+instance Arbitrary HttpScheme where
1584+ arbitrary = genericArbitrary
test/Data/OpenApiSpec.hs+12−2
@@ -13,9 +13,11 @@ import Data.Aeson
13import Data.Aeson.QQ.Simple
13import Data.Aeson.QQ.Simple
14import Data.HashMap.Strict (HashMap)
14import Data.HashMap.Strict (HashMap)
15import qualified Data.HashSet.InsOrd as InsOrdHS
15import qualified Data.HashSet.InsOrd as InsOrdHS
16+import Data.Proxy
16import Data.Text (Text)
17import Data.Text (Text)
17
18
18import Data.OpenApi
19import Data.OpenApi
20+import Data.OpenApi.Internal
19import SpecCommon
21import SpecCommon
20import Test.Hspec hiding (example)
22import Test.Hspec hiding (example)
21
23
@@ -45,6 +47,7 @@ spec = do
45 fromJSON petstoreExampleJSON `shouldSatisfy` (\x -> case x of Success (_ :: OpenApi) -> True; _ -> False)
47 fromJSON petstoreExampleJSON `shouldSatisfy` (\x -> case x of Success (_ :: OpenApi) -> True; _ -> False)
46 it "roundtrips: fmap toJSON . fromJSON" $ do
48 it "roundtrips: fmap toJSON . fromJSON" $ do
47 (toJSON :: OpenApi -> Value) <$> fromJSON petstoreExampleJSON `shouldBe` Success petstoreExampleJSON
49 (toJSON :: OpenApi -> Value) <$> fromJSON petstoreExampleJSON `shouldBe` Success petstoreExampleJSON
50+ testJsonIdempotency (Proxy :: Proxy HttpScheme)
48
51
49main :: IO ()
52main :: IO ()
50main = hspec spec
53main = hspec spec
@@ -456,7 +459,10 @@ securityDefinitionsExample = SecurityDefinitions
456 , _oAuth2Scopes =
459 , _oAuth2Scopes =
457 [ ("write:pets", "modify pets in your account")
460 [ ("write:pets", "modify pets in your account")
458 , ("read:pets", "read your pets") ] } )
461 , ("read:pets", "read your pets") ] } )
459− , _securitySchemeDescription = Nothing }) ]
462+ , _securitySchemeDescription = Nothing })
463+ , ("basic", SecurityScheme
464+ { _securitySchemeType = SecuritySchemeHttp Basic
465+ , _securitySchemeDescription = Nothing })]
460
466
461securityDefinitionsExampleJSON :: Value
467securityDefinitionsExampleJSON :: Value
462securityDefinitionsExampleJSON = [aesonQQ|
468securityDefinitionsExampleJSON = [aesonQQ|
@@ -477,7 +483,11 @@ securityDefinitionsExampleJSON = [aesonQQ|
477 "authorizationUrl": "http://swagger.io/api/oauth/dialog"
483 "authorizationUrl": "http://swagger.io/api/oauth/dialog"
478 }
484 }
479 }
485 }
480− }
486+ },
487+ "basic": {
488+ "type": "http",
489+ "scheme": "Basic"
490+ }
481}
491}
482
492
483|]
493|]
test/SpecCommon.hs+11
@@ -4,9 +4,12 @@ import Data.Aeson
4import Data.ByteString.Builder (toLazyByteString)
4import Data.ByteString.Builder (toLazyByteString)
5import qualified Data.Foldable as F
5import qualified Data.Foldable as F
6import qualified Data.HashMap.Strict as HashMap
6import qualified Data.HashMap.Strict as HashMap
7+import Data.Proxy
8+import Data.Typeable
7import qualified Data.Vector as Vector
9import qualified Data.Vector as Vector
8
10
9import Test.Hspec
11import Test.Hspec
12+import Test.QuickCheck (Arbitrary, property)
10
13
11isSubJSON :: Value -> Value -> Bool
14isSubJSON :: Value -> Value -> Bool
12isSubJSON Null _ = True
15isSubJSON Null _ = True
@@ -28,3 +31,11 @@ x <=> js = do
28 eitherDecode (encode $ toJSON x) `shouldBe` Right x
31 eitherDecode (encode $ toJSON x) `shouldBe` Right x
29 it "roundtrips with toEncoding" $ do
32 it "roundtrips with toEncoding" $ do
30 eitherDecode (toLazyByteString $ fromEncoding $ toEncoding x) `shouldBe` Right x
33 eitherDecode (toLazyByteString $ fromEncoding $ toEncoding x) `shouldBe` Right x
34+
35+testJsonIdempotency :: (Eq a, Show a, Arbitrary a, FromJSON a, ToJSON a, Typeable a, HasCallStack) =>
36+ Proxy a -> Spec
37+testJsonIdempotency px = describe (show ty) $ do
38+ it "roundtrips: decode . encode" $ property $ \x ->
39+ decode (encode x) == Just (x `asProxyTypeOf` px)
40+ where
41+ ty = typeOf $ undefined `asProxyTypeOf` px