namespace Freya
namespace Freya.Core
Multiple items
module Freya

from Freya.Core

--------------------
namespace Freya

--------------------
type Freya<'T> = FreyaState -> Async<'T * FreyaState>

Full name: Freya.Core.Types.Freya<_>
namespace Freya.Machine
namespace Freya.Machine.Extensions
namespace Freya.Machine.Extensions.Http
namespace Microsoft
namespace Owin
namespace System
namespace System.IO
val freya : FreyaBuilder

Full name: Freya.Core.Syntax.freya
module State

from Freya.Core.Freya
val get : state:'a -> Async<'a * 'a>

Full name: Freya.Core.Freya.State.get
type Environment =
  static member CommandLine : string
  static member CurrentDirectory : string with get, set
  static member Exit : exitCode:int -> unit
  static member ExitCode : int with get, set
  static member ExpandEnvironmentVariables : name:string -> string
  static member FailFast : message:string -> unit + 1 overload
  static member GetCommandLineArgs : unit -> string[]
  static member GetEnvironmentVariable : variable:string -> string + 1 overload
  static member GetEnvironmentVariables : unit -> IDictionary + 1 overload
  static member GetFolderPath : folder:SpecialFolder -> string + 1 overload
  ...
  nested type SpecialFolder
  nested type SpecialFolderOption

Full name: System.Environment
Multiple items
namespace System.Configuration

--------------------
module Configuration

from Freya.Machine.Extensions.Http.Syntax

--------------------
module Configuration

from Freya.Machine
Multiple items
module OwinAppFunc

from Freya.Core.Integration

--------------------
type OwinAppFunc = Func<OwinEnvironment,Threading.Tasks.Task>

Full name: Freya.Core.Integration.OwinAppFunc
val ofFreya : freya:'a -> OwinAppFunc (requires member Freya)

Full name: Freya.Core.Integration.OwinAppFunc.ofFreya
Multiple items
type EntryPointAttribute =
  inherit Attribute
  new : unit -> EntryPointAttribute

Full name: Microsoft.FSharp.Core.EntryPointAttribute

--------------------
new : unit -> EntryPointAttribute
union case FreyaMachineNode.Start: FreyaMachineNode
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
type Console =
  static member BackgroundColor : ConsoleColor with get, set
  static member Beep : unit -> unit + 1 overload
  static member BufferHeight : int with get, set
  static member BufferWidth : int with get, set
  static member CapsLock : bool
  static member Clear : unit -> unit
  static member CursorLeft : int with get, set
  static member CursorSize : int with get, set
  static member CursorTop : int with get, set
  static member CursorVisible : bool with get, set
  ...

Full name: System.Console
Console.WriteLine() : unit
   (+0 other overloads)
Console.WriteLine(value: string) : unit
   (+0 other overloads)
Console.WriteLine(value: obj) : unit
   (+0 other overloads)
Console.WriteLine(value: uint64) : unit
   (+0 other overloads)
Console.WriteLine(value: int64) : unit
   (+0 other overloads)
Console.WriteLine(value: uint32) : unit
   (+0 other overloads)
Console.WriteLine(value: int) : unit
   (+0 other overloads)
Console.WriteLine(value: float32) : unit
   (+0 other overloads)
Console.WriteLine(value: float) : unit
   (+0 other overloads)
Console.WriteLine(value: decimal) : unit
   (+0 other overloads)
Console.ReadLine() : string
namespace Freya.Lenses
namespace Freya.Lenses.Http
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
union case Option.Some: Value: 'T -> Option<'T>
Multiple items
module Map

from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> =
  interface IEnumerable
  interface IComparable
  interface IEnumerable<KeyValuePair<'Key,'Value>>
  interface ICollection<KeyValuePair<'Key,'Value>>
  interface IDictionary<'Key,'Value>
  new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
  member Add : key:'Key * value:'Value -> Map<'Key,'Value>
  member ContainsKey : key:'Key -> bool
  override Equals : obj -> bool
  member Remove : key:'Key -> Map<'Key,'Value>
  ...

Full name: Microsoft.FSharp.Collections.Map<_,_>

--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
val empty<'Key,'T (requires comparison)> : Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.empty
type Type =
  inherit MemberInfo
  member Assembly : Assembly
  member AssemblyQualifiedName : string
  member Attributes : TypeAttributes
  member BaseType : Type
  member ContainsGenericParameters : bool
  member DeclaringMethod : MethodBase
  member DeclaringType : Type
  member Equals : o:obj -> bool + 1 overload
  member FindInterfaces : filter:TypeFilter * filterCriteria:obj -> Type[]
  member FindMembers : memberType:MemberTypes * bindingAttr:BindingFlags * filter:MemberFilter * filterCriteria:obj -> MemberInfo[]
  ...

Full name: System.Type
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
namespace System.Text
val init : x:'T -> state:FreyaState -> Async<'T * FreyaState>

Full name: Freya.Core.Freya.init
union case Option.None: Option<'T>
Multiple items
namespace System.Data

