• Stars
    star
    269
  • Rank 146,984 (Top 3 %)
  • Language
    F#
  • License
    MIT License
  • Created about 7 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Type-safe communication layer (RPC-style) for F# featuring Fable and .NET Apps

Fable.Remoting

Build Status Build status

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 Nuget
Fable.Remoting.Client Nuget
Fable.Remoting.Json Nuget
Fable.Remoting.Server Nuget
Fable.Remoting.Suave Nuget
Fable.Remoting.Giraffe Nuget
Fable.Remoting.AspNetCore Nuget
Fable.Remoting.DotnetClient Nuget
Fable.Remoting.AzureFunctions.Worker Nuget

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:

open Fable.Remoting.Server
open Fable.Remoting.AzureFunctions.Worker
open Microsoft.Azure.Functions.Worker
open Microsoft.Azure.Functions.Worker.Http
open Microsoft.Extensions.Logging

type Functions(log:ILogger<Functions>) =
    
    [<Function("Index")>]
    member _.Index ([<HttpTrigger(AuthorizationLevel.Anonymous, Route = "{*any}")>] req: HttpRequestData, ctx: FunctionContext) =
        Remoting.createApi()
        |> Remoting.withRouteBuilder FunctionsRouteBuilder.apiPrefix
        |> Remoting.fromValue myImplementation
        |> Remoting.buildRequestHandler
        |> HttpResponseData.fromRequestHandler req

Of course, having one implementation per Function App is not ideal, so HttpResponseData.fromRequestHandlers is here to the rescue:

type Functions(log:ILogger<Functions>) =
    
    [<Function("Index")>]
    member _.Index ([<HttpTrigger(AuthorizationLevel.Anonymous, Route = "{*any}")>] req: HttpRequestData, ctx: FunctionContext) =
        let handlerOne =
            Remoting.createApi()
            |> Remoting.withRouteBuilder FunctionsRouteBuilder.apiPrefix
            |> Remoting.fromValue myImplementationOne
            |> Remoting.buildRequestHandler
        
        let handlerTwo =
            Remoting.createApi()
            |> Remoting.withRouteBuilder FunctionsRouteBuilder.apiPrefix
            |> Remoting.fromValue myImplementationTwo
            |> Remoting.buildRequestHandler
        
        [ handlerOne; handlerTwo ] |> HttpResponseData.fromRequestHandlers req

Fable Client

Install Fable.Remoting.Client from nuget using Paket:

paket add Fable.Remoting.Client --project /path/to/Project.fsproj

Reference the shared types to your client project

<Compile Include="path/to/SharedTypes.fs" />

Start using the library:

open Fable.Remoting.Client
open SharedTypes

// studentApi : IStudentApi
let studentApi =
    Remoting.createApi()
    |> Remoting.buildProxy<IStudentApi>

async {
  // students : Student[]
  let! students = studentApi.allStudents()
  for student in students do
    // student : Student
    printfn "Student %s is %d years old" student.Name student.Age
}
|> Async.StartImmediate

Finally, when you are using webpack-dev-server, you have to change the config from this:

devServer: {
  contentBase: resolve('./public'),
  port: 8080
}

to this:

