Skip to content

v2.0

Choose a tag to compare

@pimbrouwers pimbrouwers released this 12 Jul 00:25
· 749 commits to master since this release
0a18981

Release Notes

  • The markup DSL is qualified instead of bare functions.
    • Html.h1 vs h1
    • Attr.class' vs _class
  • Handlers considered end-to-end processors of a request.
    • Continuations are still possible by creating new HttpHandler function which accept another HttpHandler as a parameter.
    • As a result of this change, performance has increased.
  • Host setup functions have been added.
    • These functions (startWebHost and startWebHostDefault) simplify IHost creation.
  • Modular interop with the HttpContext.
    • Optional online extension methods are used to enrich the base library. This functionality is now exposed in a modular fashion (i.e. Response.withStatusCode vs ctx.SetStatusCode).
      • HttpContext based modules exist for: Request, Response, Auth & Xss

Migration Guide

This is a general guide on migrating v1.x.x code to v2.0.0. Both sample apps have been updated and serve as more complete references.

  • The definition of an HttpHandler (HttpContext -> Task) now resembles that of a native RequestDelegate
  • A new definition for any non-IO based modifications to the HttpResponse, called HttpResponseModifier with a definition of HttpContext -> HttpContext
  • Dealing with either the HttpRequest or HttpResponse is now achieved through the Request and Response modules respectively.

An example:

// v1.x.x
let notFound : HttpHandler =
    setStatusCode 404
    >=> textOut "Not Found"

// v2.0.0
let notFound : HttpHandler =
    Response.withStatusCode 404
    >> Response.ofPlainText "Not found"

Another example:

// v.1.x.x
let helloHandler : HttpHandler =
    fun next ctx ->        
        let greeting =
            ctx.tryGetRouteValue "name"
            |> Option.defaultValue "someone"
            |> sprintf "hi %s" 

        textOut

// v2.0.0
let helloHandler : HttpHandler =
    fun ctx ->        
        let greeting =
            Request.tryGetRouteValue "name" ctx 
            |> Option.defaultValue "someone"
            |> sprintf "hi %s" 

        Response.ofPlainText greeting ctx

Another example:

// v1.x.x
let exampleTryBindFormHandler : HttpHandler =
    tryBindForm 
        (fun r ->
            Ok {
              FirstName = form?FirstName.AsString()
              LastName  = form?LastName.AsString()
              Age       = form?Age.AsInt16()      
            })
        errorHandler 
        successHandler

// v2.0.0
let exampleTryBindFormHandler : HttpHandler =
    fun ctx ->
        let bindForm form =     
            {
              FirstName = form?FirstName.AsString()
              LastName  = form?LastName.AsString()
              Age       = form?Age.AsInt16()      
            }

        let respondWith =
            match Request.tryBindForm (bindForm >> Result.Ok) ctx with
            | Error error -> Response.ofPlainText error
            | Ok model    -> Response.ofPlainText (sprintf "%A" model)

        respondWith ctx

Markup

  • Falco.ViewEngine becomes Falco.Markup
  • Element level items now reside in a module called Elem. Thus div becomes Elem.div
    • ** You can import Falco.Markup.Elem and use without Elem. prefix
  • Element attributes are now reside in a module calls Attr. This _class becomes Attr.class'
    • ** Take note of the trailing apostrophe, which is used to delimit reserved keywords like class
  • Text elements now reside in a module called Text. Thus raw becomes Text.raw
    • ** You can import Falco.Markup.Text and use without Text. prefix

An example:

// v1.x.x
let doc = 
    html [] [
            head [] [            
                    title [] [ raw "Sample App" ]                                                    
                ]
            body [] [                     
                    h1 [] [ raw "Sample App" ]
                ]
        ] 

// v2.0.0
let doc = 
    Elem.html [ Attr.lang "en" ] [
            Elem.head [] [                    
                    Elem.title [] [ Text.raw "Sample App" ]                                                            
                ]
            Elem.body [] [                     
                    Elem.main [] [
                            Elem.h1 [] [ Text.raw "Sample App" ]
                        ]
                ]
        ]