@@ -1,33 +1,5 @@
1−{-# LANGUAGE CPP #-}
21{-# OPTIONS_GHC -Wno-orphans #-}
32
4−-- | __Example:__
5−--
6−-- >>> :set -XDerivingStrategies -XDerivingVia -XDeriveGeneric
7−--
8−-- >>> :{
9−-- data User = User
10−-- { userFirstName :: String,
11−-- userAge :: Maybe Integer
12−-- }
13−-- deriving stock (Generic)
14−-- deriving (FromJSON, ToJSON, ToSchema)
15−-- via CustomJSON
16−-- '[FieldLabelModifier '[StripPrefix "user", CamelToSnake], RejectUnknownFields]
17−-- User
18−-- showYaml = Data.ByteString.Char8.putStr . Data.Yaml.encode
19−-- :}
20−--
21−-- >>> showYaml $ toSchema (Proxy :: Proxy User)
22−-- type: object
23−-- properties:
24−-- first_name:
25−-- type: string
26−-- age:
27−-- type: integer
28−-- required:
29−-- - first_name
30−-- additionalProperties: false
313module Deriving.OpenApi
324 ( CustomOpenApi,
335 DatatypeNameModifier,
@@ -36,104 +8,65 @@ module Deriving.OpenApi
368 )
379where
3810
39−import Control.Lens
4011import qualified Data.Aeson.Types as A
12+import Data.Kind
4113import Data.OpenApi
42−import Data.OpenApi.Internal.ParamSchema
4314import Data.OpenApi.Internal.Schema
4415import Data.Proxy
45−import Data.Text (Text)
46−import qualified Data.Text as T
47−import Data.Typeable
4816import Deriving.Aeson
4917import GHC.Generics
5018import GHC.TypeLits
5119
52−data Description (desc :: Symbol) = Description
53−
54−instance (AesonOptions xs) => AesonOptions (Description f ': xs) where
55− aesonOptions = aesonOptions @xs
56−
57−instance KnownSymbol t => OpenApiOptionModifier (Description t) where
58− openApiSchemaModifier = schema . description <>~ Just (toTextLine @t)
59−
60−toTextLine :: forall s. KnownSymbol s => Text
61−toTextLine = "\n\n" <> T.pack (symbolVal (Proxy @s))
62−
63−-- $setup
64−-- >>> import qualified Data.Yaml
65−-- >>> import qualified Data.ByteString.Char8
66−
6720type CustomOpenApi = CustomJSON
6821
69−instance
70− (OpenApiOptionModifier xs, GToSchema (Rep x), Generic x, Typeable x, Typeable xs, Typeable k) =>
71− ToSchema (CustomJSON (xs :: k) x)
72− where
73− declareNamedSchema Proxy =
74− openApiSchemaModifier @xs
75− <$> genericDeclareNamedSchema (openApiOptionsModifier @xs defaultSchemaOptions) (Proxy @x)
76−
77−instance
78− (OpenApiOptionModifier xs, GToParamSchema (Rep x), Generic x) =>
79− ToParamSchema (CustomJSON (xs :: k) x)
80− where
81− toParamSchema Proxy =
82− genericToParamSchema (openApiOptionsModifier @xs defaultSchemaOptions) (Proxy @x)
83−
84−class OpenApiOptionModifier x where
85− openApiOptionsModifier :: SchemaOptions -> SchemaOptions
86− openApiOptionsModifier = id
87− openApiSchemaModifier :: NamedSchema -> NamedSchema
88− openApiSchemaModifier = id
22+instance (OpenApiOptions xs, GToSchema (Rep x), Generic x) => ToSchema (CustomJSON xs x) where
23+ declareNamedSchema Proxy = genericDeclareNamedSchema (openApiOptions @xs) (Proxy @x)
8924
9025data DatatypeNameModifier t
9126
92−instance (StringModifier f) => OpenApiOptionModifier (DatatypeNameModifier f) where
93− openApiOptionsModifier o = o {datatypeNameModifier = getStringModifier @f}
94−
95−instance (AesonOptions xs) => AesonOptions (DatatypeNameModifier f ': xs) where
96− aesonOptions = aesonOptions @xs
27+instance (StringModifier f, OpenApiOptions xs) => OpenApiOptions (DatatypeNameModifier f ': xs) where
28+ openApiOptions = (openApiOptions @xs) {datatypeNameModifier = getStringModifier @f}
9729
9830-- deriving-aeson-based instances
9931
100−instance OpenApiOptionModifier UnwrapUnaryRecords where
101− openApiOptionsModifier o = o {unwrapUnaryRecords = True}
32+class OpenApiOptions (xs :: [Type]) where
33+ openApiOptions :: SchemaOptions
10234
103−instance OpenApiOptionModifier OmitNothingFields
35+instance OpenApiOptions '[] where
36+ openApiOptions = defaultSchemaOptions
10437
105−#if MIN_VERSION_deriving_aeson(0,2,4)
106−instance OpenApiOptionModifier RejectUnknownFields where
107− openApiSchemaModifier = schema . additionalProperties .~ Just (AdditionalPropertiesAllowed False)
108−#endif
38+instance OpenApiOptions xs => OpenApiOptions (UnwrapUnaryRecords ': xs) where
39+ openApiOptions = (openApiOptions @xs) {unwrapUnaryRecords = True}
10940
110−instance StringModifier f => OpenApiOptionModifier (FieldLabelModifier f) where
111− openApiOptionsModifier o = o {fieldLabelModifier = getStringModifier @f}
41+instance OpenApiOptions xs => OpenApiOptions (OmitNothingFields ': xs) where
42+ openApiOptions = openApiOptions @xs
11243
113−instance StringModifier f => OpenApiOptionModifier (ConstructorTagModifier f) where
114− openApiOptionsModifier o = o {constructorTagModifier = getStringModifier @f}
44+instance OpenApiOptions xs => OpenApiOptions (RejectUnknownFields ': xs) where
45+ openApiOptions = openApiOptions @xs
11546
116−instance
117− TypeError ('Text "deriving-openapi3 does not currently the `TagSingleConstructors` modifier.") =>
118− OpenApiOptionModifier TagSingleConstructors
47+instance (StringModifier f, OpenApiOptions xs) => OpenApiOptions (FieldLabelModifier f ': xs) where
48+ openApiOptions = (openApiOptions @xs) {fieldLabelModifier = getStringModifier @f}
11949
120−instance OpenApiOptionModifier NoAllNullaryToStringTag where
121− openApiOptionsModifier o = o {allNullaryToStringTag = False}
50+instance (StringModifier f, OpenApiOptions xs) => OpenApiOptions (ConstructorTagModifier f ': xs) where
51+ openApiOptions = (openApiOptions @xs) {constructorTagModifier = getStringModifier @f}
12252
123−instance (KnownSymbol t, KnownSymbol c) => OpenApiOptionModifier (SumTaggedObject t c) where
124− openApiOptionsModifier o = o {sumEncoding = A.TaggedObject (symbolVal (Proxy @t)) (symbolVal (Proxy @c))}
53+instance
54+ (OpenApiOptions xs, TypeError ( 'Text "openapi3-deriving does not currently the `TagSingleConstructors` modifier.")) =>
55+ OpenApiOptions (TagSingleConstructors ': xs)
56+ where
57+ openApiOptions = undefined
12558
126−instance OpenApiOptionModifier SumUntaggedValue where
127− openApiOptionsModifier o = o {sumEncoding = A.UntaggedValue}
59+instance OpenApiOptions xs => OpenApiOptions (NoAllNullaryToStringTag ': xs) where
60+ openApiOptions = (openApiOptions @xs) {allNullaryToStringTag = False}
12861
129−instance OpenApiOptionModifier SumObjectWithSingleField where
130− openApiOptionsModifier o = o {sumEncoding = A.ObjectWithSingleField}
62+instance (KnownSymbol t, KnownSymbol c, OpenApiOptions xs) => OpenApiOptions (SumTaggedObject t c ': xs) where
63+ openApiOptions = (openApiOptions @xs) {sumEncoding = A.TaggedObject (symbolVal (Proxy @t)) (symbolVal (Proxy @c))}
13164
132−instance OpenApiOptionModifier SumTwoElemArray where
133− openApiOptionsModifier o = o {sumEncoding = A.TwoElemArray}
65+instance (OpenApiOptions xs) => OpenApiOptions (SumUntaggedValue ': xs) where
66+ openApiOptions = (openApiOptions @xs) {sumEncoding = A.UntaggedValue}
13467
135−instance OpenApiOptionModifier '[]
68+instance (OpenApiOptions xs) => OpenApiOptions (SumObjectWithSingleField ': xs) where
69+ openApiOptions = (openApiOptions @xs) {sumEncoding = A.ObjectWithSingleField}
13670
137−instance (OpenApiOptionModifier x, OpenApiOptionModifier xs) => OpenApiOptionModifier (x ': xs) where
138− openApiOptionsModifier = openApiOptionsModifier @xs . openApiOptionsModifier @x
139− openApiSchemaModifier = openApiSchemaModifier @xs . openApiSchemaModifier @x
71+instance (OpenApiOptions xs) => OpenApiOptions (SumTwoElemArray ': xs) where
72+ openApiOptions = (openApiOptions @xs) {sumEncoding = A.TwoElemArray}