Web Development

46.1 ASP.NET Core Minimal APIs in F#

open System
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Http

type Todo = { Id: int; Title: string; Done: bool }

[<EntryPoint>]
let main args =
    let builder = WebApplication.CreateBuilder(args)
    let app = builder.Build()
    let todos = Collections.Concurrent.ConcurrentDictionary<int, Todo>()

    app.MapGet("/", Func<string>(fun () -> "Hello from F#")) |> ignore
    app.MapGet("/todos", Func<Todo seq>(fun () -> todos.Values)) |> ignore
    app.MapPost("/todos", Func<Todo, IResult>(fun todo ->
        todos[todo.Id] <- todo
        Results.Created($"/todos/{todo.Id}", todo))) |> ignore
    app.MapGet("/todos/{id}", Func<int, IResult>(fun id ->
        match todos.TryGetValue id with
        | true, t -> Results.Ok t
        | _ -> Results.NotFound())) |> ignore

    app.Run()
    0

46.2 Giraffe (Functional HTTP Handlers)

An HttpHandler is a function of type HttpFunc -> HttpContext -> Task<HttpContext option>, composed with >=> (the "fish" operator).

open Giraffe
open Microsoft.AspNetCore.Builder
open Microsoft.Extensions.DependencyInjection

type Greeting = { Message: string }

let webApp =
    choose [
        GET >=> choose [
            route "/" >=> text "Hello from Giraffe"
            routef "/hello/%s" (fun name -> json { Message = $"Hello, {name}!" })
            route "/ping" >=> setStatusCode 200 >=> text "pong"
        ]
        POST >=> route "/echo" >=> bindJson<Greeting> (fun g -> json g)
        setStatusCode 404 >=> text "Not Found"
    ]

let builder = WebApplication.CreateBuilder()
builder.Services.AddGiraffe() |> ignore
let app = builder.Build()
app.UseGiraffe webApp
app.Run()

46.3 Other Frameworks

Functional handlers on ASP.NET Core, Giraffe.ViewEngine for HTML

Opinionated MVC-like framework on Giraffe (application { }, router { }, controller { })

Lightweight, fast, functional-first toolkit Modern Giraffe-inspired framework (endpoint routing, Oxpecker.ViewEngine, Solid.js bindings) F# in WebAssembly via Blazor (MVU) SAFE Stack

Saturn + Azure + Fable + Elmish full-stack template (dotnet new SAFE) Full-stack F# web framework

Type-safe RPC between F# server and Fable client

// Saturn
open Saturn
let appRouter = router {
    get "/" (text "Hello from Saturn")
    getf "/hello/%s" (fun name -> text $"Hi {name}")
}
let app = application { use_router appRouter; url "http://0.0.0.0:8085" }
run app