--------------------
namespace Microsoft.FSharp.Data
val freyaMachine : FreyaMachineBuilder

Full name: Freya.Machine.Syntax.freyaMachine
val using : resource:'T -> action:('T -> 'U) -> 'U (requires 'T :> IDisposable)

Full name: Microsoft.FSharp.Core.Operators.using
val http : FreyaMachineExtension

Full name: Freya.Machine.Extensions.Http.Extension.http

Freya

Freya visual debugging

Contents

  • History
  • Freya
  • Examples
  • Machine/Leness
  • Questions?

History

OWIN

Open Web Interface for .NET

Problems:

  • Hard to break away from Asp.net/IIS
  • Lot of repetition (E.G. auth for each framework)

Goal: A standard interface between the server and application

Support Includes:

Host

  • Katana
  • Kestrel
  • Nowin
  • Suave
  • IIS/Express Adapter

Application

  • Nancy
  • Signal R
  • Asp.net
  • ServiceStack
  • etc

Freya

Gist

  • Function style web programming stack built on OWIN
  • HTTP is Functional
  • Enforce the pit of success
  • It's a library, not a framework

Library

Lib

Framework

Framework

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
module MyWebSite

open System
open System.IO
open Freya.Core
open Microsoft.Owin.Hosting

let helloWorld =
    freya {
        let text = "Hello World"B
        let! state = Freya.State.get
        state.Environment.["owin.ResponseStatusCode"] <- 200
        state.Environment.["owin.RepsonseReasonPhrase"] <- "Awesome"
        state.Environment.["owin.ResponseBody"] :?> Stream
            |> fun x -> x.Write (text, 0, text.Length)
        }

type Exercise() =
    member __.Configuration() =
        OwinAppFunc.ofFreya helloWorld

[<EntryPoint>]
let main _ =
    let url = "http://localhost:8080"
    WebApp.Start<Exercise> (url) |> ignore
    Console.WriteLine("Serving site at " + url)
    Console.WriteLine("Press ENTER to cancel")
    Console.ReadLine |> ignore

Provides several layers of abstractions

Freya logo

Strongly Typed with Arachne

  • RFC 7230 – Message Syntax and Routing
  • RFC 7231 – Semantics and Content
  • RFC 7232 – Conditional Requests
  • RFC 7233 – Range Requests
  • RFC 7234 – Caching
  • RFC 7235 – Authentication
  • Everything HTTP is typed
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
// Working with Freya lenses
open Freya.Lenses.Http

// Working directly with the types if required
open Arachne.Http

// The previous way, using raw access to the state
let readPathRaw =
    freya {
        let! state = Freya.getState
        return state.Environment.["owin.RequestPath"] :?> string }

// The lens way
let readPathLens =
    freya {
        return! Freya.get Request.path_ }

Typed

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
let readAccept =
    freya {
        return! Freya.get Request.Headers.accept_ }

// Might return something like...

Some (Accept [
    AcceptableMedia (
        Open (Parameters (Map.empty)),
        Some (AcceptParameters (Weight 0.3, Extensions (Map.empty))))
    AcceptableMedia (
        Partial (Type "text", Parameters (Map.empty)),
        Some (AcceptParameters (Weight 0.9, Extensions (Map.empty)))) ])

Lenses

Lenses are a functional technique to enable us to work with complex data structures more easily

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
type Page = { Number: int; Footnote: string; Content: string }
type Book = { Title: string; Page: Page }
type Author = { Name: string; Book: Book }

// Given a Book we can trivially retrieve its page's content:
let pageContent = author.Book.Page.Content

// Setting the page nummber is a bit more problematic though. 
//If this were mutable, we could just do:
author.Book.Page.Number <- 15

// But it's not, so we use F# copy-and-update syntax:
let author2 = { author with Book = 
                { author.Book with Page = 
                    { author.Book.Page with Number = 15 } } }
                    

Machines

A way of navigating graphs

HTTP is complex

Http machine

A request

Graph

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
// Properties
let mediaTypes = [ MediaType.Text ]
let methods = [ GET ]

// Decisions
let available = Freya.init true

// Handlers
let content _ =
    Freya.init
      {  Description =
            {  Charset = Some Charset.Utf8
               Encodings = None
               MediaType = Some MediaType.Text
               Languages = None }
         Data = "Hello World!"B } }

// Resource
let helloWorld =
    freyaMachine {
        using http
        mediaTypesSupported mediaTypes
        methodsSupported methods
        serviceAvailable available
        handleOk content } 

type Exercise() =
    member __.Configuration() =
        OwinAppFunc.ofFreya helloWorld

[<EntryPoint>]
let main _ =
    let url = "http://localhost:8080"
    let _ = WebApp.Start<Exercise> (url)
    Console.WriteLine("Serving site at " + url)
    Console.WriteLine("Press ENTER to cancel")
    let _ = Console.ReadLine ()
    0

Examples

  • Routing
  • Content Negotiation
  • HTML Rendering

Questions?