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()
046.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