The HttpHandler type is used to represent the processing of a request. It can be thought of as the eventual (i.e., asynchronous) completion and processing of an HTTP request, defined in F# as: HttpContext -> Task. Handlers will typically involve some combination of: route inspection, form/query binding, business logic and finally response writing. With access to the HttpContext you are able to inspect all components of the request, and manipulate the response in any way you choose.
let textHandler : HttpHandler =
Response.ofPlainText "hello world"Write your views in plain F#, directly in your assembly, using the Markup module. A performant F# DSL capable of generating any angle-bracket markup. Also available directly as a standalone NuGet package.
let htmlHandler : HttpHandler =
let html =
_html [ _lang_ "en" ] [
_head [] []
_body [] [
_h1' "Sample App" // shorthand for: `_h1 [] [ Text.raw "Sample App" ]`
]
]
Response.ofHtml html
// Automatically protect against XSS attacks
let secureHtmlHandler : HttpHandler =
let html token =
_html [] [
_body [] [
_form [ _method_ "post" ] [
_input [ _name_ "first_name" ]
_input [ _name_ "last_name" ]
// using the CSRF HTML helper
Xsrf.antiforgeryInput token
_input [ _type_ "submit"; _value_ "Submit" ]
]
]
]
Response.ofHtmlCsrf htmlAlternatively, if you're using an external view engine and want to return an HTML response from a string literal, then you can use Response.ofHtmlString.
let htmlHandler : HttpHandler =
Response.ofHtmlString "<html>...</html>"If you want to return a fragment of HTML, for example when working with htmx, you can use Response.ofFragment (or Response.ofFragmentCsrf). This function takes an element ID as its first argument, and a XmlNode as its second argument. The server will return only the contents of the node with the specified ID.
let fragmentHandler : HttpHandler =
let html =
_div [ _id_ "greeting" ] [
_h1 [ _id_ "heading" ] [ _text "Hello, World!" ]
]
Response.ofFragment "heading" htmlThis will return only the contents of the h1 element, i.e. <h1 id="heading">Hello, World!</h1>. In the case of multiple elements with the same ID, the first one found will be returned. If no element with the specified ID is found, an empty response will be returned.
These handlers use the .NET built-in System.Text.Json.JsonSerializer.
type Person =
{ First : string
Last : string }
let jsonHandler : HttpHandler =
let name = { First = "John"; Last = "Doe" }
Response.ofJson name
let jsonOptionsHandler : HttpHandler =
let options = JsonSerializerOptions()
options.DefaultIgnoreCondition <- JsonIgnoreCondition.WhenWritingNull
let name = { First = "John"; Last = "Doe" }
Response.ofJsonOptions options namelet oldUrlHandler : HttpHandler =
Response.redirectPermanently "/new-url" // HTTP 301
let redirectUrlHandler : HttpHandler =
Response.redirectTemporarily "/new-url" // HTTP 302let inlineBinaryHandler : HttpHandler =
let contentType = "image/jpeg"
let headers = [ HeaderNames.CacheControl, "no-store, max-age=0" ]
let bytes = // ... binary data
Response.ofBinary contentType headers bytes
let attachmentHandler : HttpHandler =
let filename = "profile.jpg"
let contentType = "image/jpeg"
let headers = [ HeaderNames.CacheControl, "no-store, max-age=0" ]
let bytes = // ... binary data
Response.ofAttachment filename contentType headers bytesResponse modifiers can be thought of as the in-and-out modification of the HttpResponse. A preamble to writing and returning. Since these functions receive the Httpcontext as input and return it as the only output, they can take advantage of function compoistion.
let notFoundHandler : HttpHandler =
Response.withStatusCode 404
>> Response.ofPlainText "Not found"let handlerWithHeaders : HttpHandler =
Response.withHeaders [ "Content-Language", "en-us" ]
>> Response.ofPlainText "Hello world"IMPORTANT: Do not use this for authentication. Instead use the
Response.signInAndRedirectandResponse.signOutAndRedirectfunctions found in the Authentication module.
let handlerWithCookie : HttpHandler =
Response.withCookie "greeted" "1"
>> Response.ofPlainText "Hello world"
let handlerWithCookieOptions : HttpHandler =
let options = CookieOptions()
options.Expires <- DateTime.Now.Minutes(15)
Response.withCookie options "greeted" "1"
>> Response.ofPlainText "Hello world"