objects () |> functions


Quatro - Step 1

Having already made the leap to F#, we will now do our Hello World in Freya. This is adapted from the "Getting Started" article on their site.

First up, we'll attack project.json. This one will require more modifications* than the others. Let's start with the dependencies section:

1: 
2: 
3: 
4: 
5: 
6: 
"dependencies": {
  "Freya": "3.0.0-rc01",
  "Microsoft.AspNetCore.Owin": "1.0.0",
  "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
  "Microsoft.NETCore.Portable.Compatibility": "1.0.1"
},

Freya should be self-explanatory, and we've seen the Owin and Kestrel imports before. The new one is the last one, and this package provides fill-ins for some types that used to be defined in mscorlib (the big library-to-rule-them-all that went away between the full .NET framework and .NET Core).

The frameworks sections needs some attention as well:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
"frameworks": {
  "netcoreapp1.0": {
    "dependencies": {
      "Microsoft.NETCore.App": {
        "type": "platform",
        "version": "1.0.1"
      },
      "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-160831"
    },
    "imports": [
      "portable-net45+win8+dnxcore50",
      "portable-net45+win8",
      "net452",
      "dnxcore50"
    ]
  }
},

These imports allow us to use some Freya dependencies that target Portable Class Libraries (PCLs) that are supported by .NET Core. Finally, while we're there, change "Program.fs" to "App.fs" in the compiled file list, as we'll rename Program.fs to App.fs to remain consistent among the projects.

Now, for App.fs:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
namespace Quatro

open Freya.Core
open Freya.Machines.Http
open Freya.Routers.Uri.Template
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Hosting

Freya.Core gives us the freya computation expression, which we will use for the main part of our request handling. Freya.Machines.Http provides the freyaMachine computation expression, which allows us to define our request-response. Freya.Routers.Uri.Template provides the freyaRouter computation expression, where we assign an HTTP machine to a URL route pattern.

Continuing on...

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
module App =
  let hello =
    freya {
      return Represent.text "Hello World from Freya"
      }

  let machine =
    freyaMachine {
      handleOk hello
      }

  let router =
    freyaRouter {
      resource "/" machine
      }

This code uses the three expressions described above to define the response (hard-coded for now), the machine that uses it for its OK response, and the route that uses the machine.

Still within module App =...

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
  type Startup () =
    member __.Configure (app : IApplicationBuilder) =
      let freyaOwin = OwinMidFunc.ofFreya (UriTemplateRouter.Freya router)
      app.UseOwin (fun p -> p.Invoke freyaOwin) |> ignore

  [<EntryPoint>]
  let main _ =
    use host = (new WebHostBuilder()).UseKestrel().UseStartup<Startup>().Build()
    host.Run()
    0

This is the familiar Startup class from Tres, except that the Configure() method uses the Freya implementation instead of the Nancy implementation. Notice that the middleware function uses the router as the hook into the pipeline; that is how we get the OWIN request to be handled by Freya. Notice how much closer to idiomatic F# this code has become; the only place we had to ignore anything was the "seam" where we interoperated with the OWIN library.

dotnet run should succeed at this point, and localhost:5000 should display our Hello World message.

Back to Step 1


* - Huge props go to @neoeinstein for documenting these settings in this Gist. I had not seen the PCL compat package or an import for "net452" in .NET Core before this.

namespace Freya
namespace Freya.Core
Multiple items
module Freya

from Freya.Core.Inference

--------------------
module Freya

from Freya.Core

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

--------------------
type Freya<'a> = State -> Async<'a * State>

Full name: Freya.Core.Freya<_>
namespace Freya.Machines
namespace Freya.Machines.Http
namespace Freya.Routers
namespace Freya.Routers.Uri
namespace Freya.Routers.Uri.Template
namespace Microsoft
namespace Microsoft.AspNetCore
namespace Microsoft.AspNetCore.Builder
namespace Microsoft.AspNetCore.Hosting
module App

from Quatro
val hello : Freya<Representation>

Full name: Quatro.App.hello
val freya : FreyaBuilder

