2

I'm using Refit in a C# project to create an API client. I'd prefer to do everything with F# but Refit doesn't fully support F# yet.

If I create my User model in C# everything is fine but I'd prefer to be able to express which properties are optional and handle them appropriately.

If I add FSharp.Core and use FSharpOption<string> or similar then assertions that try to access those members fail with a NullReferenceException but only if the JSON response contains something optional.

If I create a separate F# project that contains a User model I always get a NullReferenceException when trying to deserialize.

Admittedly, keeping any models as part of the C# project seems easier but I don't want to sacrifice knowing which members are optional on the F# side.

What is the best way to go about this?

Bennor McCarthy
  • 11,415
  • 1
  • 49
  • 51
Paul Young
  • 1,489
  • 1
  • 15
  • 34
  • 1
    It might be that the answer is "Don't use Refit". I'd love recommendations for alternatives if that's the case. – Paul Young Jul 02 '15 at 21:12
  • 1
    The alternative would probably be to use Suave (www.suave.io) for writing the server-side code and F# Data JSON type provider for the client-side. But it's a quite different style, so I don't think that directly answers your question. Fixing Refit so that it supports F# would be neat :) – Tomas Petricek Jul 02 '15 at 22:10
  • Can you include some code? Your types, your refit interface, and your failing test with output? – SimonF Jul 03 '15 at 01:36

3 Answers3

1

My current thinking is to leave the C# project as-is and create an F# wrapper which returns models in a Result type, with optional members where appropriate.


Update:

I ended up doing this and adding the following to my FSharp models:

static member ToCSharp :
    user: User
       -> CSharp.User

static member FromCSharp :
    user: CSharp.User
       -> User option
Paul Young
  • 1,489
  • 1
  • 15
  • 34
0

I'm not sure if this will work, but Refit allows you to specify custom serializer settings, which will allow you to try this approach: Serializing F# Option types.

If that doesn't work, create a small repro project and create an issue and I'll look into it.

Community
  • 1
  • 1
Bennor McCarthy
  • 11,415
  • 1
  • 49
  • 51
0

I'm not familiar with Refit but here's some FSharpOption<> converter code we use in production https://gist.github.com/NickJosevski/956246019c431630931b

For JSON.net we add that FSharpOptionConverter to the list of converters that json.net takes.

From the docs on refit I see a this note:

When creating a Refit generated live interface, you may optionally pass a RefitSettings that will allow you to specify what serializer settings you would like. This allows you to have different serializer settings for separate APIs

So in my code the JsonSerializerSettings setup is like this:

var settings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.Auto,
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    Formatting = Formatting.Indented
};

// important bit:
 settings.Converters.Add(new FSharpOptionConverter());

So if you can find the right place to get those settings wired up then deserializion should be fine for FSharpOption<>.

Nick Josevski
  • 4,156
  • 3
  • 43
  • 63