Alongside raw HTTP, you can also use Fable.Remoting, which provides an RPC-style mechanism for calling server endpoints. With Remoting, you don't need to worry about the details of serialization or of how to consume the endpoint - instead, remoting lets you define you client-server interactions as a shared type that is commonly referred to as a protocol or contract.
Each field of the record is either of type Async<T> or a function that returns Async<T>, for example:
type ICustomerApi = {
getCustomers : unit -> Async<Customer list>
findCustomerByName : string -> Async<Customer option>
}The supported types used within the protocol can be any F# type: primitive values (int, string, DateTime, etc.), records, options, discriminated unions or collections etc.
On the server you would implement the protocol as follows:
let getCustomers() =
async {
return [
{ Id = 1; Name = "John Doe" }
{ Id = 2; Name = "Jane Smith" } ]
}
let findCustomerByName (name: string) =
async {
let! allCustomers = getCustomers()
return allCustomers |> List.tryFind (fun c -> c.Name = name)
}
let customerApi : ICustomerApi = {
getCustomers = getCustomers
findCustomerByName = findCustomerByName
}After exposing an HttpHandler from customerApi you can start calling the API from the client.
let api = Remoting.createApi() |> Remoting.buildProxy<ICustomerApi>
async {
let! customers = api.getCustomers()
for customer in customers do
printfn "#%d => %s" customer.Id customer.Name
}Notice here, that there is no need to configure routes or JSON serialization, worry about HTTP verbs, or even involve yourself with the Giraffe pipeline. If you open your browser network tab, you can easily inspect what remoting is doing behind the scenes.