Haskell: JSON Query parameters (#18047)

* Allow json encoded query paramters

* Also fix haskell-http-client

* Regenerate haskell samples
This commit is contained in:
Timo von Holtz 2024-03-12 02:35:18 -05:00 committed by GitHub
parent 6251aa17ef
commit 5975e6c5b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 2683 additions and 70 deletions

View File

@ -1,6 +1,6 @@
generatorName: haskell-http-client generatorName: haskell-http-client
outputDir: samples/client/petstore/haskell-http-client outputDir: samples/client/petstore/haskell-http-client
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml inputSpec: modules/openapi-generator/src/test/resources/3_0/haskell-http-client/petstore-with-fake-endpoints-models-for-testing.yaml
templateDir: modules/openapi-generator/src/main/resources/haskell-http-client templateDir: modules/openapi-generator/src/main/resources/haskell-http-client
additionalProperties: additionalProperties:
queryExtraUnreserved: '' queryExtraUnreserved: ''

View File

@ -745,11 +745,16 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
param.vendorExtensions.put(VENDOR_EXTENSION_X_IS_BODY_OR_FORM_PARAM, param.isBodyParam || param.isFormParam); param.vendorExtensions.put(VENDOR_EXTENSION_X_IS_BODY_OR_FORM_PARAM, param.isBodyParam || param.isFormParam);
if (!StringUtils.isBlank(param.collectionFormat)) { if (!StringUtils.isBlank(param.collectionFormat)) {
param.vendorExtensions.put(VENDOR_EXTENSION_X_COLLECTION_FORMAT, mapCollectionFormat(param.collectionFormat)); param.vendorExtensions.put(VENDOR_EXTENSION_X_COLLECTION_FORMAT, mapCollectionFormat(param.collectionFormat));
} else if (!param.isBodyParam && (param.isArray || param.dataType.startsWith("["))) { // param.isArray is sometimes false for list types } else if (!param.isBodyParam) {
if (param.isArray || param.dataType.startsWith("[")) { // param.isArray is sometimes false for list types
// defaulting due to https://github.com/wing328/openapi-generator/issues/72 // defaulting due to https://github.com/wing328/openapi-generator/issues/72
param.collectionFormat = "csv"; param.collectionFormat = "csv";
param.vendorExtensions.put(VENDOR_EXTENSION_X_COLLECTION_FORMAT, mapCollectionFormat(param.collectionFormat)); param.vendorExtensions.put(VENDOR_EXTENSION_X_COLLECTION_FORMAT, mapCollectionFormat(param.collectionFormat));
} }
}
if (param.isQueryParam && (isJsonMimeType(param.contentType) || ContainsJsonMimeType(param.contentType))) {
param.vendorExtensions.put(X_MEDIA_IS_JSON, "true");
}
if (!param.required) { if (!param.required) {
op.vendorExtensions.put(VENDOR_EXTENSION_X_HAS_OPTIONAL_PARAMS, true); op.vendorExtensions.put(VENDOR_EXTENSION_X_HAS_OPTIONAL_PARAMS, true);
} }

View File

@ -514,6 +514,13 @@ public class HaskellServantCodegen extends DefaultCodegen implements CodegenConf
// Query parameters appended to routes // Query parameters appended to routes
for (CodegenParameter param : op.queryParams) { for (CodegenParameter param : op.queryParams) {
String paramType = param.dataType; String paramType = param.dataType;
if (param.contentType == "application/json") {
if (param.isArray) {
paramType = "[JSONQueryParam " + paramType.substring(1, paramType.length() - 1) + "]";
} else {
paramType = "(JSONQueryParam " + paramType + ")";
}
}
if (param.isArray) { if (param.isArray) {
if (StringUtils.isEmpty(param.collectionFormat)) { if (StringUtils.isEmpty(param.collectionFormat)) {
param.collectionFormat = "csv"; param.collectionFormat = "csv";
@ -549,6 +556,13 @@ public class HaskellServantCodegen extends DefaultCodegen implements CodegenConf
path.add("Header \"" + param.baseName + "\" " + param.dataType); path.add("Header \"" + param.baseName + "\" " + param.dataType);
String paramType = param.dataType; String paramType = param.dataType;
if (param.contentType == "application/json") {
if (param.isArray) {
paramType = "(JSONQueryParam " + paramType.substring(1, paramType.length() - 1) + ")";
} else {
paramType = "(JSONQueryParam " + paramType + ")";
}
}
if (param.isArray) { if (param.isArray) {
if (StringUtils.isEmpty(param.collectionFormat)) { if (StringUtils.isEmpty(param.collectionFormat)) {
param.collectionFormat = "csv"; param.collectionFormat = "csv";

View File

@ -41,6 +41,7 @@ import qualified Data.Maybe as P
import qualified Data.Proxy as P (Proxy(..)) import qualified Data.Proxy as P (Proxy(..))
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Encoding as T import qualified Data.Text.Encoding as T
import qualified Data.Text.Lazy.Encoding as TL
import qualified Data.Time as TI import qualified Data.Time as TI
import qualified Data.Time.ISO8601 as TI import qualified Data.Time.ISO8601 as TI
import qualified GHC.Base as P (Alternative) import qualified GHC.Base as P (Alternative)
@ -330,6 +331,9 @@ toQuery :: WH.ToHttpApiData a => (BC.ByteString, Maybe a) -> [NH.QueryItem]
toQuery x = [(fmap . fmap) toQueryParam x] toQuery x = [(fmap . fmap) toQueryParam x]
where toQueryParam = T.encodeUtf8 . WH.toQueryParam where toQueryParam = T.encodeUtf8 . WH.toQueryParam
toJsonQuery :: A.ToJSON a => (BC.ByteString, Maybe a) -> [NH.QueryItem]
toJsonQuery = toQuery . (fmap . fmap) (TL.decodeUtf8 . A.encode)
toPartialEscapeQuery :: B.ByteString -> NH.Query -> NH.PartialEscapeQuery toPartialEscapeQuery :: B.ByteString -> NH.Query -> NH.PartialEscapeQuery
toPartialEscapeQuery extraUnreserved query = fmap (\(k, v) -> (k, maybe [] go v)) query toPartialEscapeQuery extraUnreserved query = fmap (\(k, v) -> (k, maybe [] go v)) query
where go :: B.ByteString -> [NH.EscapeItem] where go :: B.ByteString -> [NH.EscapeItem]
@ -362,6 +366,9 @@ toFormColl c xs = WH.toForm $ fmap unpack $ _toColl c toHeader $ pack xs
toQueryColl :: WH.ToHttpApiData a => CollectionFormat -> (BC.ByteString, Maybe [a]) -> NH.Query toQueryColl :: WH.ToHttpApiData a => CollectionFormat -> (BC.ByteString, Maybe [a]) -> NH.Query
toQueryColl c xs = _toCollA c toQuery xs toQueryColl c xs = _toCollA c toQuery xs
toJsonQueryColl :: A.ToJSON a => CollectionFormat -> (BC.ByteString, Maybe [a]) -> NH.Query
toJsonQueryColl c xs = _toCollA c toJsonQuery xs
_toColl :: P.Traversable f => CollectionFormat -> (f a -> [(b, BC.ByteString)]) -> f [a] -> [(b, BC.ByteString)] _toColl :: P.Traversable f => CollectionFormat -> (f a -> [(b, BC.ByteString)]) -> f [a] -> [(b, BC.ByteString)]
_toColl c encode xs = fmap (fmap P.fromJust) (_toCollA' c fencode BC.singleton (fmap Just xs)) _toColl c encode xs = fmap (fmap P.fromJust) (_toCollA' c fencode BC.singleton (fmap Just xs))
where fencode = fmap (fmap Just) . encode . fmap P.fromJust where fencode = fmap (fmap Just) . encode . fmap P.fromJust

View File

@ -7,6 +7,7 @@ Module : {{baseModule}}.Model
{-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-} {-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiParamTypeClasses #-}

View File

@ -1 +1 @@
toQuery{{#collectionFormat}}Coll {{vendorExtensions.x-collection-format}}{{/collectionFormat}} to{{#vendorExtensions.x-mediaIsJson}}Json{{/vendorExtensions.x-mediaIsJson}}Query{{#collectionFormat}}Coll {{vendorExtensions.x-collection-format}}{{/collectionFormat}}

View File

@ -47,6 +47,7 @@ import Control.Monad.Except (ExceptT, runExceptT)
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Control.Monad.Trans.Reader (ReaderT (..)) import Control.Monad.Trans.Reader (ReaderT (..))
import Data.Aeson (Value) import Data.Aeson (Value)
import qualified Data.Aeson as Aeson
{{#authMethods}} {{#authMethods}}
{{#isApiKey}} {{#isApiKey}}
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
@ -55,6 +56,7 @@ import Data.ByteString (ByteString)
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
{{/isBasicBearer}} {{/isBasicBearer}}
{{/authMethods}} {{/authMethods}}
import qualified Data.ByteString.Lazy as BSL
import Data.Coerce (coerce) import Data.Coerce (coerce)
import Data.Data (Data) import Data.Data (Data)
import Data.Function ((&)) import Data.Function ((&))
@ -64,6 +66,7 @@ import Data.Proxy (Proxy (..))
import Data.Set (Set) import Data.Set (Set)
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import Data.Time import Data.Time
import Data.UUID (UUID) import Data.UUID (UUID)
import GHC.Exts (IsString (..)) import GHC.Exts (IsString (..))
@ -166,6 +169,16 @@ instance ToHttpApiData a => ToHttpApiData (QueryList 'MultiParamArray a) where
formatSeparatedQueryList :: ToHttpApiData a => Char -> QueryList p a -> Text formatSeparatedQueryList :: ToHttpApiData a => Char -> QueryList p a -> Text
formatSeparatedQueryList char = T.intercalate (T.singleton char) . map toQueryParam . fromQueryList formatSeparatedQueryList char = T.intercalate (T.singleton char) . map toQueryParam . fromQueryList
newtype JSONQueryParam a = JSONQueryParam
{ fromJsonQueryParam :: a
} deriving (Functor, Foldable, Traversable)
instance Aeson.ToJSON a => ToHttpApiData (JSONQueryParam a) where
toQueryParam = T.decodeUtf8 . BSL.toStrict . Aeson.encode . fromJsonQueryParam
instance Aeson.FromJSON a => FromHttpApiData (JSONQueryParam a) where
parseQueryParam = either (Left . T.pack) (Right . JSONQueryParam) . Aeson.eitherDecodeStrict . T.encodeUtf8
{{#apiInfo}} {{#apiInfo}}
-- | Servant type-level API, generated from the OpenAPI spec for {{title}}. -- | Servant type-level API, generated from the OpenAPI spec for {{title}}.

View File

@ -1,6 +1,7 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-} {-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-}
module {{title}}.Types ( module {{title}}.Types (

View File

@ -1,4 +1,4 @@
resolver: lts-19.2 resolver: lts-22.12
extra-deps: [] extra-deps: []
packages: packages:
- '.' - '.'

View File

@ -157,6 +157,40 @@ paths:
- petstore_auth: - petstore_auth:
- 'read:pets' - 'read:pets'
deprecated: true deprecated: true
/pet/find:
get:
tags:
- pet
summary: Finds Pets
operationId: findPets
parameters:
- name: filter
in: query
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/PetFilter'
responses:
'200':
description: successful operation
content:
application/xml:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
'400':
description: Invalid status value
security:
- petstore_auth:
- 'read:pets'
'/pet/{petId}': '/pet/{petId}':
get: get:
tags: tags:
@ -752,3 +786,14 @@ components:
- "\"" - "\""
- "\\" - "\\"
description: description description: description
PetFilter:
type: object
properties:
tags:
type: array
items:
type: string
status:
type: array
items:
type: string

View File

@ -520,8 +520,8 @@ testQueryParameterCollectionFormat
-> OpenAPIPetstoreRequest TestQueryParameterCollectionFormat MimeNoContent NoContent MimeNoContent -> OpenAPIPetstoreRequest TestQueryParameterCollectionFormat MimeNoContent NoContent MimeNoContent
testQueryParameterCollectionFormat (Pipe pipe) (Ioutil ioutil) (Http http) (Url url) (Context context) = testQueryParameterCollectionFormat (Pipe pipe) (Ioutil ioutil) (Http http) (Url url) (Context context) =
_mkRequest "PUT" ["/fake/test-query-parameters"] _mkRequest "PUT" ["/fake/test-query-parameters"]
`addQuery` toQueryColl CommaSeparated ("pipe", Just pipe) `addQuery` toQueryColl PipeSeparated ("pipe", Just pipe)
`addQuery` toQueryColl CommaSeparated ("ioutil", Just ioutil) `addQuery` toQueryColl MultiParamArray ("ioutil", Just ioutil)
`addQuery` toQueryColl SpaceSeparated ("http", Just http) `addQuery` toQueryColl SpaceSeparated ("http", Just http)
`addQuery` toQueryColl CommaSeparated ("url", Just url) `addQuery` toQueryColl CommaSeparated ("url", Just url)
`addQuery` toQueryColl MultiParamArray ("context", Just context) `addQuery` toQueryColl MultiParamArray ("context", Just context)

View File

@ -110,6 +110,34 @@ instance HasOptionalParam DeletePet ApiKey where
instance Produces DeletePet MimeNoContent instance Produces DeletePet MimeNoContent
-- *** findPets
-- | @GET \/pet\/find@
--
-- Finds Pets
--
-- AuthMethod: 'AuthOAuthPetstoreAuth'
--
findPets
:: Accept accept -- ^ request accept ('MimeType')
-> OpenAPIPetstoreRequest FindPets MimeNoContent [Pet] accept
findPets _ =
_mkRequest "GET" ["/pet/find"]
`_hasAuthType` (P.Proxy :: P.Proxy AuthOAuthPetstoreAuth)
data FindPets
instance HasOptionalParam FindPets Filter where
applyOptionalParam req (Filter xs) =
req `addQuery` toJsonQuery ("filter", Just xs)
instance HasOptionalParam FindPets OrderBy where
applyOptionalParam req (OrderBy xs) =
req `addQuery` toJsonQueryColl CommaSeparated ("order_by", Just xs)
-- | @application/xml@
instance Produces FindPets MimeXML
-- | @application/json@
instance Produces FindPets MimeJSON
-- *** findPetsByStatus -- *** findPetsByStatus
-- | @GET \/pet\/findByStatus@ -- | @GET \/pet\/findByStatus@

View File

@ -50,6 +50,7 @@ import qualified Data.Maybe as P
import qualified Data.Proxy as P (Proxy(..)) import qualified Data.Proxy as P (Proxy(..))
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Encoding as T import qualified Data.Text.Encoding as T
import qualified Data.Text.Lazy.Encoding as TL
import qualified Data.Time as TI import qualified Data.Time as TI
import qualified Data.Time.ISO8601 as TI import qualified Data.Time.ISO8601 as TI
import qualified GHC.Base as P (Alternative) import qualified GHC.Base as P (Alternative)
@ -339,6 +340,9 @@ toQuery :: WH.ToHttpApiData a => (BC.ByteString, Maybe a) -> [NH.QueryItem]
toQuery x = [(fmap . fmap) toQueryParam x] toQuery x = [(fmap . fmap) toQueryParam x]
where toQueryParam = T.encodeUtf8 . WH.toQueryParam where toQueryParam = T.encodeUtf8 . WH.toQueryParam
toJsonQuery :: A.ToJSON a => (BC.ByteString, Maybe a) -> [NH.QueryItem]
toJsonQuery = toQuery . (fmap . fmap) (TL.decodeUtf8 . A.encode)
toPartialEscapeQuery :: B.ByteString -> NH.Query -> NH.PartialEscapeQuery toPartialEscapeQuery :: B.ByteString -> NH.Query -> NH.PartialEscapeQuery
toPartialEscapeQuery extraUnreserved query = fmap (\(k, v) -> (k, maybe [] go v)) query toPartialEscapeQuery extraUnreserved query = fmap (\(k, v) -> (k, maybe [] go v)) query
where go :: B.ByteString -> [NH.EscapeItem] where go :: B.ByteString -> [NH.EscapeItem]
@ -371,6 +375,9 @@ toFormColl c xs = WH.toForm $ fmap unpack $ _toColl c toHeader $ pack xs
toQueryColl :: WH.ToHttpApiData a => CollectionFormat -> (BC.ByteString, Maybe [a]) -> NH.Query toQueryColl :: WH.ToHttpApiData a => CollectionFormat -> (BC.ByteString, Maybe [a]) -> NH.Query
toQueryColl c xs = _toCollA c toQuery xs toQueryColl c xs = _toCollA c toQuery xs
toJsonQueryColl :: A.ToJSON a => CollectionFormat -> (BC.ByteString, Maybe [a]) -> NH.Query
toJsonQueryColl c xs = _toCollA c toJsonQuery xs
_toColl :: P.Traversable f => CollectionFormat -> (f a -> [(b, BC.ByteString)]) -> f [a] -> [(b, BC.ByteString)] _toColl :: P.Traversable f => CollectionFormat -> (f a -> [(b, BC.ByteString)]) -> f [a] -> [(b, BC.ByteString)]
_toColl c encode xs = fmap (fmap P.fromJust) (_toCollA' c fencode BC.singleton (fmap Just xs)) _toColl c encode xs = fmap (fmap P.fromJust) (_toCollA' c fencode BC.singleton (fmap Just xs))
where fencode = fmap (fmap Just) . encode . fmap P.fromJust where fencode = fmap (fmap Just) . encode . fmap P.fromJust

View File

@ -16,6 +16,7 @@ Module : OpenAPIPetstore.Model
{-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-} {-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiParamTypeClasses #-}
@ -123,6 +124,9 @@ newtype EnumQueryStringArray = EnumQueryStringArray { unEnumQueryStringArray ::
-- ** File2 -- ** File2
newtype File2 = File2 { unFile2 :: FilePath } deriving (P.Eq, P.Show) newtype File2 = File2 { unFile2 :: FilePath } deriving (P.Eq, P.Show)
-- ** Filter
newtype Filter = Filter { unFilter :: PetFilter } deriving (P.Eq, P.Show)
-- ** Http -- ** Http
newtype Http = Http { unHttp :: [Text] } deriving (P.Eq, P.Show) newtype Http = Http { unHttp :: [Text] } deriving (P.Eq, P.Show)
@ -144,6 +148,9 @@ newtype Name2 = Name2 { unName2 :: Text } deriving (P.Eq, P.Show)
-- ** Number -- ** Number
newtype Number = Number { unNumber :: Double } deriving (P.Eq, P.Show) newtype Number = Number { unNumber :: Double } deriving (P.Eq, P.Show)
-- ** OrderBy
newtype OrderBy = OrderBy { unOrderBy :: [PetOrder] } deriving (P.Eq, P.Show)
-- ** OrderId -- ** OrderId
newtype OrderId = OrderId { unOrderId :: Integer } deriving (P.Eq, P.Show) newtype OrderId = OrderId { unOrderId :: Integer } deriving (P.Eq, P.Show)
@ -1533,6 +1540,66 @@ mkPet petName petPhotoUrls =
, petStatus = Nothing , petStatus = Nothing
} }
-- ** PetFilter
-- | PetFilter
data PetFilter = PetFilter
{ petFilterTags :: !(Maybe [Text]) -- ^ "tags"
, petFilterStatus :: !(Maybe [Text]) -- ^ "status"
} deriving (P.Show, P.Eq, P.Typeable)
-- | FromJSON PetFilter
instance A.FromJSON PetFilter where
parseJSON = A.withObject "PetFilter" $ \o ->
PetFilter
<$> (o .:? "tags")
<*> (o .:? "status")
-- | ToJSON PetFilter
instance A.ToJSON PetFilter where
toJSON PetFilter {..} =
_omitNulls
[ "tags" .= petFilterTags
, "status" .= petFilterStatus
]
-- | Construct a value of type 'PetFilter' (by applying it's required fields, if any)
mkPetFilter
:: PetFilter
mkPetFilter =
PetFilter
{ petFilterTags = Nothing
, petFilterStatus = Nothing
}
-- ** PetOrder
-- | PetOrder
data PetOrder = PetOrder
{ petOrderName :: !(Maybe E'Name) -- ^ "name"
} deriving (P.Show, P.Eq, P.Typeable)
-- | FromJSON PetOrder
instance A.FromJSON PetOrder where
parseJSON = A.withObject "PetOrder" $ \o ->
PetOrder
<$> (o .:? "name")
-- | ToJSON PetOrder
instance A.ToJSON PetOrder where
toJSON PetOrder {..} =
_omitNulls
[ "name" .= petOrderName
]
-- | Construct a value of type 'PetOrder' (by applying it's required fields, if any)
mkPetOrder
:: PetOrder
mkPetOrder =
PetOrder
{ petOrderName = Nothing
}
-- ** ReadOnlyFirst -- ** ReadOnlyFirst
-- | ReadOnlyFirst -- | ReadOnlyFirst
data ReadOnlyFirst = ReadOnlyFirst data ReadOnlyFirst = ReadOnlyFirst
@ -1565,34 +1632,6 @@ mkReadOnlyFirst =
, readOnlyFirstBaz = Nothing , readOnlyFirstBaz = Nothing
} }
-- ** SpecialModelName
-- | SpecialModelName
data SpecialModelName = SpecialModelName
{ specialModelNameSpecialPropertyName :: !(Maybe Integer) -- ^ "$special[property.name]"
} deriving (P.Show, P.Eq, P.Typeable)
-- | FromJSON SpecialModelName
instance A.FromJSON SpecialModelName where
parseJSON = A.withObject "SpecialModelName" $ \o ->
SpecialModelName
<$> (o .:? "$special[property.name]")
-- | ToJSON SpecialModelName
instance A.ToJSON SpecialModelName where
toJSON SpecialModelName {..} =
_omitNulls
[ "$special[property.name]" .= specialModelNameSpecialPropertyName
]
-- | Construct a value of type 'SpecialModelName' (by applying it's required fields, if any)
mkSpecialModelName
:: SpecialModelName
mkSpecialModelName =
SpecialModelName
{ specialModelNameSpecialPropertyName = Nothing
}
-- ** Tag -- ** Tag
-- | Tag -- | Tag
data Tag = Tag data Tag = Tag
@ -2221,6 +2260,34 @@ toE'Kind = \case
s -> P.Left $ "toE'Kind: enum parse failure: " P.++ P.show s s -> P.Left $ "toE'Kind: enum parse failure: " P.++ P.show s
-- ** E'Name
-- | Enum of 'Text'
data E'Name
= E'Name'Asc -- ^ @"asc"@
| E'Name'Desc -- ^ @"desc"@
deriving (P.Show, P.Eq, P.Typeable, P.Ord, P.Bounded, P.Enum)
instance A.ToJSON E'Name where toJSON = A.toJSON . fromE'Name
instance A.FromJSON E'Name where parseJSON o = P.either P.fail (pure . P.id) . toE'Name =<< A.parseJSON o
instance WH.ToHttpApiData E'Name where toQueryParam = WH.toQueryParam . fromE'Name
instance WH.FromHttpApiData E'Name where parseQueryParam o = WH.parseQueryParam o >>= P.left T.pack . toE'Name
instance MimeRender MimeMultipartFormData E'Name where mimeRender _ = mimeRenderDefaultMultipartFormData
-- | unwrap 'E'Name' enum
fromE'Name :: E'Name -> Text
fromE'Name = \case
E'Name'Asc -> "asc"
E'Name'Desc -> "desc"
-- | parse 'E'Name' enum
toE'Name :: Text -> P.Either String E'Name
toE'Name = \case
"asc" -> P.Right E'Name'Asc
"desc" -> P.Right E'Name'Desc
s -> P.Left $ "toE'Name: enum parse failure: " P.++ P.show s
-- ** E'Status -- ** E'Status
-- | Enum of 'Text' . -- | Enum of 'Text' .

View File

@ -713,6 +713,29 @@ petStatusL f Pet{..} = (\petStatus -> Pet { petStatus, ..} ) <$> f petStatus
-- * PetFilter
-- | 'petFilterTags' Lens
petFilterTagsL :: Lens_' PetFilter (Maybe [Text])
petFilterTagsL f PetFilter{..} = (\petFilterTags -> PetFilter { petFilterTags, ..} ) <$> f petFilterTags
{-# INLINE petFilterTagsL #-}
-- | 'petFilterStatus' Lens
petFilterStatusL :: Lens_' PetFilter (Maybe [Text])
petFilterStatusL f PetFilter{..} = (\petFilterStatus -> PetFilter { petFilterStatus, ..} ) <$> f petFilterStatus
{-# INLINE petFilterStatusL #-}
-- * PetOrder
-- | 'petOrderName' Lens
petOrderNameL :: Lens_' PetOrder (Maybe E'Name)
petOrderNameL f PetOrder{..} = (\petOrderName -> PetOrder { petOrderName, ..} ) <$> f petOrderName
{-# INLINE petOrderNameL #-}
-- * ReadOnlyFirst -- * ReadOnlyFirst
-- | 'readOnlyFirstBar' Lens -- | 'readOnlyFirstBar' Lens
@ -727,15 +750,6 @@ readOnlyFirstBazL f ReadOnlyFirst{..} = (\readOnlyFirstBaz -> ReadOnlyFirst { re
-- * SpecialModelName
-- | 'specialModelNameSpecialPropertyName' Lens
specialModelNameSpecialPropertyNameL :: Lens_' SpecialModelName (Maybe Integer)
specialModelNameSpecialPropertyNameL f SpecialModelName{..} = (\specialModelNameSpecialPropertyName -> SpecialModelName { specialModelNameSpecialPropertyName, ..} ) <$> f specialModelNameSpecialPropertyName
{-# INLINE specialModelNameSpecialPropertyNameL #-}
-- * Tag -- * Tag
-- | 'tagId' Lens -- | 'tagId' Lens

View File

@ -167,21 +167,68 @@ paths:
summary: Finds Pets by tags summary: Finds Pets by tags
tags: tags:
- pet - pet
/pet/find:
get:
operationId: findPets
parameters:
- content:
application/json:
schema:
$ref: '#/components/schemas/PetFilter'
in: query
name: filter
required: false
- content:
application/json:
schema:
items:
$ref: '#/components/schemas/PetOrder'
type: array
in: query
name: order_by
required: false
responses:
"200":
content:
application/xml:
schema:
items:
$ref: '#/components/schemas/Pet'
type: array
application/json:
schema:
items:
$ref: '#/components/schemas/Pet'
type: array
description: successful operation
"400":
description: Invalid status value
security:
- petstore_auth:
- read:pets
summary: Finds Pets
tags:
- pet
/pet/{petId}: /pet/{petId}:
delete: delete:
operationId: deletePet operationId: deletePet
parameters: parameters:
- in: header - explode: false
in: header
name: api_key name: api_key
required: false
schema: schema:
type: string type: string
style: simple
- description: Pet id to delete - description: Pet id to delete
explode: false
in: path in: path
name: petId name: petId
required: true required: true
schema: schema:
format: int64 format: int64
type: integer type: integer
style: simple
responses: responses:
"200": "200":
content: {} content: {}
@ -201,12 +248,14 @@ paths:
operationId: getPetById operationId: getPetById
parameters: parameters:
- description: ID of pet to return - description: ID of pet to return
explode: false
in: path in: path
name: petId name: petId
required: true required: true
schema: schema:
format: int64 format: int64
type: integer type: integer
style: simple
responses: responses:
"200": "200":
content: content:
@ -232,12 +281,14 @@ paths:
operationId: updatePetWithForm operationId: updatePetWithForm
parameters: parameters:
- description: ID of pet that needs to be updated - description: ID of pet that needs to be updated
explode: false
in: path in: path
name: petId name: petId
required: true required: true
schema: schema:
format: int64 format: int64
type: integer type: integer
style: simple
requestBody: requestBody:
content: content:
application/x-www-form-urlencoded: application/x-www-form-urlencoded:
@ -259,12 +310,14 @@ paths:
operationId: uploadFile operationId: uploadFile
parameters: parameters:
- description: ID of pet to update - description: ID of pet to update
explode: false
in: path in: path
name: petId name: petId
required: true required: true
schema: schema:
format: int64 format: int64
type: integer type: integer
style: simple
requestBody: requestBody:
content: content:
multipart/form-data: multipart/form-data:
@ -337,11 +390,13 @@ paths:
operationId: deleteOrder operationId: deleteOrder
parameters: parameters:
- description: ID of the order that needs to be deleted - description: ID of the order that needs to be deleted
explode: false
in: path in: path
name: order_id name: order_id
required: true required: true
schema: schema:
type: string type: string
style: simple
responses: responses:
"400": "400":
content: {} content: {}
@ -358,6 +413,7 @@ paths:
operationId: getOrderById operationId: getOrderById
parameters: parameters:
- description: ID of pet that needs to be fetched - description: ID of pet that needs to be fetched
explode: false
in: path in: path
name: order_id name: order_id
required: true required: true
@ -366,6 +422,7 @@ paths:
maximum: 5 maximum: 5
minimum: 1 minimum: 1
type: integer type: integer
style: simple
responses: responses:
"200": "200":
content: content:
@ -449,17 +506,21 @@ paths:
operationId: loginUser operationId: loginUser
parameters: parameters:
- description: The user name for login - description: The user name for login
explode: true
in: query in: query
name: username name: username
required: true required: true
schema: schema:
type: string type: string
style: form
- description: The password for login in clear text - description: The password for login in clear text
explode: true
in: query in: query
name: password name: password
required: true required: true
schema: schema:
type: string type: string
style: form
responses: responses:
"200": "200":
content: content:
@ -473,14 +534,18 @@ paths:
headers: headers:
X-Rate-Limit: X-Rate-Limit:
description: calls per hour allowed by the user description: calls per hour allowed by the user
explode: false
schema: schema:
format: int32 format: int32
type: integer type: integer
style: simple
X-Expires-After: X-Expires-After:
description: date in UTC when token expires description: date in UTC when token expires
explode: false
schema: schema:
format: date-time format: date-time
type: string type: string
style: simple
"400": "400":
content: {} content: {}
description: Invalid username/password supplied description: Invalid username/password supplied
@ -503,11 +568,13 @@ paths:
operationId: deleteUser operationId: deleteUser
parameters: parameters:
- description: The name that needs to be deleted - description: The name that needs to be deleted
explode: false
in: path in: path
name: username name: username
required: true required: true
schema: schema:
type: string type: string
style: simple
responses: responses:
"400": "400":
content: {} content: {}
@ -522,11 +589,13 @@ paths:
operationId: getUserByName operationId: getUserByName
parameters: parameters:
- description: The name that needs to be fetched. Use user1 for testing. - description: The name that needs to be fetched. Use user1 for testing.
explode: false
in: path in: path
name: username name: username
required: true required: true
schema: schema:
type: string type: string
style: simple
responses: responses:
"200": "200":
content: content:
@ -551,11 +620,13 @@ paths:
operationId: updateUser operationId: updateUser
parameters: parameters:
- description: name that need to be deleted - description: name that need to be deleted
explode: false
in: path in: path
name: username name: username
required: true required: true
schema: schema:
type: string type: string
style: simple
requestBody: requestBody:
content: content:
'*/*': '*/*':
@ -604,40 +675,55 @@ paths:
operationId: testGroupParameters operationId: testGroupParameters
parameters: parameters:
- description: Required String in group parameters - description: Required String in group parameters
explode: true
in: query in: query
name: required_string_group name: required_string_group
required: true required: true
schema: schema:
type: integer type: integer
style: form
- description: Required Boolean in group parameters - description: Required Boolean in group parameters
explode: false
in: header in: header
name: required_boolean_group name: required_boolean_group
required: true required: true
schema: schema:
type: boolean type: boolean
style: simple
- description: Required Integer in group parameters - description: Required Integer in group parameters
explode: true
in: query in: query
name: required_int64_group name: required_int64_group
required: true required: true
schema: schema:
format: int64 format: int64
type: integer type: integer
style: form
- description: String in group parameters - description: String in group parameters
explode: true
in: query in: query
name: string_group name: string_group
required: false
schema: schema:
type: integer type: integer
style: form
- description: Boolean in group parameters - description: Boolean in group parameters
explode: false
in: header in: header
name: boolean_group name: boolean_group
required: false
schema: schema:
type: boolean type: boolean
style: simple
- description: Integer in group parameters - description: Integer in group parameters
explode: true
in: query in: query
name: int64_group name: int64_group
required: false
schema: schema:
format: int64 format: int64
type: integer type: integer
style: form
responses: responses:
"400": "400":
content: {} content: {}
@ -654,6 +740,7 @@ paths:
explode: false explode: false
in: header in: header
name: enum_header_string_array name: enum_header_string_array
required: false
schema: schema:
items: items:
default: $ default: $
@ -664,8 +751,10 @@ paths:
type: array type: array
style: simple style: simple
- description: Header parameter enum test (string) - description: Header parameter enum test (string)
explode: false
in: header in: header
name: enum_header_string name: enum_header_string
required: false
schema: schema:
default: -efg default: -efg
enum: enum:
@ -673,10 +762,12 @@ paths:
- -efg - -efg
- (xyz) - (xyz)
type: string type: string
style: simple
- description: Query parameter enum test (string array) - description: Query parameter enum test (string array)
explode: false explode: false
in: query in: query
name: enum_query_string_array name: enum_query_string_array
required: false
schema: schema:
items: items:
default: $ default: $
@ -687,8 +778,10 @@ paths:
type: array type: array
style: form style: form
- description: Query parameter enum test (string) - description: Query parameter enum test (string)
explode: true
in: query in: query
name: enum_query_string name: enum_query_string
required: false
schema: schema:
default: -efg default: -efg
enum: enum:
@ -696,24 +789,31 @@ paths:
- -efg - -efg
- (xyz) - (xyz)
type: string type: string
style: form
- description: Query parameter enum test (double) - description: Query parameter enum test (double)
explode: true
in: query in: query
name: enum_query_integer name: enum_query_integer
required: false
schema: schema:
enum: enum:
- 1 - 1
- -2 - -2
format: int32 format: int32
type: integer type: integer
style: form
- description: Query parameter enum test (double) - description: Query parameter enum test (double)
explode: true
in: query in: query
name: enum_query_double name: enum_query_double
required: false
schema: schema:
enum: enum:
- 1.1 - 1.1
- -1.2 - -1.2
format: double format: double
type: number type: number
style: form
requestBody: requestBody:
content: content:
application/x-www-form-urlencoded: application/x-www-form-urlencoded:
@ -903,11 +1003,13 @@ paths:
put: put:
operationId: testBodyWithQueryParams operationId: testBodyWithQueryParams
parameters: parameters:
- in: query - explode: true
in: query
name: query name: query
required: true required: true
schema: schema:
type: string type: string
style: form
requestBody: requestBody:
content: content:
application/json: application/json:
@ -961,12 +1063,14 @@ paths:
operationId: 123_test_@#$%_special_tags operationId: 123_test_@#$%_special_tags
parameters: parameters:
- description: to test uuid example value - description: to test uuid example value
explode: false
in: header in: header
name: uuid_test name: uuid_test
required: true required: true
schema: schema:
format: uuid format: uuid
type: string type: string
style: simple
requestBody: requestBody:
content: content:
application/json: application/json:
@ -1016,15 +1120,18 @@ paths:
items: items:
type: string type: string
type: array type: array
style: form style: pipeDelimited
- in: query - explode: true
in: query
name: ioutil name: ioutil
required: true required: true
schema: schema:
items: items:
type: string type: string
type: array type: array
- in: query style: form
- explode: false
in: query
name: http name: http
required: true required: true
schema: schema:
@ -1061,12 +1168,14 @@ paths:
operationId: uploadFileWithRequiredFile operationId: uploadFileWithRequiredFile
parameters: parameters:
- description: ID of pet to update - description: ID of pet to update
explode: false
in: path in: path
name: petId name: petId
required: true required: true
schema: schema:
format: int64 format: int64
type: integer type: integer
style: simple
requestBody: requestBody:
content: content:
multipart/form-data: multipart/form-data:
@ -1240,6 +1349,25 @@ components:
type: object type: object
xml: xml:
name: Pet name: Pet
PetFilter:
properties:
tags:
items:
type: string
type: array
status:
items:
type: string
type: array
type: object
PetOrder:
properties:
name:
enum:
- asc
- desc
type: string
type: object
ApiResponse: ApiResponse:
example: example:
code: 0 code: 0
@ -1254,14 +1382,6 @@ components:
message: message:
type: string type: string
type: object type: object
$special[model.name]:
properties:
$special[property.name]:
format: int64
type: integer
type: object
xml:
name: "$special[model.name]"
Return: Return:
description: Model for testing reserved words description: Model for testing reserved words
properties: properties:
@ -2146,4 +2266,3 @@ components:
http_basic_test: http_basic_test:
scheme: basic scheme: basic
type: http type: http
x-original-swagger-version: "2.0"

View File

@ -470,6 +470,23 @@ genPet n =
<*> arbitraryReducedMaybe n -- petTags :: Maybe [Tag] <*> arbitraryReducedMaybe n -- petTags :: Maybe [Tag]
<*> arbitraryReducedMaybe n -- petStatus :: Maybe E'Status2 <*> arbitraryReducedMaybe n -- petStatus :: Maybe E'Status2
instance Arbitrary PetFilter where
arbitrary = sized genPetFilter
genPetFilter :: Int -> Gen PetFilter
genPetFilter n =
PetFilter
<$> arbitraryReducedMaybe n -- petFilterTags :: Maybe [Text]
<*> arbitraryReducedMaybe n -- petFilterStatus :: Maybe [Text]
instance Arbitrary PetOrder where
arbitrary = sized genPetOrder
genPetOrder :: Int -> Gen PetOrder
genPetOrder n =
PetOrder
<$> arbitraryReducedMaybe n -- petOrderName :: Maybe E'Name
instance Arbitrary ReadOnlyFirst where instance Arbitrary ReadOnlyFirst where
arbitrary = sized genReadOnlyFirst arbitrary = sized genReadOnlyFirst
@ -479,14 +496,6 @@ genReadOnlyFirst n =
<$> arbitraryReducedMaybe n -- readOnlyFirstBar :: Maybe Text <$> arbitraryReducedMaybe n -- readOnlyFirstBar :: Maybe Text
<*> arbitraryReducedMaybe n -- readOnlyFirstBaz :: Maybe Text <*> arbitraryReducedMaybe n -- readOnlyFirstBaz :: Maybe Text
instance Arbitrary SpecialModelName where
arbitrary = sized genSpecialModelName
genSpecialModelName :: Int -> Gen SpecialModelName
genSpecialModelName n =
SpecialModelName
<$> arbitraryReducedMaybe n -- specialModelNameSpecialPropertyName :: Maybe Integer
instance Arbitrary Tag where instance Arbitrary Tag where
arbitrary = sized genTag arbitrary = sized genTag
@ -605,6 +614,9 @@ instance Arbitrary E'JustSymbol where
instance Arbitrary E'Kind where instance Arbitrary E'Kind where
arbitrary = arbitraryBoundedEnum arbitrary = arbitraryBoundedEnum
instance Arbitrary E'Name where
arbitrary = arbitraryBoundedEnum
instance Arbitrary E'Status where instance Arbitrary E'Status where
arbitrary = arbitraryBoundedEnum arbitrary = arbitraryBoundedEnum

View File

@ -58,8 +58,9 @@ main =
propMimeEq MimeJSON (Proxy :: Proxy OuterComposite) propMimeEq MimeJSON (Proxy :: Proxy OuterComposite)
propMimeEq MimeJSON (Proxy :: Proxy OuterEnum) propMimeEq MimeJSON (Proxy :: Proxy OuterEnum)
propMimeEq MimeJSON (Proxy :: Proxy Pet) propMimeEq MimeJSON (Proxy :: Proxy Pet)
propMimeEq MimeJSON (Proxy :: Proxy PetFilter)
propMimeEq MimeJSON (Proxy :: Proxy PetOrder)
propMimeEq MimeJSON (Proxy :: Proxy ReadOnlyFirst) propMimeEq MimeJSON (Proxy :: Proxy ReadOnlyFirst)
propMimeEq MimeJSON (Proxy :: Proxy SpecialModelName)
propMimeEq MimeJSON (Proxy :: Proxy Tag) propMimeEq MimeJSON (Proxy :: Proxy Tag)
propMimeEq MimeJSON (Proxy :: Proxy TypeHolderDefault) propMimeEq MimeJSON (Proxy :: Proxy TypeHolderDefault)
propMimeEq MimeJSON (Proxy :: Proxy TypeHolderExample) propMimeEq MimeJSON (Proxy :: Proxy TypeHolderExample)

View File

@ -42,7 +42,9 @@ import Control.Monad.Except (ExceptT, runExceptT)
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Control.Monad.Trans.Reader (ReaderT (..)) import Control.Monad.Trans.Reader (ReaderT (..))
import Data.Aeson (Value) import Data.Aeson (Value)
import qualified Data.Aeson as Aeson
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as BSL
import Data.Coerce (coerce) import Data.Coerce (coerce)
import Data.Data (Data) import Data.Data (Data)
import Data.Function ((&)) import Data.Function ((&))
@ -52,6 +54,7 @@ import Data.Proxy (Proxy (..))
import Data.Set (Set) import Data.Set (Set)
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import Data.Time import Data.Time
import Data.UUID (UUID) import Data.UUID (UUID)
import GHC.Exts (IsString (..)) import GHC.Exts (IsString (..))
@ -143,11 +146,22 @@ instance ToHttpApiData a => ToHttpApiData (QueryList 'MultiParamArray a) where
formatSeparatedQueryList :: ToHttpApiData a => Char -> QueryList p a -> Text formatSeparatedQueryList :: ToHttpApiData a => Char -> QueryList p a -> Text
formatSeparatedQueryList char = T.intercalate (T.singleton char) . map toQueryParam . fromQueryList formatSeparatedQueryList char = T.intercalate (T.singleton char) . map toQueryParam . fromQueryList
newtype JSONQueryParam a = JSONQueryParam
{ fromJsonQueryParam :: a
} deriving (Functor, Foldable, Traversable)
instance Aeson.ToJSON a => ToHttpApiData (JSONQueryParam a) where
toQueryParam = T.decodeUtf8 . BSL.toStrict . Aeson.encode . fromJsonQueryParam
instance Aeson.FromJSON a => FromHttpApiData (JSONQueryParam a) where
parseQueryParam = either (Left . T.pack) (Right . JSONQueryParam) . Aeson.eitherDecodeStrict . T.encodeUtf8
-- | Servant type-level API, generated from the OpenAPI spec for OpenAPIPetstore. -- | Servant type-level API, generated from the OpenAPI spec for OpenAPIPetstore.
type OpenAPIPetstoreAPI type OpenAPIPetstoreAPI
= Protected :> "pet" :> ReqBody '[JSON] Pet :> Verb 'POST 200 '[JSON] Pet -- 'addPet' route = Protected :> "pet" :> ReqBody '[JSON] Pet :> Verb 'POST 200 '[JSON] Pet -- 'addPet' route
:<|> Protected :> "pet" :> Capture "petId" Integer :> Header "api_key" Text :> Verb 'DELETE 200 '[JSON] NoContent -- 'deletePet' route :<|> Protected :> "pet" :> Capture "petId" Integer :> Header "api_key" Text :> Verb 'DELETE 200 '[JSON] NoContent -- 'deletePet' route
:<|> Protected :> "pet" :> "find" :> QueryParam "filter" (JSONQueryParam PetFilter) :> Verb 'GET 200 '[JSON] [Pet] -- 'findPets' route
:<|> Protected :> "pet" :> "findByStatus" :> QueryParam "status" (QueryList 'CommaSeparated (Text)) :> Verb 'GET 200 '[JSON] [Pet] -- 'findPetsByStatus' route :<|> Protected :> "pet" :> "findByStatus" :> QueryParam "status" (QueryList 'CommaSeparated (Text)) :> Verb 'GET 200 '[JSON] [Pet] -- 'findPetsByStatus' route
:<|> Protected :> "pet" :> "findByTags" :> QueryParam "tags" (QueryList 'CommaSeparated (Text)) :> Verb 'GET 200 '[JSON] [Pet] -- 'findPetsByTags' route :<|> Protected :> "pet" :> "findByTags" :> QueryParam "tags" (QueryList 'CommaSeparated (Text)) :> Verb 'GET 200 '[JSON] [Pet] -- 'findPetsByTags' route
:<|> Protected :> "pet" :> Capture "petId" Integer :> Verb 'GET 200 '[JSON] Pet -- 'getPetById' route :<|> Protected :> "pet" :> Capture "petId" Integer :> Verb 'GET 200 '[JSON] Pet -- 'getPetById' route
@ -188,6 +202,7 @@ newtype OpenAPIPetstoreClientError = OpenAPIPetstoreClientError ClientError
data OpenAPIPetstoreBackend a m = OpenAPIPetstoreBackend data OpenAPIPetstoreBackend a m = OpenAPIPetstoreBackend
{ addPet :: a -> Pet -> m Pet{- ^ -} { addPet :: a -> Pet -> m Pet{- ^ -}
, deletePet :: a -> Integer -> Maybe Text -> m NoContent{- ^ -} , deletePet :: a -> Integer -> Maybe Text -> m NoContent{- ^ -}
, findPets :: a -> Maybe PetFilter -> m [Pet]{- ^ -}
, findPetsByStatus :: a -> Maybe [Text] -> m [Pet]{- ^ Multiple status values can be provided with comma separated strings -} , findPetsByStatus :: a -> Maybe [Text] -> m [Pet]{- ^ Multiple status values can be provided with comma separated strings -}
, findPetsByTags :: a -> Maybe [Text] -> m [Pet]{- ^ Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. -} , findPetsByTags :: a -> Maybe [Text] -> m [Pet]{- ^ Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. -}
, getPetById :: a -> Integer -> m Pet{- ^ Returns a single pet -} , getPetById :: a -> Integer -> m Pet{- ^ Returns a single pet -}
@ -240,6 +255,7 @@ createOpenAPIPetstoreClient = OpenAPIPetstoreBackend{..}
where where
((coerce -> addPet) :<|> ((coerce -> addPet) :<|>
(coerce -> deletePet) :<|> (coerce -> deletePet) :<|>
(coerce -> findPets) :<|>
(coerce -> findPetsByStatus) :<|> (coerce -> findPetsByStatus) :<|>
(coerce -> findPetsByTags) :<|> (coerce -> findPetsByTags) :<|>
(coerce -> getPetById) :<|> (coerce -> getPetById) :<|>
@ -314,6 +330,7 @@ serverWaiApplicationOpenAPIPetstore auth backend = serveWithContextT (Proxy :: P
serverFromBackend OpenAPIPetstoreBackend{..} = serverFromBackend OpenAPIPetstoreBackend{..} =
(coerce addPet :<|> (coerce addPet :<|>
coerce deletePet :<|> coerce deletePet :<|>
coerce findPets :<|>
coerce findPetsByStatus :<|> coerce findPetsByStatus :<|>
coerce findPetsByTags :<|> coerce findPetsByTags :<|>
coerce getPetById :<|> coerce getPetById :<|>

View File

@ -1,6 +1,7 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-} {-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-}
module OpenAPIPetstore.Types ( module OpenAPIPetstore.Types (
@ -8,6 +9,7 @@ module OpenAPIPetstore.Types (
Category (..), Category (..),
Order (..), Order (..),
Pet (..), Pet (..),
PetFilter (..),
SpecialCharacters (..), SpecialCharacters (..),
Tag (..), Tag (..),
User (..), User (..),
@ -160,6 +162,34 @@ optionsPet =
] ]
-- |
data PetFilter = PetFilter
{ petFilterTags :: Maybe [Text] -- ^
, petFilterStatus :: Maybe [Text] -- ^
} deriving (Show, Eq, Generic, Data)
instance FromJSON PetFilter where
parseJSON = genericParseJSON optionsPetFilter
instance ToJSON PetFilter where
toJSON = genericToJSON optionsPetFilter
instance ToSchema PetFilter where
declareNamedSchema = Swagger.genericDeclareNamedSchema
$ Swagger.fromAesonOptions
$ optionsPetFilter
optionsPetFilter :: Options
optionsPetFilter =
defaultOptions
{ omitNothingFields = True
, fieldLabelModifier = \s -> fromMaybe ("did not find JSON field name for " ++ show s) $ lookup s table
}
where
table =
[ ("petFilterTags", "tags")
, ("petFilterStatus", "status")
]
-- | description -- | description
data SpecialCharacters = SpecialCharacters data SpecialCharacters = SpecialCharacters
{ specialCharactersDoubleQuote :: Text -- ^ double quote { specialCharactersDoubleQuote :: Text -- ^ double quote

View File

@ -1,4 +1,4 @@
resolver: lts-19.2 resolver: lts-22.12
extra-deps: [] extra-deps: []
packages: packages:
- '.' - '.'

View File

@ -6,6 +6,7 @@
/pet PetR PUT POST /pet PetR PUT POST
/pet/findByStatus PetFindByStatusR GET /pet/findByStatus PetFindByStatusR GET
/pet/findByTags PetFindByTagsR GET /pet/findByTags PetFindByTagsR GET
/pet/find PetFindR GET
!/pet/#Int64 PetByInt64R GET POST DELETE !/pet/#Int64 PetByInt64R GET POST DELETE
/pet/#Int64/uploadImage PetByInt64UploadImageR POST /pet/#Int64/uploadImage PetByInt64UploadImageR POST
/store/inventory StoreInventoryR GET /store/inventory StoreInventoryR GET

View File

@ -20,6 +20,12 @@ deletePetByInt64R :: Int64 -- ^ Pet id to delete
-> Handler Value -> Handler Value
deletePetByInt64R petId = notImplemented deletePetByInt64R petId = notImplemented
-- | Finds Pets
--
-- operationId: findPets
getPetFindR :: Handler Value
getPetFindR = notImplemented
-- | Finds Pets by status -- | Finds Pets by status
-- --
-- Multiple status values can be provided with comma separated strings -- Multiple status values can be provided with comma separated strings

View File

@ -8,6 +8,7 @@ module OpenAPIPetstore.Types (
Category (..), Category (..),
Order (..), Order (..),
Pet (..), Pet (..),
PetFilter (..),
SpecialCharacters (..), SpecialCharacters (..),
Tag (..), Tag (..),
User (..), User (..),
@ -139,6 +140,30 @@ optionsPet =
] ]
-- |
data PetFilter = PetFilter
{ petFilterTags :: Maybe [Text] -- ^
, petFilterStatus :: Maybe [Text] -- ^
} deriving (Show, Eq, Generic)
instance FromJSON PetFilter where
parseJSON = genericParseJSON optionsPetFilter
instance ToJSON PetFilter where
toJSON = genericToJSON optionsPetFilter
optionsPetFilter :: Options
optionsPetFilter =
defaultOptions
{ omitNothingFields = True
, fieldLabelModifier = \s -> fromMaybe ("did not find JSON field name for " ++ show s) $ List.lookup s table
}
where
table =
[ ("petFilterTags", "tags")
, ("petFilterStatus", "status")
]
-- | description -- | description
data SpecialCharacters = SpecialCharacters data SpecialCharacters = SpecialCharacters
{ specialCharactersDoubleQuote :: Text -- ^ double quote { specialCharactersDoubleQuote :: Text -- ^ double quote