Normalize params and responses

This commit is contained in:
Alex Biehl 2022-02-21 11:36:38 +01:00
parent c1c9b1fdb4
commit 9f7e58dad3
9 changed files with 123 additions and 9 deletions

View File

@ -49,6 +49,7 @@ import Tie.Name
import Tie.Operation import Tie.Operation
( Operation (..), ( Operation (..),
errors, errors,
normalizeOperation,
operationResponseDependencies, operationResponseDependencies,
operationSchemaDependencies, operationSchemaDependencies,
pathItemsToOperation, pathItemsToOperation,
@ -185,19 +186,24 @@ generate write packageName apiName inputFile = do
for_ operations $ \operation@Operation {name} -> do for_ operations $ \operation@Operation {name} -> do
let path = toResponseHaskellFileName apiName name let path = toResponseHaskellFileName apiName name
header = codegenModuleHeader (toResponseHaskellModuleName apiName name) header = codegenModuleHeader (toResponseHaskellModuleName apiName name)
importsCode =
dependencyCode =
codegenSchemaDependencies apiName $ codegenSchemaDependencies apiName $
nubOrd (operationSchemaDependencies shallow operation) nubOrd (operationSchemaDependencies shallow operation)
(operation, inlineDefinitions) <-
normalizeOperation operation
codeForInlineDefinitions <-
traverse (uncurry codegenSchema) inlineDefinitions
responsesCode <- codegenResponses resolver operation responsesCode <- codegenResponses resolver operation
write path $ write path $
vsep vsep
[ header, [ header,
mempty, mempty,
dependencyCode, importsCode,
mempty, mempty,
codegenExtraResponseModuleDependencies apiName, codegenExtraResponseModuleDependencies apiName,
mempty, mempty,
vsep codeForInlineDefinitions,
mempty,
responsesCode responsesCode
] ]

View File

@ -35,6 +35,9 @@ module Tie.Name
inlineObjectTypeName, inlineObjectTypeName,
inlineVariantTypeName, inlineVariantTypeName,
inlineArrayElementTypeName, inlineArrayElementTypeName,
operationParamTypeName,
apiResponseConstructorName,
apiDefaultResponseConstructorName,
) )
where where
@ -85,7 +88,7 @@ toSchemaHaskellFileName apiName (Name name) =
haskellModuleToFilePath apiName <> "/Schemas/" <> capitalizeFirstLetter (Text.unpack name) <> ".hs" haskellModuleToFilePath apiName <> "/Schemas/" <> capitalizeFirstLetter (Text.unpack name) <> ".hs"
haskellModuleToFilePath :: ApiName -> FilePath haskellModuleToFilePath :: ApiName -> FilePath
haskellModuleToFilePath = haskellModuleToFilePath =
Text.unpack . Text.replace "." "/" Text.unpack . Text.replace "." "/"
toOperationHaskellModuleName :: ApiName -> Name -> Text toOperationHaskellModuleName :: ApiName -> Name -> Text
@ -146,6 +149,15 @@ toParamBinder :: Name -> PP.Doc ann
toParamBinder = toParamBinder =
PP.pretty . Text.pack . escapeKeyword . lowerFirstLetter . Text.unpack . unName PP.pretty . Text.pack . escapeKeyword . lowerFirstLetter . Text.unpack . unName
operationParamTypeName :: Name -> Name -> Name
operationParamTypeName (Name operationName) (Name paramName) =
Name $
Text.pack $
escapeKeyword $
capitalizeFirstLetter (Text.unpack operationName)
<> capitalizeFirstLetter (Text.unpack paramName)
<> "Param"
toApiMemberName :: Name -> PP.Doc ann toApiMemberName :: Name -> PP.Doc ann
toApiMemberName = toApiMemberName =
PP.pretty . Text.pack . escapeKeyword . lowerFirstLetter . Text.unpack . unName PP.pretty . Text.pack . escapeKeyword . lowerFirstLetter . Text.unpack . unName
@ -158,10 +170,18 @@ toApiResponseConstructorName :: Name -> Int -> PP.Doc ann
toApiResponseConstructorName name statusCode = toApiResponseConstructorName name statusCode =
PP.pretty . Text.pack . escapeKeyword . (<> show statusCode) . (<> "Response") . capitalizeFirstLetter . Text.unpack . unName $ name PP.pretty . Text.pack . escapeKeyword . (<> show statusCode) . (<> "Response") . capitalizeFirstLetter . Text.unpack . unName $ name
apiResponseConstructorName :: Name -> Int -> Name
apiResponseConstructorName name statusCode =
Name . Text.pack . escapeKeyword . (<> show statusCode) . (<> "Response") . capitalizeFirstLetter . Text.unpack . unName $ name
toApiDefaultResponseConstructorName :: Name -> PP.Doc ann toApiDefaultResponseConstructorName :: Name -> PP.Doc ann
toApiDefaultResponseConstructorName name = toApiDefaultResponseConstructorName name =
PP.pretty . Text.pack . escapeKeyword . (<> "DefaultResponse") . capitalizeFirstLetter . Text.unpack . unName $ name PP.pretty . Text.pack . escapeKeyword . (<> "DefaultResponse") . capitalizeFirstLetter . Text.unpack . unName $ name
apiDefaultResponseConstructorName :: Name -> Name
apiDefaultResponseConstructorName name =
Name . Text.pack . escapeKeyword . (<> "DefaultResponse") . capitalizeFirstLetter . Text.unpack . unName $ name
toEnumConstructorName :: Name -> Text -> PP.Doc ann toEnumConstructorName :: Name -> Text -> PP.Doc ann
toEnumConstructorName (Name typName) variant = toEnumConstructorName (Name typName) variant =
PP.pretty $ PP.pretty $

