Open piaste opened 5 years ago
I've found an alternative approach that seems to work: instead of adding a TypeMapper
, I can provide a custom ReflectionService
that returns the type description for T
with IsNullable = true
when asked to describe Option<T>
.
Hacking into the reflection seems a bit overkill though, the TypeMapper
should be the right approach - it shouldn't be doing anything that PrimitiveTypeMapper isn't already doing.
@piaste I'm trying to do this exact thing. Do you mind sharing your ReflectionService
solution, if available?
@baleeds
Sure, it's just a few lines of code:
type OptionReflectionService internal () =
inherit DefaultReflectionService()
override __.GetDescription (contextualType, defaultReferenceTypeNullHandling, settings) =
if contextualType.OriginalType.IsGenericType &&
contextualType.OriginalType.GetGenericTypeDefinition() = typedefof<Option<_>> then
let wrappedType = contextualType.OriginalType.GetGenericArguments().[0]
let wrappedContextualType = Namotion.Reflection.ContextualTypeExtensions.ToContextualType(wrappedType)
let wrappedDesc = base.GetDescription(wrappedContextualType, defaultReferenceTypeNullHandling, settings)
wrappedDesc.IsNullable <- true
wrappedDesc
else
base.GetDescription(contextualType, defaultReferenceTypeNullHandling, settings)
@piaste Thank you for that! It was very helpful. 🥇
I came across this problem too, but I'm beginning to think reflection might be the correct approach here, if you need to deal with discriminated unions in general.
Only issue is that I don't know how extensible this approach is, since you can't really "chain" reflection services without inheritance.
Custom ReflectionService does not solve #1302
I had the same issue but the suggestion solution did not work for me because I had T
s which were reference types, which led to #1302. My solution was to create a custom generator:
public class MySchemaGenerator : OpenApiSchemaGenerator
{
/// <inheritdoc />
public MyJsonSchemaGenerator(OpenApiDocumentGeneratorSettings settings) : base(settings)
{
}
/// <inheritdoc />
public override TSchemaType GenerateWithReferenceAndNullability<TSchemaType>(
ContextualType contextualType,
bool isNullable,
JsonSchemaResolver schemaResolver,
Action<TSchemaType, JsonSchema>? transformation = null)
{
while (IsWrapperType(contextualType.Type))
{
contextualType = contextualType.OriginalGenericArguments[0];
}
return base.GenerateWithReferenceAndNullability(contextualType, isNullable: true, schemaResolver, transformation);
static bool IsWrapperType(Type type)
{
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Option<>);
}
}
}
(Originally posted in https://github.com/RicoSuter/NSwag/issues/2362)
What I'm using:
The API Explorer generator middleware, version 13.0.4
What I'm trying to do:
My classes make extensive use of the
Option<T>
class, which through a JSON.NET custom converter de/serializes to eitherT
ornull
.I would like the generated OpenAPI spec to match this expectation, that is, the type:
should be represented as
(By default, NSwag represents the class as
FSharpOptionOfString
,FSharpOptionOfBoolean
, etc.)What I've done:
Added a custom type mapper for the generic type (I've seen in the code that NSwag does check for generics):
What happens:
The
GenerateSchema
method above executes without error, and inspecting theschema
object it looks exactly as I expected (Type: string
,IsNullable: true
).However, the following error happens immediately after, and I've been unable to catch it in debug or pinpoint the problem:
What I've tried:
UseReference
totrue
schema.ParentSchema.Definitions.Add("FSharpOptionOf" + tipo.Name, schema)
), which fails becauseParentSchema
is nullT
toOption<T>
T
toOption<T>