SaturnFramework / Saturn

Opinionated, web development framework for F# which implements the server-side, functional MVC pattern
https://saturnframework.org
MIT License
715 stars 109 forks source link

Some application builder extensions #254

Open Thorium opened 4 years ago

Thorium commented 4 years ago

A few ideas what to add to ApplicationBuilder for some common web-application scenarios:

let app = 
   application {
      index_page "index.html"
      default_error_page "error.html"
      blacklist_filter_urls ["%252F%252F";"%2F%2F";".%2F";".%252F";"%3C";"%253C";".."]
      static_files_auth_required ["userhomepage.html"; "paymentcards.html"]
      static_files_corsMap corsToMime
      domain_redirect ["www.mydomain.com", "mydomain.com"; "myold.com", "mydomain.com"]
      allow_facebook_auth
   }

static_files_corsMap: Cors-header-setting by file type (or mime type). Not all filetypes are equally sensitive for cross-sites. The use_cors has already some kind of policy-name, it would be nice to be able to map those policies easily to some corresponding static file types.

Some of these might be silly, because I don't know Saturn well yet. Some of these features (application firewall security, start&error-pages) can probably be set from the product where on-top-of Saturn sits (IIS/Kestrel/...), but then again, why not from here...

Thorium commented 4 years ago

One question is that commands like allow_facebook_auth and use_signalr would add external dependencies, then should these 10 lines-of-code blocks components released as separate nuget packages just for that, or would there be another kind of plugin models available.

Krzysztof-Cieslak commented 4 years ago

Hey, thanks for the suggestions. To go one by one

Shmew commented 4 years ago

I've been working on a SignalR wrapper for Giraffe/Saturn. It's definitely not a small chunk of code, at least if you want it to be properly safe (which is the reason I'm working on this).

Which currently is designed like this:

application {
    use_signalr (
        configure_signalr {
            endpoint Endpoints.Root
            update SignalRHub.update
            with_on_connected (fun _ -> task { return printfn "Howdy!" })
        }
    )
    ...
}

(I'd love to know if there was a way to eliminate the need for the nesting here to use the CE.)

module SignalRHub =
    open Fable.SignalR
    open SignalRHub

    let update (msg: Action) (hubContext: FableHub<Action,Response>) =
        printfn "New Msg: %A" msg

        match msg with
        | Action.SayHello ->
            Response.Howdy
        | Action.IncrementCount i ->
            Response.NewCount(i + 1)
        | Action.DecrementCount i ->
            Response.NewCount(i - 1)
        | Action.RandomCharacter ->
            let characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

            System.Random().Next(0,characters.Length-1)
            |> fun i -> characters.ToCharArray().[i]
            |> string
            |> Response.RandomCharacter
        |> hubContext.Clients.Caller.Send

There's probably value in an additional package that just does a simple implementation for people not using Fable (such as native JS apps), as this is a bit more restrictive to ensure safety.