Giraffe icon indicating copy to clipboard operation
Giraffe copied to clipboard

Capitalized handlers ignore custom serializers

Open Tarmil opened this issue 6 years ago • 5 comments

I was surprised to find out that the following samples behave differently (given a request that accepts json):

// This uses my registered IJsonSerializer:
Successful.ok (json { x = 1 })

// This uses the default serializer:
Successful.OK { x = 1 }

I don't know if this is intentional or a bug, but it's at least unexpected.

Tarmil avatar Apr 22 '20 09:04 Tarmil

Hi, this is not intended, so must be a bug. I'll have a look later tonight!

dustinmoris avatar Apr 22 '20 09:04 dustinmoris

Can you show me how you configured your custom serializer?

dustinmoris avatar Apr 22 '20 09:04 dustinmoris

I add a services.AddSingleton<IJsonSerializer, MySerializer>() to my ConfigureServices.

Here's a repro based on the default template: https://github.com/Tarmil/giraffe-411-repro

Tarmil avatar Apr 22 '20 13:04 Tarmil

Looking into this it seems that both are using the registered IJsonSerializer but Successful.OK uses Content Negotiation and therefore might attempt to serialize the response in a different content type based on the client's accept headers.

dustinmoris avatar Dec 07 '20 09:12 dustinmoris

We got bitten by this at $WORK yesterday, and after some investigation it turned out that it is indeed content negotiaton that causes the issue. In our specific instance, we had custom serializer options for a certain type, which were ignored. Interestingly, the configuration was respected when the type was returned as part of a collection, i.e.:

type Stuff = Stuff of string

// This ignored the serialization options
Succesful.OK (Stuff "problematic")

// This was fine
Succesful.OK [ Stuff "all good" ]

In any case, after some investigation, I noticed that the negotiate function defines responseObj with type obj, this is what trips the serializer. https://github.com/giraffe-fsharp/Giraffe/blob/6fe39c21abdf85bf1e49db55a053342c42186e7f/src/Giraffe/Negotiation.fs#L174

I was able to copy the functions and add a type parameter instead of obj, which fixes the problem, but I was not able to make the whole content negotiation "pipeline" generic in Giraffe itself. I got stuck when registering INegotiationConfig and its default implementation, after having turned it into a generic type.

I suspect the fix for this issue is going to be a bit more involved than just slapping type parameters everywhere like I tried doing. :sweat_smile:

aurecchia avatar May 19 '22 14:05 aurecchia