View File

@ -6,6 +6,7 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-}
module Tie.Operation module Tie.Operation
( StatusCode, ( StatusCode,
@ -28,13 +29,23 @@ module Tie.Operation
-- * Dependencies -- * Dependencies
operationSchemaDependencies, operationSchemaDependencies,
operationResponseDependencies, operationResponseDependencies,
-- * Normalization
normalizeOperation,
) )
where where
import Control.Monad.Writer (WriterT (..), runWriterT)
import qualified Data.HashMap.Strict.InsOrd as InsOrd import qualified Data.HashMap.Strict.InsOrd as InsOrd
import qualified Data.OpenApi as OpenApi import qualified Data.OpenApi as OpenApi
import qualified Data.Text as Text import qualified Data.Text as Text
import Tie.Name (Name, fromText) import Tie.Name
( Name,
apiDefaultResponseConstructorName,
apiResponseConstructorName,
fromText,
operationParamTypeName,
)
import Tie.Resolve (Resolver, resolve) import Tie.Resolve (Resolver, resolve)
import Tie.Type import Tie.Type
( Named, ( Named,
@ -42,6 +53,7 @@ import Tie.Type
isBasicType, isBasicType,
namedType, namedType,
namedTypeDependencies, namedTypeDependencies,
normalizeNamedType,
schemaRefToType, schemaRefToType,
) )
import Prelude hiding (Type) import Prelude hiding (Type)
@ -366,3 +378,41 @@ pathToPath resolver errors@Errors {..} textualPath params = do
(isBasicType (namedType (schema param))) (isBasicType (namedType (schema param)))
paramNotBasicType paramNotBasicType
pure param pure param
normalizeParam :: Monad m => Name -> Param -> m (Param, [(Name, Type)])
normalizeParam operationName param@Param {..} = do
(normedType, inlineDefinitions) <-
normalizeNamedType
(pure (operationParamTypeName operationName name))
schema
pure (param {schema = normedType}, inlineDefinitions)
normalizeResponse :: Monad m => Name -> Response -> m (Response, [(Name, Type)])
normalizeResponse name response@Response {..} = do
(normedType, inlineDefinitions) <- normalizeNamedType (pure name) jsonResponseContent
pure (response {jsonResponseContent = normedType}, inlineDefinitions)
normalizeOperation :: Monad m => Operation -> m (Operation, [(Name, Type)])
normalizeOperation operation@Operation {..} = runWriterT $ do
queryParams <-
traverse
(WriterT . normalizeParam name)
queryParams
headerParams <-
traverse
(WriterT . normalizeParam name)
headerParams
defaultResponse <-
traverse
(WriterT . normalizeResponse (apiDefaultResponseConstructorName name))
defaultResponse
responses <-
traverse
( \(status, response) ->
( (status,)
<$> WriterT
(normalizeResponse (apiResponseConstructorName name status) response)
)
)
responses
pure Operation {..}

