Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions openapi3-code-generator/src/OpenAPI/Generate/Model.hs
Original file line number Diff line number Diff line change
Expand Up @@ -419,13 +419,18 @@ defineOneOfSchema schemaName description allSchemas discriminator = do
let paramName = mkName "val"
body =
case discriminator of
-- When discriminator is present, we'll use it to figure out
-- which constructor to parse
Just disc -> do
let fnArgName = mkName "obj"
discriminatorPropertyName = mkName "propertyName"
nonFixedSchemas = zip ([1 ..] :: [Integer]) $ do
schema <- allSchemas
guard $ E.isLeft $ extractSchemaWithFixedValue FixedValueStrategyExclude schema
pure schema
-- Map from refs in anyOf to schema name. We'll use this to
-- discover the actual relevant constructor names (and
-- their indexes which we may need if the setting is on).
schemaLookupFromRef = Map.fromList $ do
(n, schema) <- nonFixedSchemas
case schema of
Expand All @@ -434,6 +439,9 @@ defineOneOfSchema schemaName description allSchemas discriminator = do
oneOfSchemaRefs = do
(ref, (_, name')) <- Map.toList schemaLookupFromRef
pure (name', ref)
-- Per the spec: if `mapping` exists we'll use the keys
-- specified there. If not, we'll use the schema component
-- names.
propertyNamesWithReferences = maybe oneOfSchemaRefs Map.toList $ OAS.discriminatorObjectMapping disc
let mkMatchedCase (propName, fullRef) =
case Map.lookup fullRef schemaLookupFromRef of
Expand All @@ -443,9 +451,12 @@ defineOneOfSchema schemaName description allSchemas discriminator = do
parseConstructor constructorName = [|($(varE constructorName) <$> Aeson.parseJSON $(varE paramName))|]
[match (litP $ stringL $ T.unpack propName) (normalB [|$(parseConstructor $ haskellifyConstructor $ schemaName <> haskellifyPartialConstructor caseName <> suffix)|]) []]
matchedCases = propertyNamesWithReferences >>= mkMatchedCase
-- Fallback. If we don't parse the property, we'll fail.
unmatchedCase = match (varP $ mkName "_unmatched") (normalB [|fail "No match for discriminator property"|]) []
propertyCases = matchedCases <> [unmatchedCase]
getDiscProp = [|$(varE fnArgName) Aeson..:? $(stringE $ T.unpack $ OAS.discriminatorObjectPropertyName disc)|]
-- Annotate as `Text` otherwise we get ambiguity since we're
-- just matching on string literals.
annotatedDiscriminatorPropertyName = [|$(varE discriminatorPropertyName) :: Text|]
withObjectLamda =
[|
Expand All @@ -457,6 +468,8 @@ defineOneOfSchema schemaName description allSchemas discriminator = do
$(caseE annotatedDiscriminatorPropertyName propertyCases)
|]
[|Aeson.withObject $(stringE $ T.unpack schemaName) $(lam1E (varP fnArgName) withObjectLamda) $(varE paramName)|]
-- When there's no discriminator, we'll just try to parse the
-- different variants, in the order they're defined.
Nothing -> do
constructorNames' <- sequence constructorNames
let resultExpr =
Expand Down
104 changes: 104 additions & 0 deletions specifications/petstore-running-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,46 @@ paths:
"$ref": "#/components/schemas/NullableAndOptionalTest"
description: Nullable and optional values as input
required: true
"/discriminator/fish/{fishType}":
get:
summary: Get a fish by discriminator type
operationId: getFishByType
parameters:
- name: fishType
in: path
required: true
description: The fish type (guppie, minnow, shark)
schema:
type: string
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: "#/components/schemas/Fish"
'400':
description: Invalid fish type
"/discriminator/lizard/{lizardType}":
get:
summary: Get a lizard by discriminator type
operationId: getLizardByType
parameters:
- name: lizardType
in: path
required: true
description: The lizard type (gecko, gilaMonster)
schema:
type: string
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: "#/components/schemas/Lizard"
'400':
description: Invalid lizard type
/query/array/form:
get:
operationId: queryArrayForm
Expand Down Expand Up @@ -836,6 +876,70 @@ components:
type: number
B:
type: number
Fish:
type: object
oneOf:
- $ref: '#/components/schemas/Guppie'
- $ref: '#/components/schemas/Minnow'
- $ref: '#/components/schemas/Shark'
discriminator:
propertyName: fishType
mapping:
guppie: '#/components/schemas/Guppie'
minnow: '#/components/schemas/Minnow'
shark: '#/components/schemas/Shark'
Guppie:
type: object
properties:
color:
type: string
fishType:
type: string
required:
- fishType
Minnow:
type: object
properties:
color:
type: string
fishType:
type: string
required:
- fishType
Shark:
type: object
properties:
teethRemaining:
type: integer
fishType:
type: string
required:
- fishType
Lizard:
type: object
oneOf:
- $ref: '#/components/schemas/Gecko'
- $ref: '#/components/schemas/GilaMonster'
discriminator:
propertyName: discriminatorTag
Gecko:
type: object
properties:
hasTail:
type: boolean
discriminatorTag:
type: string
required:
- discriminatorTag
GilaMonster:
type: object
properties:
hasTail:
type: boolean
discriminatorTag:
type: string
required:
- discriminatorTag
requestBodies:
Pet:
content:
Expand Down
Loading
Loading