open Donald open System.Data.Common open System.Data.SQLite open System.Threading.Tasks open Giraffe open Giraffe.ViewEngine open FsToolkit.ErrorHandling open Microsoft.AspNetCore.Builder [] type EmailAddress = | Private | Public of string type PublicUserInformation = { Id: int Username: string EmailAddress: EmailAddress } module User = let read (reader: DbDataReader) = { Id = reader.ReadInt32 "id" Username = reader.ReadString "username" EmailAddress = match reader.ReadBoolean "is_email_visible" with | true -> EmailAddress.Public(reader.ReadString "email_address") | false -> EmailAddress.Private } let queryUserById id = use connection = new SQLiteConnection("Data Source=local.db") let query = "select * from users where id = @id" connection |> Db.newCommand query |> Db.setParams [ "id", SqlType.Int id ] |> Db.Async.querySingle User.read let userNotFoundView = main [] [ p [] [ str "This user does not exist :(" ] ] let userView user = main [] [ p [] [ str $"User ID: {user.Id}" ] p [] [ str $"Username: {user.Username}" ] match user.EmailAddress with | EmailAddress.Private -> p [] [ str "This user has a private email address" ] | EmailAddress.Public email -> p [] [ str $"Email address: {email}" ] ] let renderUserOrNotFound potentialUser = potentialUser |> Option.map userView |> Option.defaultValue userNotFoundView let renderUserHandler userId = fun next ctx -> userId |> queryUserById |> Task.map renderUserOrNotFound |> Task.bind (fun view -> htmlView view next ctx) let handler: HttpHandler = routef "/users/%i" renderUserHandler let webApplicationBuilder = WebApplication.CreateBuilder() webApplicationBuilder.Services.AddGiraffe() |> ignore let webApp = webApplicationBuilder.Build() webApp.UseGiraffe handler webApp.Run()