Zaid-Ajaj / Fable.Remoting

Type-safe communication layer (RPC-style) for F# featuring Fable and .NET Apps
https://zaid-ajaj.github.io/Fable.Remoting/
MIT License
272 stars 54 forks source link

Making the API to return (also) XML (instead of JSON) #224

Closed TitusRie closed 3 years ago

TitusRie commented 3 years ago

I'm trying to setup a service based on the SAFE.Simplified template, which is of course consumed by the Fable client, but also by a seperate C# dotnet application which wants XML format.

Setting the request Accept header to application/xml (in the dotnet app) didn't seem to work.

Looking at the saturn documentation I can see that with xml ctx obj you can make the service return content serialized to XML.

Is there a way to do the same in Fable.Remoting, like |> Remoting.withBinarySerialization' but then for XML?

Zaid-Ajaj commented 3 years ago

Hi there @TitusRie, unfortunately Fable.Remoting does not support data transport in XML. Only JSON and MsgPack are supported. This has to do with how complicated the implementation would be across the stacks. There aren't any plans to implement XML support in Fable.Remoting.

This brings to the question: why does your C# application require XML? Using the package Fable.Remoting.DotnetClient allows a dotnet app (whether written in F# or C#) to talk to the backend using Fable.Remoting. You can use Fable.Remoting.DotnetClient from any application because it targets netstandard2.0 and net46 (full framework). It also supports both JSON and (binary) MsgPack protocols.

TitusRie commented 3 years ago

Hi @Zaid-Ajaj, digging into the subject I'm starting to understand the complications... Using Fable.Remoting.DotnetClient would of course be a good alternative, the only thing is the service needs to comply with standards which require XML format. Maybe a separate Saturn controller for supplying XML is an option in this case. Of course missing out the nice Fable client integration and automatic docs generation. I surely understand this use case is not on the top of your list, but in some (archaic) contexts, XML is still a requirement. Giving the complexity of XML serializers and all the Fable.Remoting abstractions, I'm not sure I could be of any help integrating this into Fable.Remoting but of course I can share the solution I've come up with.

kerams commented 3 years ago

Whether you use the Fable client or DotnetClient, the transport and serialization is hidden away (that's the primary selling point of Remoting after all) to the point that you can (almost) forget it is there.

If you're going to consume the API and deserialize it manually somewhere (those archaic contexts you speak of), then I'm not sure using Remoting on the server alone makes much sense (it might even be a bit of a hindrance), because all you're getting at that point is automatic serialization, which isn't exactly something to write home about. The beauty of it all is when you put together both client and server and they click.

TitusRie commented 3 years ago

@kerams I completely agree, in this case I'm in a hybrid scenario, where I would love to leverage joy of the magic 'click' of remoting with client and server and at the same time comply with archaic XML standards (which obviously would naturally migrate towards JSON in due time). I also love the type-safe documentation functionality, to document for external clients, unfortunately, this only makes sense for JSON consumers. Right now I'm thinking in the line of having the standard API function as a standard Fable.Remoting solution (as shown in SAFE.Simplified) and add an extra Saturn router for XML access. The more both can share in implementation and documentation, the better of course. So any thoughts and pointers are more than welcome! :-)

Zaid-Ajaj commented 3 years ago

@TitusRie just a heads-up if you are using SAFE.Simplified, the client is still using Fable 2.x (latest is Fable 3) and some packages might need an update (Feliz, Feliz.Router, Fable.Remoting and co etc.) I need to update the packages at some point, you can look at the more modern SAFE.React for reference, although it is more Feliz-centric than full fledged Elmish on the client

Zaid-Ajaj commented 3 years ago

About the shared implementation. That sounds like a good compromise. I am not sure how to do it, but you could expose a SwaggerUI of your XML-retuning endpoints and it will probably be nicer than the the simple generated docs application 😉

kerams commented 3 years ago

Sure, having a Remoting endpoint with JSON and a Saturn router with XML side-by-side calling into the same business logic is certainly a good strategy. Especially if they're both lean and all they do is remap objects. You'll still have to set up XML serialization on your own, but you have an easy migration when you move forward.

If, on the other, you're thinking of trying to put the router in front of the Remoting function, thinking you'd be able to somehow intercept the data returned from your business logic, that won't work because Remoting is internally writing directly to the response stream and nothing is passed between middlewares.

TitusRie commented 3 years ago

@Zaid-Ajaj, @kerams, thanks a lot! I love Feliz, so the SAFE.React template looks like a good solution. I also was already very happy with the simple generated docs, but the SaggerUI sounds like a good alternative. And thank you for saving me a lot of digging around! As soon as I've made a sort of decent solution, I'll share it. For now I think it's ok to close this issue.