Full name: Freya.Core.Builder.freya
module Represent

from Freya.Machines.Http
val text : text:string -> Representation

Full name: Freya.Machines.Http.Represent.text
val machine : HttpMachine

Full name: Quatro.App.machine
val freyaMachine : HttpMachineBuilder

Full name: Freya.Machines.Http.Builder.freyaMachine
custom operation: handleOk ('a)

Calls HttpMachineBuilder.HandleOk
val router : UriTemplateRouter

Full name: Quatro.App.router
val freyaRouter : UriTemplateRouterBuilder

Full name: Freya.Routers.Uri.Template.Builder.freyaRouter
custom operation: resource ('a) ('b)

Calls UriTemplateRouterBuilder.Resource
Multiple items
type Startup =
  new : unit -> Startup
  member Configure : app:IApplicationBuilder -> unit

Full name: Quatro.App.Startup

--------------------
new : unit -> Startup
member Startup.Configure : app:IApplicationBuilder -> unit

Full name: Quatro.App.Startup.Configure
val app : IApplicationBuilder
type IApplicationBuilder =
  member ApplicationServices : IServiceProvider with get, set
  member Build : unit -> RequestDelegate
  member New : unit -> IApplicationBuilder
  member Properties : IDictionary<string, obj>
  member ServerFeatures : IFeatureCollection
  member Use : middleware:Func<RequestDelegate, RequestDelegate> -> IApplicationBuilder

Full name: Microsoft.AspNetCore.Builder.IApplicationBuilder
val freyaOwin : OwinMidFunc
Multiple items
module OwinMidFunc

from Freya.Core

--------------------
type OwinMidFunc = System.Func<OwinAppFunc,OwinAppFunc>

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

Full name: Freya.Core.OwinMidFunc.ofFreya
Multiple items
union case UriTemplateRouter.UriTemplateRouter: (UriTemplateRoutes -> unit * UriTemplateRoutes) -> UriTemplateRouter

--------------------
module UriTemplateRouter

from Freya.Routers.Uri.Template

--------------------
type UriTemplateRouter =
  | UriTemplateRouter of (UriTemplateRoutes -> unit * UriTemplateRoutes)
  static member Freya : router:UriTemplateRouter -> Freya<PipelineChoice>
  static member Pipeline : router:UriTemplateRouter -> Pipeline

Full name: Freya.Routers.Uri.Template.UriTemplateRouter
static member UriTemplateRouter.Freya : router:UriTemplateRouter -> Freya<PipelineChoice>
(extension) IApplicationBuilder.UseOwin() : System.Action<System.Func<System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>,System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>>>
(extension) IApplicationBuilder.UseOwin(pipeline: System.Action<System.Action<System.Func<System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>,System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>>>>) : IApplicationBuilder
val p : System.Action<System.Func<System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>,System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>>>
System.Action.Invoke(obj: System.Func<System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>,System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>>) : unit
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
Multiple items
type EntryPointAttribute =
  inherit Attribute
  new : unit -> EntryPointAttribute

Full name: Microsoft.FSharp.Core.EntryPointAttribute

--------------------
new : unit -> EntryPointAttribute
val main : string [] -> int

Full name: Quatro.App.main
val host : IWebHost
Multiple items
type WebHostBuilder =
  new : unit -> WebHostBuilder
  member Build : unit -> IWebHost
  member ConfigureLogging : configureLogging:Action<ILoggerFactory> -> IWebHostBuilder
  member ConfigureServices : configureServices:Action<IServiceCollection> -> IWebHostBuilder
  member GetSetting : key:string -> string
  member UseLoggerFactory : loggerFactory:ILoggerFactory -> IWebHostBuilder
  member UseSetting : key:string * value:string -> IWebHostBuilder

Full name: Microsoft.AspNetCore.Hosting.WebHostBuilder

--------------------
WebHostBuilder() : unit
(extension) IWebHost.Run() : unit
(extension) IWebHost.Run(token: System.Threading.CancellationToken) : unit
Fork me on GitHub