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 =
Elem.html [ Attr.lang "en" ] [
Elem.head [] []
Elem.body [] [
Text.h1 "Sample App" // shorthand for: `Elem.h1 [] [ Text.raw "Sample App" ]`
]
]
Response.ofHtml html
// Automatically protect against XSS attacks
let secureHtmlHandler : HttpHandler =
let html token =
Elem.html [] [
Elem.body [] [
Elem.form [ Attr.method "post" ] [
Elem.input [ Attr.name "first_name" ]
Elem.input [ Attr.name "last_name" ]
// using the CSRF HTML helper
Xsrf.antiforgeryInput token
Elem.input [ Attr.type' "submit"; Attr.value "Submit" ]
]
]
]
Response.ofHtmlCsrf html
Alternatively, 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>"
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 name
let oldUrlHandler : HttpHandler =
Response.redirectPermanently "/new-url" // HTTP 301
let redirectUrlHandler : HttpHandler =
Response.redirectTemporarily "/new-url" // HTTP 302
let 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 bytes
Response 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.signInAndRedirect
andResponse.signOutAndRedirect
functions 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"