xyncro / freya

Freya Web Stack - Meta-Package
https://freya.io
Other
330 stars 30 forks source link

Documentation or Examples on handling Cookies #197

Closed ptrelford closed 6 years ago

ptrelford commented 6 years ago

Is there any documentation or examples on handling Cookies with Freya?

ptrelford commented 6 years ago

I think I've managed to find some source code: https://github.com/xyncro/freya-types/blob/master/src/Freya.Types.Http.State/Types.fs

and some tests: https://github.com/xyncro/freya-types/blob/master/tests/Freya.Types.Http.State.Tests/Types.fs

kolektiv commented 6 years ago

Yes, the types in Http.State, along with the associated Optics in Optics.Http.State (from memory) should allow you to work with cookies in pretty much any normal Freya<_> function...

ptrelford commented 6 years ago

OK, thanks @kolektiv, so say I'm trying to set a Cookie using the hello world app. I've referenced the Freya.Types.Http.State package.

Opened the relevant namespaces:

open Freya.Optics.Http
open Freya.Types.Http.State

Have a SetCookie value:

let setCookie =
    SetCookie (
        Pair (Name "test", Value "value"),
        Attributes [
            Expires (DateTime.Parse "1994/10/29 19:43:31")
            MaxAge (TimeSpan.FromSeconds 42.)
            Domain (SubDomain "www.example.com")
            Path ("/some/path")
            Secure
            HttpOnly ])

How and where would I use the SetCookie value?

let hello =
    freya {
        let! name = name
        /// ... cookie here? if so, what would it look like?
        return Represent.text (sprintf "Hello %s!" name) }

let machine =
    freyaMachine {
        // ... or cookie code here? if so, what would it look like?
        handleOk hello }

I've looked in https://github.com/xyncro/freya-optics/blob/master/src/Freya.Optics.Http/Response.fs and can see functions for headers like status code and age but I can't seeing anything explicitly for cookies, how would you do it?

kolektiv commented 6 years ago

Hmmm, that's an interesting one as I thought we had optics for cookies... @neoeinstein do you remember seeing some? 😄 If you were setting the cookie, you would want to do it in your hello handler in the example above - it would look something like Freya.Optic.set Response.cookie setCookie - given that suitable optic. I'll hunt around and see whether I have one and it's just unpublished...

ptrelford commented 6 years ago

@kolektiv here's some code to work around the missing functions for cookies:

module Request =
    open Aether.Operators
    open Freya.Optics
    let (*private*) value_ key (tryParse, format) =
        Request.header_ key
        >-> Option.mapEpimorphism (tryParse >> Option.ofResult, format)
    module Headers=
        let cookie_ =
            value_ "Cookie" (Cookie.tryParse, Cookie.format)

module Response =
    open Aether.Operators
    open Freya.Optics
    let (*private*) value_ key (tryParse, format) =
        Response.header_ key
        >-> Option.mapEpimorphism (tryParse >> Option.ofResult, format)
    module Headers =
        let setCookie_ =
            value_ "Set-Cookie" (SetCookie.tryParse, SetCookie.format)

let testSetCookie =
    SetCookie (
        Pair (Name "test", Value "value"),
        Attributes [
            Expires (DateTime.Parse "2037/10/29 19:43:31")
            Domain (SubDomain "localhost:7000")
            Path ("/") ])

let hello =
    freya {
        let! name = name
        let! cookie = Freya.Optic.get Request.Headers.cookie_
        match cookie with
        | Some cookie -> printfn "%A" cookie
        | None -> printfn "No cookie"
        do! Freya.Optic.set Response.Headers.setCookie_ (Some testSetCookie)
        return Represent.text (sprintf "Hello %s!" name) }