View File

@ -28,10 +28,8 @@ module Tie.Type
isOneOfType, isOneOfType,
-- * Normalize types -- * Normalize types
-- normalizeObjectType,
-- normalizeVariants,
normalizeType, normalizeType,
normalizeNamedType,
-- * Dependencies -- * Dependencies
namedTypeDependencies, namedTypeDependencies,

View File

@ -115,6 +115,8 @@ import Test.Schemas.Test
import Test.Response import Test.Response
data TestResponse data TestResponse
= TestResponse200 Test = TestResponse200 Test

View File

@ -129,8 +129,28 @@ import qualified Web.HttpApiData
import Test.Response import Test.Response
data ListPackagesResponse200
= ListPackagesResponse200A
| ListPackagesResponse200B
| ListPackagesResponse200C
deriving (Eq, Show)
instance Data.Aeson.ToJSON ListPackagesResponse200 where
toJSON x = case x of
ListPackagesResponse200A -> "A"
ListPackagesResponse200B -> "B"
ListPackagesResponse200C -> "C"
instance Data.Aeson.FromJSON ListPackagesResponse200 where
parseJSON = Data.Aeson.withText "ListPackagesResponse200" $ \s ->
case s of
"A" -> pure ListPackagesResponse200A
"B" -> pure ListPackagesResponse200B
"C" -> pure ListPackagesResponse200C
_ -> fail "invalid enum value"
data ListPackagesResponse data ListPackagesResponse
= ListPackagesResponse200 error: Enum = ListPackagesResponse200 ListPackagesResponse200
instance ToResponse ListPackagesResponse where instance ToResponse ListPackagesResponse where
toResponse (ListPackagesResponse200 x) = toResponse (ListPackagesResponse200 x) =
@ -166,6 +186,8 @@ import Test.Schemas.Package
import Test.Response import Test.Response
data ListPackagesResponse data ListPackagesResponse
= ListPackagesResponse200 Package = ListPackagesResponse200 Package

View File

@ -143,6 +143,8 @@ import Test.Schemas.Packages
import Test.Response import Test.Response
data ListPackagesResponse data ListPackagesResponse
= ListPackagesResponse200 Packages = ListPackagesResponse200 Packages
@ -180,6 +182,8 @@ import Test.Schemas.Package
import Test.Response import Test.Response
data ListPackages2Response data ListPackages2Response
= ListPackages2Response200 [ Package ] = ListPackages2Response200 [ Package ]
@ -217,6 +221,8 @@ import Test.Schemas.Inline
import Test.Response import Test.Response
data ListPackages3Response data ListPackages3Response
= ListPackages3Response200 [ Inline ] = ListPackages3Response200 [ Inline ]

View File

@ -143,6 +143,8 @@ import Test.Schemas.Packages
import Test.Response import Test.Response
data ListPackagesResponse data ListPackagesResponse
= ListPackagesResponse200 Packages = ListPackagesResponse200 Packages
@ -180,6 +182,8 @@ import Test.Schemas.Inline
import Test.Response import Test.Response
data ListPackages2Response data ListPackages2Response
= ListPackages2Response200 Inline = ListPackages2Response200 Inline
@ -217,6 +221,8 @@ import Test.Schemas.Inline2
import Test.Response import Test.Response
data ListPackages2Response data ListPackages2Response
= ListPackages2Response200 Inline2 = ListPackages2Response200 Inline2

View File

@ -178,6 +178,8 @@ import Test.Schemas.Vehicle
import Test.Response import Test.Response
data CreateUserResponse data CreateUserResponse
= CreateUserResponse200 Vehicle = CreateUserResponse200 Vehicle
@ -215,6 +217,8 @@ import Test.Schemas.Vehicle
import Test.Response import Test.Response
data GetUserResponse data GetUserResponse
= GetUserResponse200 Vehicle = GetUserResponse200 Vehicle