v2.0
Release Notes
- The markup DSL is qualified instead of bare functions.
Html.h1vsh1Attr.class'vs_class
- Handlers considered end-to-end processors of a request.
- Continuations are still possible by creating new
HttpHandlerfunction which accept anotherHttpHandleras a parameter. - As a result of this change, performance has increased.
- Continuations are still possible by creating new
- Host setup functions have been added.
- These functions (
startWebHostandstartWebHostDefault) simplifyIHostcreation.
- These functions (
- 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.withStatusCodevsctx.SetStatusCode).HttpContextbased modules exist for: Request, Response, Auth & Xss
- Optional online extension methods are used to enrich the base library. This functionality is now exposed in a modular fashion (i.e.
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 nativeRequestDelegate - A new definition for any non-IO based modifications to the
HttpResponse, calledHttpResponseModifierwith a definition ofHttpContext -> HttpContext - Dealing with either the
HttpRequestorHttpResponseis now achieved through theRequestandResponsemodules 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 ctxAnother 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 ctxMarkup
Falco.ViewEnginebecomesFalco.Markup- Element level items now reside in a module called
Elem. ThusdivbecomesElem.div- ** You can import
Falco.Markup.Elemand use withoutElem.prefix
- ** You can import
- Element attributes are now reside in a module calls
Attr. This_classbecomesAttr.class'- ** Take note of the trailing apostrophe, which is used to delimit reserved keywords like
class
- ** Take note of the trailing apostrophe, which is used to delimit reserved keywords like
- Text elements now reside in a module called
Text. ThusrawbecomesText.raw- ** You can import
Falco.Markup.Textand use withoutText.prefix
- ** You can import
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" ]
]
]
]