devServer: {
  contentBase: resolve('./public'),
  port: 8080,
  proxy: {
    '/*': { // tell webpack-dev-server to re-route all requests from client to the server
      target: "http://localhost:5000",// assuming the backend server is hosted on port 5000 during development
      changeOrigin: true
    }
}

That's it!

Dotnet Client

You can also use client functionality in non-fable projects, such as a console, desktop or mobile application.

Install Fable.Remoting.DotnetClient from nuget using Paket:

paket add Fable.Remoting.DotnetClient --project /path/to/Project.fsproj

Reference the shared types in your client project

<Compile Include="path/to/SharedTypes.fs" />

Start using the library:

open Fable.Remoting.DotnetClient
open SharedTypes

// studentApi : IStudentApi
let studentApi =
  Remoting.createApi "http://localhost:8085"
  |> Remoting.buildProxy<IStudentApi>

async {
  // students : Student[]
  let! students = studentApi.allStudents()
  for student in students do
    // student : Student
    printfn "Student %s is %d years old" student.Name student.Age
}
|> Async.StartImmediate

Notice here, that unlike the Fable client, you will need to provide the base Url of the backend because the dotnet client will be deployed separately from the backend.

Adding a new route

  • Add another record field function to IStudentApi
  • Implement that function
  • Restart server and client

Done! You can now use that function from the client too.

See the following article if you are interested in how this library is implemented (a bit outdated but gives you an overview of the mechanism) Statically Typed Client-Server Communication with F#: Proof of Concept

In-depth Introduction (Blog)

More Repositories

1

Feliz

A fresh retake of the React API in Fable and a collection of high-quality components to build React applications in F#, optimized for happiness
F#
511
star
2

the-elmish-book

A practical guide to building modern and reliable web applications in F# from first principles
HTML
323
star
3

Npgsql.FSharp

Thin F# wrapper around Npgsql, the PostgreSQL database driver for .NET
F#
305
star
4

tabula-rasa

Minimalistic real-worldish blogging platform, written entirely in F#, made as a learning reference for building large Elmish apps
F#
199
star
5

LiteDB.FSharp

Advanced F# Support for LiteDB, an embedded NoSql database for .NET with type-safe query expression through F# quotations
F#
179
star
6

Snowflaqe

A dotnet CLI to generate type-safe GraphQL clients for F# and Fable with automatic deserialization, static query verification and type checking
F#
150
star
7

Femto

Femto is a CLI tool that automatically resolves npm packages used by Fable bindings
F#
145
star
8

ThrowawayDb

Dead simple integration tests with SQL Server or Postgres throwaway databases that are created on the fly, used briefly then disposed of automagically.
C#
140
star
9

Npgsql.FSharp.Analyzer

F# analyzer that provides embedded SQL syntax analysis, type-checking for parameters and result sets and nullable column detection when writing queries using Npgsql.FSharp.
C#
132
star
10

Hawaii

dotnet CLI tool to generate type-safe F# and Fable clients from OpenAPI/Swagger or OData services
F#
122
star
11

SAFE.Simplified

A lightweight alternative template of SAFE for happy cross-IDE full-stack F# development
F#
101
star
12

Fable.SimpleHttp

Http with Fable, made simple.
F#
82
star
13

ClosedXML.SimpleSheets

Easily generate Excel sheets from F#
F#
80
star
14

DustyTables

Thin F# API for SqlClient for easy data access to ms sql server with functional seasoning on top
F#
74
star
15

Giraffe.GoodRead

Practical dependency injection in Giraffe that gets out of your way
F#
73
star
16

Feliz.Router

A router component for React and Elmish that is focused, powerful and extremely easy to use.
F#
72
star
17

Fable.SimpleJson

A library for working with JSON in Fable projects
F#
56
star
18

SAFE.React

Full Stack F# powered by ASP.NET Core on the backend and modern React on the frontend.
F#
54
star
19

Fable.Mocha

Fable library for a proper testing story using different runners such as mocha, standalone browsers and dotnet
F#
51
star
20

fabulous-simple-elements

An alternative view rendering API for Fabulous (Elmish Xamarin.Forms) that is easy to use and simple to read, inspired by Elmish on the web.
F#
46
star
21

desktop-feliz-with-photino

F#
43
star
22

fsharp-weekly

F# Weekly mobile, available for Android (soon iOS and UWP too)
F#
42
star
23

SAFE-TodoList

The simplest Todo app showcasing a client-server application written entirely in F#
F#
41
star
24

Giraffe.SerilogExtensions

Dead simple library to integrate Serilog within Giraffe apps: implemented as a composable HttpHandler and has native destructuring of F# types.
F#
30
star
25

dotnetconf-react-with-fsharp

Demo application used in DotnetCONF to build React applications with F#
F#
30
star
26

Elmish.SweetAlert

SweetAlert integration for Fable, made with ❀️ to work in Elmish apps. https://zaid-ajaj.github.io/Elmish.SweetAlert/
F#
29
star
27

Fable.DateFunctions

Fable binding for date-fns javascript library, implemented as extension methods for DateTime. See https://zaid-ajaj.github.io/Fable.DateFunctions/
F#
27
star
28

Fable.CloudFlareWorkers

Write CloudFlare Workers in idiomatic, type-safe F# and compile them to JS using Fable
F#
24
star
29

Elmish.Toastr

Toastr integration with Fable, implemented as Elmish commands https://zaid-ajaj.github.io/Elmish.Toastr/
F#
24
star
30

elmish-getting-started

A simple and minimalistic template to easily get up and running with Elmish and Fable
F#
22
star
31

Giraffe.QueryReader

HttpHandler for easily working with query string parameters within Giraffe apps.
F#
21
star
32

navigation-bar-with-feliz

Modern navigation bar built with Feliz
JavaScript
20
star
33

Giraffe.JsonTherapy

Simply extract JSON values from HTTP requests without defining intermediate types or using model binding
F#
19
star
34

fable-getting-started

Template for getting started with Fable
JavaScript
19
star
35

Feliz.ViewEngine.Htmx

A library that allows using Htmx attributes with Feliz.ViewEngine
F#
18
star
36

Fable.SimpleXml

A library for easily parsing and working with XML in Fable projects
F#
17
star
37

AlgebraFs

A simple computer algebra system (CAS), written in F# for fun and learning.
F#
15
star
38

Fable.React.Flatpickr

Fable binding for react-flatpickr that is ready to use within Elmish applications
F#
14
star
39

elmish-login-flow-validation

Elmish sample that demonstrates a login flow with user input validation
F#
13
star
40

pulumi-schema-explorer

Web application and UI to explore Pulumi schemas
F#
13
star
41

Fable.SqlClient

Fable Node client for Microsoft SQL Server, built around a node-mssql binding
F#
12
star
42

Elmish.AnimatedTree

An animated tree user interface made for Elmish applications
JavaScript
11
star
43

pulumi-csharp-analyzer

Roslyn-based static code analysis for pulumi programs written in C#
C#
11
star
44

Cable

Type-safe client-server communication for C# featuring Bridge.NET and NancyFx
C#
10
star
45

elmish-composition

A library to compare the different compositional techniques in Elmish applications
JavaScript
10
star
46

Nancy.Serilog

Nancy plugin for application-wide logging using Serilog
C#
9
star
47

scaling-elmish-programs

FableConf 2018 slides and apps used in the presentation
F#
8
star
48

Suave.SerilogExtensions

Suave plugin to use the awesome Serilog library as the logger for your application
F#
8
star
49

ElmCounterWPF

Pure F#/Xaml counter using Elmish.WPF and XAML type provider
F#
7
star
50

ReactCSharpDemo

Using React in C# with Bridge
C#
7
star
51

Fable.SimpleJson.Python

A library for working with JSON in F# Fable projects targeting Python
F#
7
star
52

Feliz.AntDesign

AntDesign bindings using Feliz syntax for a clean, discoverable and type-safe React components. (WIP)
F#
6
star
53

hawaii-samples-feliz-petstore

This is a sample application that shows how to use Feliz with a client generated by Hawaii
F#
6
star
54

elmish-wpf-template

A template for easily getting started with building WPF apps using Elmish
F#
5
star
55

elmish-routing

F#
4
star
56

Bridge.Redux

Bindings of the Redux library for the Bridge transpiler
C#
4
star
57

Fable.Requests

Fable library for making HTTP requests targeting Python
F#
4
star
58

elmish-todo-exercises

F#
4
star
59

ExcelPluginTemplate

Template project to create Excel Add-ins with F# and ExcelDNA
F#
3
star
60

elmish-calc

Calculator application with Fable and Fable-Elmish
F#
3
star
61

interop-fableconf2019

JavaScript
3
star
62

FifteenPuzzleWithFeliz

The small fifteen puzzle game I am building live on Twitch
JavaScript
3
star
63

docute-starter

a simple and easy to use project to start writing documentation with Docute
HTML
3
star
64

Bridge.ChartJS

Bindings for Chart.js library to be used in Bridge.NET projects
C#
3
star
65

Bridge.CanvasJS

CanvasJS C#-wrapper for Bridge.NET project.
C#
3
star
66

pulumi-workshop-automation-fsharp

This workshop will walk you through the basics of using the Automation API of Pulumi to create and deploy a Pulumi stack programmatically with F#
F#
3
star
67

FSharp.SimpleJson

A library for easily parsing, transforming and converting JSON in F#, ported from Fable.SimpleJson
F#
3
star
68

MandelbrotHaskell

Mandelbrot fractal as text (ASCII), written in Haskell
Haskell
2
star
69

hawaii-samples-petstore

PetStore API sample with Hawaii
F#
2
star
70

fsharp-exchange-2021

Code repository for the F# eXchange 2021 conference
F#
2
star
71

Cable.ArticleSample

Type-safe web app sample used to demonstrate Cable
C#
2
star
72

terraform-basic-vpc-to-pulumi

HCL
2
star
73

SAFE-FileUploadDownload

F#
2
star
74

hawaii-samples-odata-trippin

F#
2
star
75

ReactReduxTodoApp

Todo app written in pure C# with React and Redux
C#
2
star
76

login-with-url-extended

F#
2
star
77

Simple-Feliz-i18n

Using Feliz template, this repository shows how to implement a simple internationalization mechanism that makes parts of the application be dependent on the current users' locale.
JavaScript
2
star
78

Fable.React.Responsive

Fable binding for react-responsive that is ready to use within Elmish applications
F#
1
star
79

remoting-pure-kestrel

The simplest AspNetCore sample with Fable.Remoting using the Kestrel server
F#
1
star
80

Bridge.SweetAlert

SweetAlert bindings for the Bridge.NET project.
CSS
1
star
81

FableSuaveSample

Fable and Suave sample for integration-testing Fable.Remoting with Suave to the death
F#
1
star
82

Image-Processor

A program to process and filter images, written in C#.
C#
1
star
83

ChristianHolidaysAssignment

C++
1
star
84

gitbook-enhanced-katex

Math typesetting using KaTex for gitBook
JavaScript
1
star
85

pulumi-codegen-dotnet

Building Pulumi Codegen tooling in F#
F#
1
star
86

RemotingJsonBenchmarks

F#
1
star
87

elmish-todo-part1

F#
1
star
88

WindowsExplorer

A WPF application that mimics Windows Explorer functionality
C#
1
star
89

elmish-hackernews-part1

F#
1
star
90

elmish-todo-part2

F#
1
star
91

elmish-todo-part3

F#
1
star
92

fast-refresh-bug-reproduction

JavaScript
1
star
93

tagmeme-analyzer

Static code analyzer that checks for exhaustive pattern matching, union case typos and redundant arguments in tagmeme
JavaScript
1
star
94

xmlhttprequest-in-elmish

F#
1
star
95

Bridge.Ractive

Bindings of Ractive.js to be used in Bridge.NET projects.
JavaScript
1
star
96

elmish-hackernews-part3

F#
1
star