Fable.Remoting
Type-safe communication layer (RPC-style) for F# featuring Fable and .NET Apps
Install / Use
/learn @Zaid-Ajaj/Fable.RemotingREADME
Fable.Remoting
Fable.Remoting is a RPC communication layer for Fable and .NET apps, it abstracts away Http and Json and lets you think of your client-server interactions only in terms of pure stateless functions that are statically checked at compile-time:
Define a shared interface
This interface is a record type where each field is either Async<'T> or a function that returns Async<'T>
type IGreetingApi = {
greet : string -> Async<string>
}
Implement the interface on the server
let greetingApi = {
greet = fun name ->
async {
let greeting = sprintf "Hello, %s" name
return greeting
}
}
// Expose the implementation as a HTTP service
let webApp =
Remoting.createApi()
|> Remoting.fromValue greetingApi
Call the functions from the client
// get a typed-proxy for the service
let greetingApi =
Remoting.createApi()
|> Remoting.buildProxy<IGreetingApi>
// Start using the service
async {
let! message = greetingApi.greet "World"
printfn "%s" message // Hello, World
}
That's it, no HTTP, no JSON and it is all type-safe.
Applications using Remoting
- SAFE-TodoList A simple full-stack Todo list application (beginner)
- tabula-rasa a real-world-ish blogging platform (intermediate)
- Yobo Yoga Class Booking System implemented with Event Sourcing (advanced)
Full Documentation
The library runs everywhere on the backend: As Suave WebPart, as Giraffe/Saturn HttpHandler or any other framework as Asp.NET Core middleware. Clients can be Fable or .NET application.
"Fable.Remoting solves the age-old problem of keeping your front-end code in sync with your backend code at compile time, and in a language as enjoyable to use as F#" - David Falkner
Quick Start
Use the SAFE Simplified template where Fable.Remoting is already set up and ready to go
Available Packages:
| Library | Version |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| Fable.Remoting.MsgPack | |
| Fable.Remoting.Client |
|
| Fable.Remoting.Json |
|
| Fable.Remoting.Server |
|
| Fable.Remoting.Suave |
|
| Fable.Remoting.Giraffe |
|
| Fable.Remoting.AspNetCore |
|
| Fable.Remoting.DotnetClient |
|
| Fable.Remoting.AzureFunctions.Worker |
|
| Fable.Remoting.AwsLambda |
|
Scaffold from scratch - Suave
Create a new F# console app:
dotnet new console -lang F#
Define the types you want to share between client and server:
// SharedTypes.fs
module SharedTypes
type Student = {
Name : string
Age : int
}
// Shared specs between Server and Client
type IStudentApi = {
studentByName : string -> Async<Student option>
allStudents : unit -> Async<list<Student>>
}
The type IStudentApi is very important, this is the specification of the protocol between your server and client. Fable.Remoting expects such type to only have functions returning Async on the final result:
Async<A>
A -> Async<B>
A -> B -> Async<C>
// etc...
Try to put such types in seperate files to reference these files later from the Client
Then provide an implementation for IStudentApi on the server:
open SharedTypes
let getStudents() =
async {
return [
{ Name = "Mike"; Age = 23; }
{ Name = "John"; Age = 22; }
{ Name = "Diana"; Age = 22; }
]
}
let findStudentByName name =
async {
let! students = getStudents()
let student = List.tryFind (fun student -> student.Name = name) students
return student
}
let studentApi : IStudentApi = {
studentByName = findStudentByName
allStudents = getStudents
}
Now that we have the implementation studentApi, you can expose it as a web service from different web frameworks. We start with Suave
Install the library from Nuget using Paket:
paket add Fable.Remoting.Suave --project /path/to/Project.fsproj
Create a WebPart from the value studentApi
open Suave
open Fable.Remoting.Server
open Fable.Remoting.Suave
let webApp : WebPart =
Remoting.createApi()
|> Remoting.fromValue studentApi
|> Remoting.buildWebPart
// start the web server
startWebServer defaultConfig webApp
Yes, it is that simple.
You can think of the webApp value as if it was the following in pseudo-code:
let webApp =
choose [
POST
>=> path "/IStudentApi/studentByName"
>=> (* deserialize request body (from json) *)
>=> (* invoke studentApi.getStudentByName with the deserialized input *)
>=> (* give client the output back serialized (to json) *)
// other routes
]
You can enable diagnostic logging from Fable.Remoting.Server (recommended) to see how the library is doing it's magic behind the scenes :)
let webApp =
Remoting.createApi()
|> Remoting.fromValue studentApi
|> Remoting.withDiagnosticsLogger (printfn "%s")
|> Remoting.buildWebPart
AspNetCore Middleware
Install the package from Nuget using paket
paket add Fable.Remoting.AspNetCore --project /path/to/Project.fsproj
Now you can configure your remote handler as AspNetCore middleware
let webApp =
Remoting.createApi()
|> Remoting.fromValue studentApi
let configureApp (app : IApplicationBuilder) =
// Add Remoting handler to the ASP.NET Core pipeline
app.UseRemoting webApp
[<EntryPoint>]
let main _ =
WebHostBuilder()
.UseKestrel()
.Configure(Action<IApplicationBuilder> configureApp)
.Build()
.Run()
0
Giraffe
You can follow the Suave part up to the library installation, where it will become:
paket add Fable.Remoting.Giraffe --project /path/to/Project.fsproj
Now instead of a WebPart, by opening the Fable.Remoting.Giraffe namespace, you will get a HttpHandler from the value server:
open Giraffe
open Fable.Remoting.Server
open Fable.Remoting.Giraffe
let webApp : HttpHandler =
Remoting.createApi()
|> Remoting.fromValue studentApi
|> Remoting.buildHttpHandler
let configureApp (app : IApplicationBuilder) =
// Add Giraffe to the ASP.NET Core pipeline
app.UseGiraffe webApp
let configureServices (services : IServiceCollection) =
// Add Giraffe dependencies
services.AddGiraffe() |> ignore
[<EntryPoint>]
let main _ =
WebHostBuilder()
.UseKestrel()
.Configure(Action<IApplicationBuilder> configureApp)
.ConfigureServices(configureServices)
.Build()
.Run()
0
Saturn
You can use the same webApp generated by the Giraffe library.
open Saturn
open Fable.Remoting.Server
open Fable.Remoting.Giraffe
let webApp : HttpHandler =
Remoting.createApi()
|> Remoting.fromValue studentApi
|> Remoting.buildHttpHandler
let app = application {
url "http://127.0.0.1:8083/"
use_router webApp
}
run app
Azure Functions (isolated)
To use Azure Functions in isolated mode with custom HttpTrigger as serverless remoting server, just install:
dotnet add package Fable.Remoting.AzureFunctions.Worker
or using paket
paket add Fable.Remoting.AzureFunctions.Worker --project /path/to/Project.fsproj
Since Azure Functions don't know anything about HttpHandler we need to use built-in HttpRequestData and HttpResponseData objects. Luckily we have Remoting.buildRequestHandler and HttpResponseData.fromRequestHandler functions to the rescue:
Related Skills
node-connect
338.7kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
338.7kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.6kCommit, push, and open a PR
