Full Code of pimbrouwers/Falco for AI

master 3b8475ac1ed7 cached
101 files
663.8 KB
184.1k tokens
12 symbols
1 requests
Download .txt
Showing preview only (698K chars total). Download the full file or copy to clipboard to get everything.
Repository: pimbrouwers/Falco
Branch: master
Commit: 3b8475ac1ed7
Files: 101
Total size: 663.8 KB

Directory structure:
gitextract_7tuo7p7z/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── build.yml
├── .gitignore
├── Build.ps1
├── CHANGELOG.md
├── CNAME
├── Falco.sln
├── LICENSE
├── README.md
├── docs/
│   ├── CNAME
│   ├── docs/
│   │   ├── authentication.html
│   │   ├── cross-site-request-forgery.html
│   │   ├── deployment.html
│   │   ├── example-basic-rest-api.html
│   │   ├── example-dependency-injection.html
│   │   ├── example-external-view-engine.html
│   │   ├── example-hello-world-mvc.html
│   │   ├── example-hello-world.html
│   │   ├── example-htmx.html
│   │   ├── example-open-api.html
│   │   ├── get-started.html
│   │   ├── host-configuration.html
│   │   ├── index.html
│   │   ├── markup.html
│   │   ├── migrating-from-v4-to-v5.html
│   │   ├── request.html
│   │   ├── response.html
│   │   └── routing.html
│   ├── index.html
│   ├── prism.css
│   ├── prism.js
│   ├── style.css
│   └── tachyons.css
├── documentation/
│   ├── authentication.md
│   ├── cross-site-request-forgery.md
│   ├── deployment.md
│   ├── example-basic-rest-api.md
│   ├── example-dependency-injection.md
│   ├── example-external-view-engine.md
│   ├── example-hello-world-mvc.md
│   ├── example-hello-world.md
│   ├── example-htmx.md
│   ├── example-open-api.md
│   ├── get-started.md
│   ├── host-configuration.md
│   ├── markup.md
│   ├── migrating-from-v4-to-v5.md
│   ├── migrating-from-v5-to-v6.md
│   ├── readme.md
│   ├── request.md
│   ├── response.md
│   └── routing.md
├── examples/
│   ├── BasicRestApi/
│   │   ├── BasicRestApi.fs
│   │   ├── BasicRestApi.fsproj
│   │   └── appsettings.json
│   ├── DependencyInjection/
│   │   ├── DependencyInjection.fs
│   │   └── DependencyInjection.fsproj
│   ├── ExternalViewEngine/
│   │   ├── ExternalViewEngine.fs
│   │   └── ExternalViewEngine.fsproj
│   ├── Falco.Examples.sln
│   ├── HelloWorld/
│   │   ├── HelloWorld.fs
│   │   └── HelloWorld.fsproj
│   ├── HelloWorldMvc/
│   │   ├── HelloWorldMvc.fs
│   │   ├── HelloWorldMvc.fsproj
│   │   ├── appsettings.json
│   │   └── wwwroot/
│   │       └── style.css
│   ├── Htmx/
│   │   ├── Htmx.fs
│   │   ├── Htmx.fsproj
│   │   └── appsettings.json
│   └── OpenApi/
│       ├── OpenApi.fs
│       └── OpenApi.fsproj
├── global.json
├── site/
│   ├── Site.fs
│   └── Site.fsproj
├── src/
│   └── Falco/
│       ├── Core.fs
│       ├── Falco.fsproj
│       ├── Multipart.fs
│       ├── Request.fs
│       ├── RequestData.fs
│       ├── RequestValue.fs
│       ├── Response.fs
│       ├── Routing.fs
│       ├── Security.fs
│       ├── String.fs
│       └── WebApplication.fs
└── test/
    ├── Falco.IntegrationTests/
    │   ├── Falco.IntegrationTests.fsproj
    │   └── Program.fs
    ├── Falco.IntegrationTests.App/
    │   ├── Falco.IntegrationTests.App.fsproj
    │   └── Program.fs
    └── Falco.Tests/
        ├── Common.fs
        ├── Falco.Tests.fsproj
        ├── MultipartTests.fs
        ├── Program.fs
        ├── RequestDataTests.fs
        ├── RequestTests.fs
        ├── RequestValueTests.fs
        ├── ResponseTests.fs
        ├── RoutingTests.fs
        ├── SecurityTests.fs
        ├── StringTests.fs
        └── WebApplicationTests.fs

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root=true

[*]
charset=utf-8
end_of_line=lf
trim_trailing_whitespace=true
insert_final_newline=true
indent_style=space
indent_size=4
max_line_length=120
tab_width=4

================================================
FILE: .github/workflows/build.yml
================================================
name: build

on:
  push:
    branches: [master]
    paths-ignore:
      - '**/*.md'
      - 'docs/**'
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET Core SDK
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: |
            8.0.x
            9.0.x
            10.0.x

      - name: Restore dependencies
        run: dotnet restore

      - name: Build
        run: dotnet build -c Release --no-restore

      - name: Unit Tests
        run: dotnet test test/Falco.Tests -c Release --no-build

      - name: Integration Tests
        run: dotnet test test/Falco.IntegrationTests -c Release --no-build


================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
[Ee]xamples/[Ss]andbox/
[Ss]andbox/
*.sqlite
[Mm]emory

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Mono auto generated files
mono_crash.*

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb

# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/
.DS_Store

# Rider (JetBrain's cross-platform .NET IDE) working folder
.idea/
.vscode/launch.json
.vscode/launch.json


================================================
FILE: Build.ps1
================================================
[CmdletBinding()]
param (
    [Parameter(HelpMessage="The action to execute.")]
    [ValidateSet("Build", "Test", "IntegrationTest", "Pack", "BuildSite", "DevelopSite")]
    [string] $Action = "Build",

    [Parameter(HelpMessage="The msbuild configuration to use.")]
    [ValidateSet("Debug", "Release")]
    [string] $Configuration = "Debug",

    [switch] $NoRestore,

    [switch] $Clean
)

function RunCommand {
    param ([string] $CommandExpr)
    Write-Verbose "  $CommandExpr"
    Invoke-Expression $CommandExpr
}

$rootDir = $PSScriptRoot
$srcDir = Join-Path $rootDir 'src'
$testDir = Join-Path $rootDir 'test'
$docsOutputDir = Join-Path $rootDir 'docs'

switch ($Action) {
    "Test"            { $projectdir = Join-Path $testDir 'Falco.Tests' }
    "IntegrationTest" { $projectdir = Join-Path $testDir 'Falco.IntegrationTests' }
    "Pack"            { $projectDir = Join-Path $srcDir 'Falco' }
    "BuildSite"       { $projectDir = Join-Path $rootDir 'site' }
    "DevelopSite"     { $projectDir = Join-Path $rootDir 'site' }
    Default           { $projectDir = Join-Path $srcDir 'Falco' }
}

if(!$NoRestore.IsPresent) {
    RunCommand "dotnet restore $projectDir --force --force-evaluate --nologo --verbosity quiet"
}

if ($Clean) {
    RunCommand "dotnet clean $projectDir -c $Configuration --nologo --verbosity quiet"
}

switch ($Action) {
    "Test"            { RunCommand "dotnet test `"$projectDir`"" }
    "IntegrationTest" { RunCommand "dotnet test `"$projectDir`"" }
    "Pack"            { RunCommand "dotnet pack `"$projectDir`" -c $Configuration --include-symbols --include-source" }
    "BuildSite"       { RunCommand "dotnet run --project `"$projectDir`" -- `"$docsOutputDir`"" }
    "DevelopSite"     { RunCommand "dotnet watch --project `"$projectDir`" -- run `"$docsOutputDir`"" }
    Default           { RunCommand "dotnet build `"$projectDir`" -c $Configuration" }
}


================================================
FILE: CHANGELOG.md
================================================
# Changelog

All notable changes to this project will be documented in this file.

## [6.0.0] - _unreleased_

### Added

- `Request.getBodyStringOptions` to allow configuration of the maximum request body size, with a default of `Multipart.DefaultMaxSize` (32MB).
- `Request.getFormOptions` to allow configuration of the maximum form size, with a default of `Multipart.DefaultMaxSize` (32MB).
- Guards to `RequestValue.parse` to prevent oversized numerics or leading-zero numeric strings (non-decimal) from being parsed as floats.
- Max size constraint to multipart form streaming, with a default of `Multipart.DefaultMaxSize` (32MB).
- `FormData.IsValid` property to indicate whether CSRF validation succeeded for form requests.

### Changed

- `Request.getForm` now automatically performs CSRF validation if antiforgery services are registered and the request method is POST, PUT, PATCH, or DELETE. Returns `FormData` with `IsValid = false` when validation fails.
- Increased multipart form streaming buffer size from 1024 to 8192 bytes to improve performance of large file uploads.
- `Request.ifAuthenticatedInRole` accepts roles as `seq` instead of `list` for more flexible input options.
- `Request.getJsonOptions` explicitly checks for application/json content type and empty body, returning default form of `T`. Returns 415 Unsupported Media Type response when content type is missing.
- `Response.signInOptions` and `Response.signOutOptions` now conditionally set status code 301 and Location header only when `AuthenticationProperties.RedirectUri` is present.
- `Response.challengeOptions` and `Response.challengeAndRedirect` now set status code 401 and WWW-Authenticate header to properly indicate authentication challenge.

### Fixed

- Unnecessary URL decode in `RequestValue.parseString`.
- Default `JsonSerializerOptions` used for JSON deserialization, optimized by making read-only and static to prevent unnecessary allocations.
- `Response.ofAttachment` now properly escapes provided filename to ensure correct handling of special characters and spaces across different browsers.
- Added missing Location header to `Response.signInOptions` and `Response.signOutOptions` when redirect URI is specified.

### Removed

- `Request.getFormSecure` and `Request.mapFormSecure`, which were explicit enablements of the now default CSRF validation for form requests. `Request.getForm` and `Request.mapForm` now include automatic CSRF validation when antiforgery services are registered and request method is POST, PUT, PATCH, or DELETE.

## [5.2.0] - 2025-12-21

### Added

- `net10.0` support.

## [5.1.0] - 2025-09-09

### Added

- `Response.ofFragment` and `Response.ofFragmentCsrf` to return HTML fragments by element ID, with optional CSRF token support.
- `Falco.Markup` [version 1.4.0](https://www.nuget.org/packages/Falco.Markup/1.4.0), which reverted API to 1.2.0 and provided correct support for template fragments.

## [5.0.3] - 2025-09-09

### Added

- `Falco.Markup` [version 1.3.0](https://www.nuget.org/packages/Falco.Markup/1.3.0), which enables support for template fragment responses.

## [5.0.2] - 2025-06-26

### Fixed

- Request module error for JSON transfer encoding chunked requests.

## [5.0.1] - 2025-06-26

### Added

- `Falco.Markup` [version 1.2.0](https://www.nuget.org/packages/Falco.Markup/1.2.0) support, which includes a unified DSL module introduces consistent prefix-based naming conventions for elements, text shortcuts, and attributes, making code cleaner and more readable.

### Fixed

- `Request.mapCookies` and `Request.mapHeaders` re-added, which were accidentally removed in the 5.0.0 release.

## [5.0.0] - 2025-01-28

### Added

- Declarative OpenAPI support.
- `RequestData` (and `RequestValue`) to support complex form & query submissions,
  - Provided by an HTTP key/value pair (i.e., `name=falco&classification=toolkit`) parser.
  - A derivative `FormData` contains parsed `RequestValue` and access to `IFormFileCollection`.
- `HttpContext.Plug<T>` for generic injection support of dependencies within `HttpHandler`'s (service locator pattern).
- `Request.getJson<T>` for generic JSON request deserialization, using default settings (property name case-insensitive, trailing commas allowed).
- `Request.getCookies`, replacing `Request.getCookie`.
- `Response.signInOptions` to sign in claim principal for provided scheme and options then responds with a 301 redirect to provided URL.
- `Response.challengeAndRedirect`, replacing `Response.challengeWithRedirect`.
- `Routing.map[Get|Head|Post|Put|Patch|Delete|Options|Trace|Any]` which produces `HttpEndpoint` by associating a route pattern to an `HttpHandler` after mapping route.
- `Routing.setDisplayName` to set the display name of the endpoint.
- `Routing.setOrder` to set the order number of the endpoint.
- `WebApplication.run`, registers the provided `HttpHandler` as the terminal middleware and runs the application.

### Changed

- `Xss` module renamed to `Xsrf`. Functions: `Xsrf.antiforgeryInput`, `Xsrf.getToken` & `Xsrf.validateToken`.

### Fixed

- Missing cancellation token pass-through during form reading, `multipart/form-data` streaming and JSON serialization/deserialization.
- Empty request body support for JSON request methods.
- `WebApplication.UseFalcoNotFound` & `IApplicationBuilder.UseFalcoNotFound` to correctly terminate by returning `unit` akin to the native method.

### Removed

- `net6.0` support dropped (end of life 2024-11-12).
- `webHost [||] {}` builder removed.
- `config {}` builder removed.
- `HttpContext.GetLogger<T>()` extension removed.
- `IApplicationBuilder.IsDevelopment()`, `IApplicationBuilder.UseWhen()` extensions removed.
- `Services.inject<T>` (and overloads) removed.
- `Response.withContentLength` removed (unsupported).
- `StringCollectionReader` and derivatives removed (`FormCollectionReader`, `QueryCollectionReader`, `RouteCollectionReader`, `HeaderCollectionReader`, and `CookieCollectionReader`).
    - All replaced by homogenous `RequestData` type.
- `Request.streamForm`, `Request.streamFormSecure`, `Request.mapFormStream` and `Request.mapFormStreamSecure` removed.
- `Falco.Security.Crypto` and `Falco.Security.Auth` modules removed.
- Removed `Request.getCookie`, renamed `Request.getCookies`.
- Removed `Response.challengeWithRedirect`, renamed `Response.challengeAndRedirect`.
- Removed `Response.debugRequest`.

## [4.0.6] - 2023-12-12

- `net7.0` and `net8.0` support added.
- Added ability to configure `IWebHostBuilder` to host builder (i.e., `webHost [||] { web_host (fun webHost -> ...) }`).

## [4.0.5] - 2023-11-16

- Execution order of configuration builder (i.e., `configuration { add_env }`) set to match [default](https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration#alternative-hosting-approach) configuration behaviour.

## [4.0.4] - 2023-03-13

### Added

- `Request.getFormSecure` and `Request.streamFormSecure`.
- `use_cors` to host builder (i.e., `webHost [||] { use_cors }`).

### Removed

- Unused types `HttpContextAccessor` and `AsyncHttpContextAccessor`.

## [4.0.3] - 2023-01-01

### Added

- Working tutorial sample.
- Documentation website generator `/site`, and output `/docs`.

### Removed

- Internal utility functions `httpPipe` and `httpPipeTask`. See issue #94, #95.

## [4.0.2] - 2022-11-30

### Fixed

- NuGet package metadata, invalid readme.

### Changed

- Hello world sample to use ASP.NET static file middleware.
- Spelling and grammar of comments. See #96.

### Removed

- Unused internal function `String.parseInt`.

## [4.0.1] - 2022-11-23

### Added

- `Response.debugRequest`, which pretty prints the content of the current request to the screen.
- Related community projects and libraries to README.md.

### Fixed

- NuGet package metadata, invalid icon path.

## [4.0.0] - 2022-11-07

The project no longer intends to support anything prior to net6.0, which enables the built-in `task {}` computation expression.

### Added

- `StringCollectionReader.GetChildren`, safely retrieves a collection of readers. Intended to be used with the "dot notation" collection wire format (i.e., Person.First=John&Person.Last=Doe&Person.First=Jane&Person.Last=Doe).
- `MultipartReader.StreamSectionsAsync` for async streaming of multipart/form-data, following MSFT [spec](https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads).
- `Services.inject` helpers, for CPS-style dependency injection, supporting up to five generic input types.
- `in_memory`, `required_ini`, `optional_ini`, `required_xml`, `optional_xml` custom operations added to the configuration builder.

### Changed

- `StringCollectionReader` abstract attribute removed, to support nested readers.
- `StringCollectionReader.Get{String|StringNonEmpty|Int16|Int32|Int|Int64|Boolean|Float|Decimal|DateTime|DateTimeOffset|Guid|TimeSpan}` default value made optional.
- Upgraded host builder expression from `IWebHostBuilde` to `WebApplication`.

### Removed

- `Falco.Markup`, module has been extracted into it's own [project](https://github.com/FalcoFramework/Falco.Markup).
- Additional `StringCollectionReader` constructors, per-collection type.
- `StringCollectionReader.TryArrayString`, use `StringCollectionReader.GetStringArray`
- `StringCollectionReader.TryArrayInt16`, use `StringCollectionReader.GetInt16Array`
- `StringCollectionReader.TryArrayInt32`, use `StringCollectionReader.GetInt32Array`
- `StringCollectionReader.TryArrayInt`, use `StringCollectionReader.GetIntArray`
- `StringCollectionReader.TryArrayInt64`, use `StringCollectionReader.GetInt64Array`
- `StringCollectionReader.TryArrayBoolean`, use `StringCollectionReader.GetBooleanArray`
- `StringCollectionReader.TryArrayFloat`, use `StringCollectionReader.GetFloatArray`
- `StringCollectionReader.TryArrayDecimal`, use `StringCollectionReader.GetDecimalArray`
- `StringCollectionReader.TryArrayDateTime`, use `StringCollectionReader.GetDateTimeArray`
- `StringCollectionReader.TryArrayDateTimeOffset`, use `StringCollectionReader.GetDateTimeOffsetArray`
- `StringCollectionReader.TryArrayGuid`, use `StringCollectionReader.GetGuidArray`
- `StringCollectionReader.TryArrayTimeSpan`, use `StringCollectionReader.GetTimeSpanArray`
- `HttpRequest.IsMultipart`, `HttpRequest.TryStreamFormAsync`, use `HttpRequest.StreamFormAsync()`
- `Request.tryBindRoute`, use `Request.getRoute`.
- `Request.tryBindQuery`, use `Request.getQuery`.
- `Request.tryBindForm`, use `Request.getForm`.
- `Request.tryBindFormStream`, use `Request.tryStreamForm`.
- `Request.tryBindCookie`, use `Request.getCookie`.
- `Request.getJson`, use `Request.getJsonOptions Constants.defaultJsonOptions`.
- `Request.tryBindJsonOptions`, use `Request.getJsonOptions`.
- `Request.tryBindJson`, use `Request.getJsonOptions Constants.defaultJsonOptions`.
- `Request.bindJson`, use `Request.mapJson`.
- `Request.bindRoute`, use `Request.mapRoute`.
- `Request.bindQuery`, use `Request.mapQuery`.
- `Request.bindCookie`, use `Request.mapCookie`.
- `Request.bindForm`, use `Request.mapForm`.
- `Request.bindFormStream`, use `Request.mapFormStream`.
- `Request.bindFormSecure`, use `Request.mapFormSecure`.
- `Request.bindFormStreamSecure`, use `Request.mapFormStreamSecure`.
- `Response.withHeader`, use `Response.withHeaders [ x ]`.
- `Response.redirect`, use `Response.redirectTemporarily` or `Response.redirectPermanently`

## [3.1.14] - 2022-08-29

### Added

- Embedded readme and project icon into NuGet package.
- Additional obsolete attributes to functions in preparation for v4.x.

### Fixed

- `Request.mapJson` failing to invoke next handler, caused by a bad merge which left the valid function body commented out.

## [3.1.13] - 2022-08-11

### Added

- Obsolete attributes to `Request.bind{Json|Route|Query|Cookie|Form|FormStream|FormSecure|FormStreamSecure} functions in preparation for v4.x.

### Fixed

- Typo in `Markup.Attr.httpEquiv`.

## [3.1.12] - 2022-05-20

### Added

- `Auth.signInOptions` to establish an authenticated context for the provide scheme, options and principal
- `Markup.Attr.open'`.
- Missing .gitignore items for JetBrains.

## [3.1.11] - 2/8/2022

### Added

- `Auth.challenge` to challenge the specified authentication scheme.
- `Response.challengeWithRedirect` to challenge the specified authentication scheme and redirect URI.

### Fixed

- Website to address certain accessibility issues.

## [3.1.10] - 12/14/2021

### Changed

- Incorporated built-in `System.Task` expression, with compiler directives to continue supporting Ply usage.

## [3.1.9] - 12/6/2021

### Changed

- `StringCollectionReader` lookups made case-insensitive.

## [3.1.8] - 12/3/2021

### Added

- `net6.0` support.

### Changed

- Embedded PDBs to faciliate sourcelink.

## [3.1.7] - 9/24/2021

### Added

- `HttpVerb.toHttpMethodMetadata` to properly capture the `HttpVerb.ANY` to produce an empty `HttpMethodData` (not `HttpMethodData [| "ANY" |]`).

## [3.1.6] - 9/24/2021

### Removed

- Mistakenly added, experimental `Request.signOut` function.

## [3.1.5] - 9/24/2021

### Added

- Route name metadata to support ASP.NET link generator.
- Null check to internal `Response.writeString`.
- Explicit starting size for the internal `StringBuilder` within `XmlNodeSerializer`

## [3.1.4] - 8/24/2021

### Added

- Comparative view engine benchmarks.
- `XmlNodeSerializer` type.
- Source link support.

## [3.1.3] - 8/4/2021

### Added

- Dependency on [Ply](https://github.com/crowded/ply).
- `Request.authenticate` to authenticate the current request using the provided scheme.

### Removed

- TPL helpers.

## [3.1.2] - 7/30/2021

### Changed

- CSRF validation switched to occur _after_ form is streamed, which includes enabling buffering for the request body.


## [3.1.1] - 7/27/2021

### Added

- `stringf` function.

### Removed

- Dependency on [Taskbuilder.fs](https://github.com/rspeele/Taskbuilder.fs), replaced with TPL helpers.

## [3.1.0] - 7/27/2021

### Added

- `FalcoEndpointDataSource` to properly integrate with ASP.NET endpoint routing.
- Binary response handlers `Response.ofBinary`, `Response.ofAttachment`.
- `IConfiguration` builder expression with JSON input hooks.
- `Auth.getClaimValue`
- `IServiceCollection` operations to the HostBuilder expression: `add_service`, `add_antiforgery`, `add_cookie`, `add_conf_cookies`, `add_authorization`, `add_data_protection`, `add_http_client`.
- `IApplicationBuilder` operations to the HostBuilder expression:
`use_middleware`, `use_if`, `use_ifnot`, `use_authentication`, `use_authorization`, `use_caching`, `use_compression`, `use_hsts`, `use_https`, `use_static_files`.
- `not_found` operation added to HostBuilder expression to serve default document when no endpoints are matched.

### Changed

- Internal `Response.writeBytes` to use `BodyWriter`.

### Fixed

- Optional JSON config file fix, misassigned.

### Removed

- MVC and REST templates

## [3.0.5] - 6/14/2021

### Added

- PowerShell website build script.

### Fixed

- Null reference exception when consuming `IFormCollection.Files`.

## [3.0.4] - 5/5/2021

### Added

- `Response.signInAndRedirect`.
- `IEndpointRouteBuilder` extension method `UserFalcoEndpoints`.


## [3.0.3] - 4/10/2021

### Added

- `Auth.hasScope`, `Auth.tryFindClaim`, `Auth.getClaim`.
- `Request.ifAuthenticatedWithScope`.
- `CookieCollectionReader`, accessible get `Request.getCookie`, `Request.tryBindCookie`, `Request.bindCookie`, `Request.mapCookie`.
- `StringUtils.strSplit`.

## [3.0.2] - 12/8/2020

### Added

- `Markup.Elem.form`, `Markup.Elem.button`, `Markup.Elem.script`

## [3.0.1] - 12/1/2020

### Fixed

- `Markup.Templates.html5` not using provided language code.

## [3.0.0] - 11/27/2020

### Added

- `net5.0` support.
- `IHost` builder expression, `webHost [||] {}`.
- `IServiceCollection.AddFalco`.
- `IServiceCollection.AddFalco (routeOptions : RouteOptions -> unit)`.
- `IApplicationBuilder.UseFalco (endpoints : HttpEndpoint list)`.
- `IApplicationBuilder.UseFalcoExceptionHandler (exceptionHandler : HttpHandler)`.
- `QueryCollectionReader`.
- `HeaderCollectionReader`.
- `RouteCollectionReader`.

### Removed

- Extensions, `HttpRequest.GetHeader`, `HttpRequest.GetRouteValues`, `HttpRequest.GetRouteReader`.
- Exceptions. `ExceptionHandler`, `ExceptionHandlingMiddleware`.
- Host module, `Host.defaultExceptionHandler`, `Host.defaultNotFoundHandler`, `Host.startWebHostDefault`, `Host.startWebHost`.
- `IApplicationBuilder.UseHttpEndpoints (endpoints : HttpEndpoint list)` replaced by `IApplicationBuilder.UseFalco (endpoints : HttpEndpoint list)`.
- `Request.getHeader`, `Request.getRouteValues` replaced by `Request.getRoute`, `Request.tryGetRouteValue`.
- `StringCollectionReader` ? dynamic operator

## [2.1.0] - 11/11/2020

### Added

- Multimethod `HttpEndpoint` support.
- `StringCollectionReader.TryGetStringNonEmpty` which returns `None` for empty, whitespace and null value strings.

## [2.0.4] - 11/9/2020

### Added

- `Request.tryBindRoute`, `Request.mapRoute` and `Request.bindRoute`.
- `Request.bindQuery`.
- `Request.bindJson` which uses `System.Text.Json`.

## [2.0.3] - 10/31/2020

### Added

- Dependency on [Taskbuilder.fs](https://github.com/rspeele/Taskbuilder.fs), with internal extesion for `Task<unit> -> Task` conversion.

## [2.0.2] - 7/31/2020

### Added

- `Request.validateCsrfToken` which uses `Microsoft.AspNetCore.Antiforgery`.
- `Response.ofJson` which uses `System.Text.Json` and references `Constants.defaultJsonOptions`.
- `Response.ofEmpty`.

## [2.0.1] - 7/20/2020

### Changed

- Parameter ordering for `Response.withCookieOptions`, `Response.ofJsonOptions` to ensure configuration uniformly occured first.

## [2.0.0] - 7/12/2020

### Added

- `HttpResponseModifier` defined as `HttpContext -> HttpContext` used to make non-IO modifications to the `HttpResponse`.
- `Response` and `Request` modules, which provide functional access to the `HttpResponse` and `HttpRequest` respectively.

    - `Response.redirect`
    - `Response.withHeader`
    - `Response.withContentLength`
    - `Response.withContentType`
    - `Response.withStatusCode`
    - `Response.withCookie`
    - `Response.withCookieOptions`
    - `Response.ofString`
    - `Response.ofPlainText`
    - `Response.ofHtml`
    - `Response.ofJson`
    - `Response.ofJsonOptions    `
    - `Request.getVerb`
    - `Request.getRouteValues`
    - `Request.tryGetRouteValue`
    - `Request.getQuery`
    - `Request.tryBindQuery`
    - `Request.getForm`
    - `Request.tryBindForm`
    - `Request.tryStreamForm`
    - `Request.tryBindJson`
    - `Request.tryBindJsonOptions`

### Changed

- `HttpHandler` definition changed to `HttpContext -> Task`.
- `Falco.ViewEngine` becomes `Falco.Markup`
- Markup functions are now fully qualified (i.e., `Elem.h1` instead of `h1`).
- `webApp

## [1.2.3] - 7/2/2020
## [1.2.2] - 6/29/2020
## [1.2.1] - 6/28/2020
## [1.2.0] - 6/23/2020
## [1.1.0] - 6/6/2020

Still kicking myself over this brainfart. Starting version `1.1` for the win 🙄.


================================================
FILE: CNAME
================================================
www.falcoframework.com

================================================
FILE: Falco.sln
================================================

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Falco", "src\Falco\Falco.fsproj", "{D6613F0B-7571-432E-964B-B9629B3B06CB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0C88DD14-F956-CE84-757C-A364CCF449FC}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Falco.Tests", "test\Falco.Tests\Falco.Tests.fsproj", "{9600E734-196E-4922-929E-8B5906A1FBAA}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Falco.IntegrationTests.App", "test\Falco.IntegrationTests.App\Falco.IntegrationTests.App.fsproj", "{7A9A92D3-EADC-40D0-8E90-82AE651195F1}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Falco.IntegrationTests", "test\Falco.IntegrationTests\Falco.IntegrationTests.fsproj", "{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Debug|x64 = Debug|x64
		Debug|x86 = Debug|x86
		Release|Any CPU = Release|Any CPU
		Release|x64 = Release|x64
		Release|x86 = Release|x86
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Debug|x64.ActiveCfg = Debug|Any CPU
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Debug|x64.Build.0 = Debug|Any CPU
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Debug|x86.ActiveCfg = Debug|Any CPU
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Debug|x86.Build.0 = Debug|Any CPU
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Release|Any CPU.Build.0 = Release|Any CPU
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Release|x64.ActiveCfg = Release|Any CPU
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Release|x64.Build.0 = Release|Any CPU
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Release|x86.ActiveCfg = Release|Any CPU
		{D6613F0B-7571-432E-964B-B9629B3B06CB}.Release|x86.Build.0 = Release|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Debug|x64.ActiveCfg = Debug|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Debug|x64.Build.0 = Debug|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Debug|x86.ActiveCfg = Debug|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Debug|x86.Build.0 = Debug|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Release|Any CPU.Build.0 = Release|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Release|x64.ActiveCfg = Release|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Release|x64.Build.0 = Release|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Release|x86.ActiveCfg = Release|Any CPU
		{9600E734-196E-4922-929E-8B5906A1FBAA}.Release|x86.Build.0 = Release|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Debug|x64.ActiveCfg = Debug|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Debug|x64.Build.0 = Debug|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Debug|x86.ActiveCfg = Debug|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Debug|x86.Build.0 = Debug|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Release|Any CPU.Build.0 = Release|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Release|x64.ActiveCfg = Release|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Release|x64.Build.0 = Release|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Release|x86.ActiveCfg = Release|Any CPU
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1}.Release|x86.Build.0 = Release|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Debug|x64.ActiveCfg = Debug|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Debug|x64.Build.0 = Debug|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Debug|x86.ActiveCfg = Debug|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Debug|x86.Build.0 = Debug|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Release|Any CPU.Build.0 = Release|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Release|x64.ActiveCfg = Release|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Release|x64.Build.0 = Release|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Release|x86.ActiveCfg = Release|Any CPU
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA}.Release|x86.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(NestedProjects) = preSolution
		{D6613F0B-7571-432E-964B-B9629B3B06CB} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
		{9600E734-196E-4922-929E-8B5906A1FBAA} = {0C88DD14-F956-CE84-757C-A364CCF449FC}
		{7A9A92D3-EADC-40D0-8E90-82AE651195F1} = {0C88DD14-F956-CE84-757C-A364CCF449FC}
		{5985B9A8-267A-46FF-8E5C-3E016B36E3EA} = {0C88DD14-F956-CE84-757C-A364CCF449FC}
	EndGlobalSection
EndGlobal


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# Falco

[![NuGet Version](https://img.shields.io/nuget/v/Falco.svg)](https://www.nuget.org/packages/Falco)
[![build](https://github.com/FalcoFramework/Falco/actions/workflows/build.yml/badge.svg)](https://github.com/FalcoFramework/Falco/actions/workflows/build.yml)

```fsharp
open Falco
open Microsoft.AspNetCore.Builder

let wapp = WebApplication.Create()

wapp.Run(Response.ofPlainText "Hello world")
```

[Falco](https://github.com/FalcoFramework/Falco) is a toolkit for building functional-first, full-stack web applications using F#.

- Built on the high-performance components of ASP.NET Core.
- Seamlessly integrates with existing .NET Core middleware and libraries.
- Designed to be simple, lightweight and easy to learn.

## Key Features

- Simple and powerful [routing](documentation/routing.md) API.
- Uniform API for [accessing _any_ request data](documentation/request.md).
- Native F# [view engine](documentation/markup.md).
- Asynchronous [request handling](documentation/response.md).
- [Authentication](documentation/authentication.md) and [security](documentation/cross-site-request-forgery.md) utilities.
- Built-in support for [large uploads](documentation/request.md#multipartform-data-binding) and [binary responses](documentation/response.md#content-disposition).


## Design Goals

- Provide a toolset to build full-stack web application in F#.
- Should be simple, extensible and integrate with existing .NET libraries.
- Can be easily learned.

## Learn

The best way to get started is by visiting the [documentation](https://falcoframework.com/docs). For questions and support please use [discussions](https://github.com/FalcoFramework/Falco/discussions). For chronological updates refer to the [changelog](CHANGELOG.md) is the best place to find chronological updates.

### Related Libraries

- [Falco.Markup](https://github.com/FalcoFramework/Falco.Markup) - an XML markup module primary used as the syntax for [authoring HTML with Falco](https://www.falcoframework.com/docs/markup.html).
- [Falco.Htmx](https://github.com/dpraimeyuu/Falco.Htmx) - a full featured integration with [htmx JS package](https://htmx.org/).
- [Falco.OpenApi](https://github.com/FalcoFramework/Falco.OpenApi) - a library for generating OpenAPI documentation from Falco applications.
- [Falco.Template](https://github.com/FalcoFramework/Falco.Template) - a .NET SDK [project template](https://learn.microsoft.com/en-us/dotnet/core/tools/custom-templates) to help get started with Falco quickly.
- [Falco.UnionRoutes](https://github.com/michaelglass/Falco.UnionRoutes/) - a library for expressing routes as a descriminated union, inspired by Haskell's [Servant](https://docs.servant.dev/).
- [CloudSeed](https://cloudseed.xyz/) - a simple, scalable project boilerplate for F# / .NET.

### Community Projects

- [Falco GraphQL Sample](https://github.com/adelarsq/falco_graphql_sample) - A sample showing how to use GraphQL on Falco using .NET 6.
- [Falco API with Tests Sample](https://github.com/jasiozet/falco-api-with-tests-template) - A sample project using Falco and unit testing.
- [Falco + SQLite + Donald](https://github.com/galassie/FalcoSample) - A demo project using Falco, [Donald](https://github.com/pimbrouwers/Donald), and SQLite
- [FShopOnWeb](https://github.com/NitroDevs/FShopOnWeb) - An adaptation of the classic [ASP.NET Core sample application](https://github.com/dotnet-architecture/eShopOnWeb) using Falco and an F# architecture.

### Articles

- Hamilton Greene - [Spin up a Fullstack F# WebApp in 10 minutes with the CloudSeed Project Template](https://hamy.xyz/blog/2025-01_fsharp-webapp-10-minutes)
- Hamilton Greene - [Why I'm Ditching F# + Giraffe For Falco For Building WebApps](https://hamy.xyz/blog/2025-01_ditching-giraffe-for-falco)
- Istvan - [Running ASP.Net web application with Falco on AWS Lambda](https://dev.l1x.be/posts/2020/12/18/running-asp.net-web-application-with-falco-on-aws-lambda/)

### Videos

- Hamilton Greene - [Build a Fullstack Webapp with F# + Falco](https://www.youtube.com/watch?v=ELPdHdtEIY8)
- Hamilton Greene - [Build a Single-File Web API with F# + Falco](https://www.youtube.com/watch?v=SJCHBqrc3sE)
- Hamilton Greene - [Why I'm Ditching F# + Giraffe For Falco For Building WebApps](https://www.youtube.com/watch?v=tonPeWfu_WM)
- Ben Gobeil - [Why I'm Using Falco Instead Of Saturn | How To Switch Your Backend In SAFE Stack | StonkWatch Ep.13](https://youtu.be/DTy5gIUWvpo)


## Contribute

We kindly ask that before submitting a pull request, you first submit an [issue](https://github.com/FalcoFramework/Falco/issues) or open a [discussion](https://github.com/FalcoFramework/Falco/discussions).

If functionality is added to the API, or changed, please kindly update the relevant [document](/docs). Unit tests must also be added and/or updated before a pull request can be successfully merged.

Only pull requests which pass all build checks and comply with the general coding standard can be approved.

If you have any further questions, submit an [issue](https://github.com/FalcoFramework/Falco/issues) or open a [discussion](https://github.com/FalcoFramework/Falco/discussions) or reach out on [Twitter](https://twitter.com/falco_framework).


## Why "Falco"?

[Kestrel](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel) has been a game changer for the .NET web stack. In the animal kingdom, "Kestrel" is a name given to several members of the falcon genus. Also known as "Falco".


## Find a bug?

There's an [issue](https://github.com/FalcoFramework/Falco/issues) for that.


## License

Licensed under [Apache License 2.0](https://github.com/FalcoFramework/Falco/blob/master/LICENSE).


================================================
FILE: docs/CNAME
================================================
www.falcoframework.com

================================================
FILE: docs/docs/authentication.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Authentication & Authorization. - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="authentication-authorization">Authentication &amp; Authorization.</h1>
<p>ASP.NET Core has built-in support for authentication and authorization. Falco includes some prebuilt, configurable handlers for common scenarios.</p>
<blockquote>
<p>Review the <a href="https://docs.microsoft.com/en-us/aspnet/core/security/authentication">docs</a> for specific implementation details.</p>
</blockquote>
<h2 id="secure-resources">Secure Resources</h2>
<h3 id="allow-only-authenticated-access">Allow only authenticated access</h3>
<pre><code class="language-fsharp">open Falco

let authScheme = &quot;some.secure.scheme&quot;

let secureResourceHandler : HttpHandler =
    let handleAuth : HttpHandler =
        Response.ofPlainText &quot;hello authenticated user&quot;

    Request.ifAuthenticated authScheme handleAuth
</code></pre>
<h3 id="allow-only-non-authenticated-access">Allow only non-authenticated access</h3>
<pre><code class="language-fsharp">open Falco

let anonResourceOnlyHandler : HttpHandler =
    let handleAnon : HttpHandler =
        Response.ofPlainText &quot;hello anonymous&quot;

    Request.ifNotAuthenticated authScheme handleAnon
</code></pre>
<h3 id="allow-only-authenticated-access-when-in-certain-roles">Allow only authenticated access when in certain role(s)</h3>
<pre><code class="language-fsharp">open Falco

let secureResourceHandler : HttpHandler =
    let handleAuthInRole : HttpHandler =
        Response.ofPlainText &quot;hello admin&quot;

    let rolesAllowed = [ &quot;Admin&quot; ]

    Request.ifAuthenticatedInRole authScheme rolesAllowed handleAuthInRole
</code></pre>
<h3 id="allow-only-authenticated-acces-with-a-certain-scope">Allow only authenticated acces with a certain scope</h3>
<pre><code class="language-fsharp">open Falco

let secureResourceHandler : HttpHandler =
    let handleAuthHasScope : HttpHandler =
        Response.ofPlainText &quot;user1, user2, user3&quot;

    let issuer = &quot;https://oauth2issuer.com&quot;
    let scope = &quot;read:users&quot;

    Request.ifAuthenticatedWithScope authScheme issuer scope handleAuthHasScope
</code></pre>
<h3 id="terminate-authenticated-session">Terminate authenticated session</h3>
<pre><code class="language-fsharp">open Falco

let logOut : HttpHandler =
    let authScheme = &quot;...&quot;
    let redirectTo = &quot;/login&quot;

    Response.signOutAndRedirect authScheme redirectTo
</code></pre>
<p><a href="host-configuration.html">Next: Host Configuration</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/cross-site-request-forgery.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Cross-site Scripting (XSS) Attacks - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="cross-site-scripting-xss-attacks">Cross-site Scripting (XSS) Attacks</h1>
<p>Cross-site scripting attacks are extremely common since they are quite simple to carry out. Fortunately, protecting against them is as easy as performing them.</p>
<p>The <a href="https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery">Microsoft.AspNetCore.Antiforgery</a> package provides the required utilities to easily protect yourself against such attacks.</p>
<h2 id="activating-antiforgery-protection">Activating Antiforgery Protection</h2>
<p>To use the Falco Xsrf helpers, ensure that the <code>Antiforgery</code> service has been <a href="https://learn.microsoft.com/en-us/aspnet/core/security/anti-request-forgery">registered</a>.</p>
<pre><code class="language-fsharp">open Falco
open Falco.Routing
open Microsoft.AspNetCore.Builder
open Microsoft.Extensions.DependencyInjection
// ^-- this import enables antiforgery activation

let endpoints =
    [
        // endpoints...
    ]

let bldr = WebApplication.CreateBuilder()

bldr.Services
    .AddAntiforgery()

let wapp = WebApplication.Create()

wapp.UseAntiforgery()
    // ^-- activate Antiforgery before routing
    .UseRouting()
    .UseFalco(endpoints)
    .Run()

</code></pre>
<h2 id="falco-xsrf-support">Falco XSRF Support</h2>
<p>Falco provides a few handlers via <code>Falco.Security.Xsrf</code>:</p>
<pre><code class="language-fsharp">open Falco.Markup
open Falco.Security

let formView token =
    _html [] [
        _body [] [
            _form [ _methodPost_ ] [
                // using the CSRF HTML helper, recommended to include as first
                // form element
                Xsrf.antiforgeryInput token
                _control &quot;first_name&quot; [] [ _text &quot;First Name&quot; ]
                _control &quot;first_name&quot; [] [ _text &quot;First Name&quot; ]
                _input [ _typeSubmit_ ]
            ]
        ]
    ]

// A handler that demonstrates obtaining a
// CSRF token and applying it to a view
let csrfViewHandler : HttpHandler =
    Response.ofHtmlCsrf formView

// A handler that demonstrates validating
// the request's CSRF token
let mapFormSecureHandler : HttpHandler =
    let mapPerson (form : FormData) =
        { FirstName = form?first_name.AsString()
          LastName = form?last_name.AsString }

    let handleInvalid : HttpHandler =
        Response.withStatusCode 400
        &gt;&gt; Response.ofEmpty

    Request.mapFormSecure mapPerson Response.ofJson handleInvalid
</code></pre>
<p><a href="authentication.html">Next: Authentication</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/deployment.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Deployment - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="deployment">Deployment</h1>
<p>One of the key features of Falco is that it contains little to no &quot;magic&quot; (i.e., no hidden reflection or dynamic code). This means that Falco is both <a href="https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-self-contained">trimmable</a> and <a href="https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot">AOT</a> compatible out of the box.</p>
<p>This means that you can deploy your Falco application as a self-contained executable, or as a native AOT executable, with no additional configuration. A huge benefit of this is that you can deploy your Falco application to any environment, without having to worry about the underlying runtime or dependencies.</p>
<blockquote>
<p>Important! If you're in a <strong>scale-to-zero</strong> hosting environment consider using a <a href="https://learn.microsoft.com/en-us/dotnet/core/deploying/ready-to-run">ReadyToRun</a> deployment. This will ensure that your application will experience faster cold start times.</p>
</blockquote>
<h2 id="self-contained-deployments">Self-contained deployments</h2>
<p>It is highly recommended to deploy your Falco application as a self-contained executable. This means that the .NET runtime and all dependencies are included in the deployment package, so you don't have to worry about the target environment having the correct version of .NET installed. This will result in a slightly larger deployment package, but it will ensure that your application runs correctly in any environment. The larger binary size can also be offset by using trim.</p>
<p>Below is an example [Directory.Build.props] that will help enable the non-AOT features. These properties can also be added to you fsproj file.</p>
<pre><code class="language-xml">&lt;Project&gt;
    &lt;PropertyGroup&gt;
        &lt;SelfContained&gt;true&lt;/SelfContained&gt;
        &lt;PublishSingleFile&gt;true&lt;/PublishSingleFile&gt;
        &lt;PublishTrimmed&gt;true&lt;/PublishTrimmed&gt;
        &lt;TrimMode&gt;Link&lt;/TrimMode&gt;
        &lt;IncludeNativeLibrariesForSelfExtract&gt;true&lt;/IncludeNativeLibrariesForSelfExtract&gt;
        &lt;EnableCompressionInSingleFile&gt;true&lt;/EnableCompressionInSingleFile&gt;
        &lt;!-- Optional: enable if in scale-to-zero hosting environment --&gt;
        &lt;!-- &lt;PublishReadyToRun&gt;true&lt;/PublishReadyToRun&gt; --&gt;
    &lt;/PropertyGroup&gt;
&lt;/Project&gt;
</code></pre>
<h2 id="native-aot-deployments">Native AOT deployments</h2>
<p>Publishing your app as Native AOT produces an app that's self-contained and that has been ahead-of-time (AOT) compiled to native code. Native AOT apps have faster startup time and smaller memory footprints. These apps can run on machines that don't have the .NET runtime installed.</p>
<p>Since AOT deployments require trimming, and are single file by nature the only required msbuild property is:</p>
<pre><code class="language-xml">&lt;Project&gt;
    &lt;PropertyGroup&gt;
        &lt;PublishAot&gt;true&lt;/PublishAot&gt;
    &lt;/PropertyGroup&gt;
&lt;/Project&gt;
</code></pre>
<p><a href="example-hello-world.html">Next: Example - Hello World</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/example-basic-rest-api.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Example - Basic REST API - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="example-basic-rest-api">Example - Basic REST API</h1>
<p>This example demonstrates how to create a basic REST API using Falco. The API will allow users to perform CRUD (Create, Read, Update, Delete) operations on a simple resource, users in this case.</p>
<p>The API will be built using the following components, in addition to the Falco framework:</p>
<ul>
<li><a href="https://www.nuget.org/packages/System.Data.SQLite/">System.Data.SQLite</a>, which provides SQLite support, built and maintained by the SQLite developers.</li>
<li><a href="https://www.nuget.org/packages/Donald/">Donald</a> which simplifies database access, built and maintained by the Falco developers.</li>
</ul>
<blockquote>
<p>For simplicity, we'll stick to sychronous database access in this example. However, you can easily adapt the code to use asynchronous database access if needed. Specific to SQLite, in many cases it is better to use synchronous access, and let SQLite handle serialization for you.</p>
</blockquote>
<p>The code for this example can be found <a href="https://github.com/FalcoFramework/Falco/tree/master/examples/BasicRestApi">here</a>.</p>
<h2 id="creating-the-application-manually">Creating the Application Manually</h2>
<pre><code class="language-shell">&gt; dotnet new falco -o BasicRestApiApp
&gt; cd BasicRestApiApp
&gt; dotnet add package System.Data.SQLite
&gt; dotnet add package Donald
</code></pre>
<h2 id="overview">Overview</h2>
<p>The API will consist of four endpoints:</p>
<ul>
<li><code>GET /users</code>: Retrieve all users.</li>
<li><code>GET /users/{username}</code>: Retrieve a user by username.</li>
<li><code>POST /users</code>: Create a new user.</li>
<li><code>DELETE /users/{username}</code>: Delete a user by username.</li>
</ul>
<p>Users will be stored in a SQLite database, and the API will use Donald to interact with the database. Our user model will be a simple record type with two properties: <code>Username</code> and <code>Full Name</code>.</p>
<pre><code class="language-fsharp">type User =
    { Username : string
      FullName : string }
</code></pre>
<p>It's also valueable to have a concrete type to represent API errors. This will be used to return error messages in a consistent format.</p>
<pre><code class="language-fsharp">type Error =
    { Code : string
      Message : string }
</code></pre>
<h2 id="data-access">Data Access</h2>
<p>To interact with the SQLite database, we'll create some abstractions for establishing new connections and performing database operations.</p>
<p>A connection factory is a useful concept to avoid passing around connection strings. It allows us to create new connections without needing to know the details of how they are created.</p>
<pre><code class="language-fsharp">type IDbConnectionFactory =
    abstract member Create : unit -&gt; IDbConnection
</code></pre>
<p>We'll also define an interface for performing list, create, read and delete operations against a set of entities.</p>
<pre><code class="language-fsharp">type IStore&lt;'TKey, 'TItem&gt; =
    abstract member List : unit   -&gt; 'TItem list
    abstract member Create : 'TItem -&gt; Result&lt;unit, Error&gt;
    abstract member Read : 'TKey -&gt; 'TItem option
    abstract member Delete : 'TKey -&gt; Result&lt;unit, Error&gt;
</code></pre>
<p>The <code>IStore</code> interface is generic, allowing us to use it with any type of entity. In our case, we'll create a concrete implementation for the <code>User</code> entity.</p>
<h2 id="implementing-the-store">Implementing the Store</h2>
<h2 id="error-responses">Error Responses</h2>
<p>The API will return error responses in a consistent format. To do this, we'll create three functions for the common error cases: <code>notFound</code>, <code>badRequest</code>, and <code>serverException</code>.</p>
<pre><code class="language-fsharp">module ErrorResponse =
    let badRequest error : HttpHandler =
        Response.withStatusCode 400
        &gt;&gt; Response.ofJson error

    let notFound : HttpHandler =
        Response.withStatusCode 404 &gt;&gt;
        Response.ofJson { Code = &quot;404&quot;; Message = &quot;Not Found&quot; }

    let serverException : HttpHandler =
        Response.withStatusCode 500 &gt;&gt;
        Response.ofJson { Code = &quot;500&quot;; Message = &quot;Server Error&quot; }
</code></pre>
<p>Here you can see our error type in action, which is used to return a JSON response with the error code and message. The signature of the <code>badRequest</code> function is a bit different, as it takes an error object as input and returns a <code>HttpHandler</code>. The reason for this is that we intend to invoke this function from within our handlers, and we want to be able to pass the error object directly to it.</p>
<h2 id="defining-the-endpoints">Defining the Endpoints</h2>
<p>It can be very useful to define values for the endpoints we want to expose. This allows us to easily change the endpoint paths in one place if needed, and also provides intellisense support when using the endpoints in our code.</p>
<pre><code class="language-fsharp">module Route =
    let userIndex = &quot;/users&quot;
    let userAdd = &quot;/users&quot;
    let userView = &quot;/users/{username}&quot;
    let userRemove = &quot;/users/{username}&quot;
</code></pre>
<p>Next, let's implement the handlers for each of the endpoints. First, we'll implement the <code>GET /users</code> endpoint, which retrieves all users from the database.</p>
<pre><code class="language-fsharp">module UserEndpoint =
    let index : HttpHandler = fun ctx -&gt;
        let userStore = ctx.Plug&lt;IStore&lt;string, User&gt;&gt;()
        let allUsers = userStore.List()
        Response.ofJson allUsers ctx
</code></pre>
<p>The <code>index</code> function retrieves the <code>IStore</code> instance from the dependency container and calls the <code>List</code> method to get all users. The result is then returned as a JSON response.</p>
<p>Next, we'll implement the <code>POST /users</code> endpoint, which creates a new user.</p>
<pre><code class="language-fsharp">module UserEndpoint =
    // ... index handler ...
    let add : HttpHandler = fun ctx -&gt; task {
        let userStore = ctx.Plug&lt;IStore&lt;string, User&gt;&gt;()
        let! userJson = Request.getJson&lt;User&gt; ctx
        let userAddResponse =
            match userStore.Create(userJson) with
            | Ok result -&gt; Response.ofJson result ctx
            | Error error -&gt; ErrorResponse.badRequest error ctx
        return! userAddResponse }
</code></pre>
<p>The <code>add</code> function retrieves the <code>IStore</code> instance from the dependency container and calls the <code>Create</code> method to add a new user. The result is then returned as a JSON response. If the user creation fails, we return a bad request error.</p>
<p>Next, we'll implement the <code>GET /users/{username}</code> endpoint, which retrieves a user by username.</p>
<pre><code class="language-fsharp">module UserEndpoint =
    // ... index and add handlers ...
    let view : HttpHandler = fun ctx -&gt;
        let userStore = ctx.Plug&lt;IStore&lt;string, User&gt;&gt;()
        let route = Request.getRoute ctx
        let username = route?username.AsString()
        match userStore.Read(username) with
        | Some user -&gt; Response.ofJson user ctx
        | None -&gt; ErrorResponse.notFound ctx
</code></pre>
<p>The <code>view</code> function retrieves the <code>IStore</code> instance from the dependency container and calls the <code>Read</code> method to get a user by username. If the user is found, it is returned as a JSON response. If not, we return a not found error.</p>
<p>Finally, we'll implement the <code>DELETE /users/{username}</code> endpoint, which deletes a user by username.</p>
<pre><code class="language-fsharp">module UserEndpoint =
    // ... index, add and view handlers ...
    let remove : HttpHandler = fun ctx -&gt;
        let userStore = ctx.Plug&lt;IStore&lt;string, User&gt;&gt;()
        let route = Request.getRoute ctx
        let username = route?username.AsString()
        match userStore.Delete(username) with
        | Ok result -&gt; Response.ofJson result ctx
        | Error error -&gt; ErrorResponse.badRequest error ctx
</code></pre>
<p>The <code>remove</code> function retrieves the <code>IStore</code> instance from the dependency container and calls the <code>Delete</code> method to remove a user by username. The result is then returned as a JSON response. If the user deletion fails, we return a bad request error.</p>
<h2 id="configuring-the-application">Configuring the Application</h2>
<p>Conventionally, you'll configure your database outside of your application scope. For the purpose of this example, we'll define and initialize the database during startup.</p>
<pre><code class="language-fsharp">module Program =
    [&lt;EntryPoint&gt;]
    let main args =
        let dbConnectionFactory =
            { new IDbConnectionFactory with
                member _.Create() = new SQLiteConnection(&quot;Data Source=BasicRestApi.sqlite3&quot;) }

        let initializeDatabase (dbConnection : IDbConnectionFactory) =
            use conn = dbConnection.Create()
            conn
            |&gt; Db.newCommand &quot;CREATE TABLE IF NOT EXISTS user (username, full_name)&quot;
            |&gt; Db.exec

        initializeDatabase dbConnectionFactory

        // ... rest of the application setup
</code></pre>
<p>First we implement the <code>IDbConnectionFactory</code> interface, which creates a new SQLite connection. Then we define a <code>initializeDatabase</code> function, which creates the database and the user table if it doesn't exist. We encapsulate the database initialization in a function, so we can quickly dispose of the connection after use.</p>
<p>Next, we need to register our database connection factory and the <code>IStore</code> implementation in the dependency container.</p>
<pre><code class="language-fsharp">module Program =
    [&lt;EntryPoint&gt;]
    let main args =
        // ... database initialization ...
        let bldr = WebApplication.CreateBuilder(args)

        bldr.Services
            .AddAntiforgery()
            .AddScoped&lt;IDbConnectionFactory&gt;(dbConnectionFactory)
            .AddScoped&lt;IStore&lt;string, User&gt;, UserStore&gt;()
            |&gt; ignore
</code></pre>
<p>Finally, we need to configure the application to use the defined endpoints.</p>
<pre><code class="language-fsharp">module Program =
    [&lt;EntryPoint&gt;]
    let main args =
        // ... database initialization &amp; dependency registration ...
        let wapp = bldr.Build()

        let isDevelopment = wapp.Environment.EnvironmentName = &quot;Development&quot;

        wapp.UseIf(isDevelopment, DeveloperExceptionPageExtensions.UseDeveloperExceptionPage)
            .UseIf(not(isDevelopment), FalcoExtensions.UseFalcoExceptionHandler ErrorResponse.serverException)
            .UseRouting()
            .UseFalco(App.endpoints)
            .Run(ErrorResponse.notFound)

        0 // Exit code
</code></pre>
<p>The <code>UseFalco</code> method is used to register the endpoints, and the <code>Run</code> method is used to handle requests that don't match any of the defined endpoints.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>And there you have it! A simple REST API built with Falco, SQLite and Donald. This example demonstrates how to create a basic CRUD API, but you can easily extend it to include more complex functionality, such as authentication, validation, and more.</p>
<p><a href="example-open-api.html">Next: Example - Open API</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/example-dependency-injection.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Example - Dependency Injection - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="example-dependency-injection">Example - Dependency Injection</h1>
<p>An important and nuanced subject to discuss is dependency injection. There's a myriad of beliefs and approaches, all of which have their merit. In the case of Falco, you are living in the world of ASP.NET which has <a href="https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection">built-in support</a> for this. It works very well and you should use it. But make sure you follow through their <a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-8.0">docs</a> on how it works and integrates with ASP.NET.</p>
<p>Going back to our basic <a href="example-hello-world.html">Hello World</a> app, let's add in an external dependency to demonstrate some of the basics of dependency injection in Falco.</p>
<p>The code for this example can be found <a href="https://github.com/FalcoFramework/Falco/tree/master/examples/DependencyInjection">here</a>.</p>
<h2 id="creating-the-application-manually">Creating the Application Manually</h2>
<pre><code class="language-shell">&gt; dotnet new falco -o DependencyInjectionApp
</code></pre>
<h2 id="creating-abstraction">Creating Abstraction</h2>
<p>The benefit of abstracting functionality is that it removes the coupling between your implementation and the calling code. You instead rely on an accepted definition of what something does.</p>
<p>F# has excellent support for <a href="https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/classes">object programming</a>. There might be an urge to avoid this type of approach because &quot;ugh classes are gross&quot;. But suck it up buttercup, they are wickedly useful in many cases and a reminder that F# code doesn't have to adhere to some functional purism.</p>
<p>In the case of our application, we're going to define an abstraction for greeting patrons. Then write a simple implementation.</p>
<blockquote>
<p>This is a completely contrived example, created purely to demonstrate how to register and consume dependencies.</p>
</blockquote>
<pre><code class="language-fsharp">type IGreeter =
    abstract member Greet : name : string -&gt; string

type FriendlyGreeter() =
    interface IGreeter with
        member _.Greet(name : string) =
            $&quot;Hello {name} 😀&quot;
</code></pre>
<p>Simple enough, we describe an <code>IGreeter</code> as having the ability to <code>Greet</code> in the form of receiving a name string and return a string message. Next we define an implementation that fulfills this interface in a friendly way.</p>
<h2 id="registering-the-dependency">Registering the Dependency</h2>
<p>To provide runtime access to our greeter, we have to register the dependency in the container. The abstraction from ASP.NET for this is called <code>IServiceCollection</code>. You can register dependencies in a number of ways, but fundamental to all is the concept of <a href="https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#service-lifetimes">service lifetime</a>. It distills down to:</p>
<ul>
<li>Transient = new for every container access</li>
<li>Scoped = new for every client request</li>
<li>Singleton = created at startup, or first container access</li>
</ul>
<p>Our greeter is both stateless and cheap to construct. So any of the lifetimes will suffice. But let's register it as a singleton. This time however, we'll create our web server in two stages, to gain access to the dependency container.</p>
<pre><code class="language-fsharp">let bldr = WebApplication.CreateBuilder() // &lt;-- create a configurable web application builder

bldr.Services
    .AddSingleton&lt;IGreeter, FriendlyGreeter&gt;() // &lt;-- register the greeter as singleton in the container
    |&gt; ignore

let wapp = bldr.Build() // &lt;-- manifest our WebApplication

let endpoints =
    [
        mapGet &quot;/{name?}&quot;
            (fun r -&gt; r?name.AsString(&quot;world&quot;))
            (fun name ctx -&gt;
                let greeter = ctx.Plug&lt;IGreeter&gt;() // &lt;-- access our dependency from the container
                let greeting = greeter.Greet(name) // &lt;-- invoke our greeter.Greet(name) method
                Response.ofPlainText greeting ctx)
    ]

wapp.UseRouting()
    .UseFalco(endpoints)
    .Run()
</code></pre>
<p>Following through you can see the web server being created in two phases. The first to establish the context (i.e., logging, server configuration and dependencies). Second, freezing the final state and creating a configurable web application.</p>
<p>Within the handler you can see the interaction with the dependency container using <code>ctx.Plug&lt;IGreeter&gt;()</code>. This code tells the container to return the implementation it has registered for that abstraction. In our case <code>FriendlyGreeter</code>.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>Now that we're finished introducing dependency injection, let's move on to a real world example by integrating with an external view engine.</p>
<p><a href="example-external-view-engine.html">Next: Example - External View Engine</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/example-external-view-engine.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Example - External View Engine - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="example-external-view-engine">Example - External View Engine</h1>
<p>Falco comes packaged with a <a href="markup.html">built-in view engine</a>. But if you'd prefer to write your own templates, or use an external template engine, that is entirely possible as well.</p>
<p>In this example we'll do some basic page rendering by integrating with <a href="https://github.com/scriban/scriban">scriban</a>. An amazing template engine by <a href="https://github.com/xoofx">xoofx</a>.</p>
<p>The code for this example can be found <a href="https://github.com/FalcoFramework/Falco/tree/master/examples/ExternalViewEngine">here</a>.</p>
<h2 id="creating-the-application-manually">Creating the Application Manually</h2>
<pre><code class="language-shell">&gt; dotnet new falco -o ExternalViewEngineApp
&gt; cd ExternalViewEngineApp
&gt; dotnet add package Scriban
</code></pre>
<h2 id="implementing-a-template-engine">Implementing a Template Engine</h2>
<p>There are a number of ways we could achieve this functionality. But in sticking with our previous examples, we'll create an interface. To keep things simple we'll use inline string literals for templates and perform rendering synchronously.</p>
<pre><code class="language-fsharp">open Scriban

type ITemplate =
    abstract member Render : template: string * model: obj -&gt; string

type ScribanTemplate() =
    interface ITemplate with
        member _.Render(template, model) =
            let tmpl = Template.Parse template
            tmpl.Render(model)
</code></pre>
<p>We define an interface <code>ITemplate</code> which describes template rendering as a function that receives a template string literal and a model, producing a string literal. Then we implement this interface definition using Scriban.</p>
<h2 id="rendering-pages">Rendering Pages</h2>
<p>To use our Scriban template engine we'll need to request it from the dependency container, then pass it our template literal and model.</p>
<blockquote>
<p>See <a href="example-dependency-injection.html">dependency injection</a> for further explanation.</p>
</blockquote>
<p>Since rendering more than one page is the goal, we'll create a shared <code>renderPage</code> function to do the dirty work for us.</p>
<pre><code class="language-fsharp">open Falco

module Pages =
    let private renderPage pageTitle template viewModel : HttpHandler = fun ctx -&gt;
        let templateService = ctx.Plug&lt;ITemplate&gt;() // &lt;-- obtain our template service from the dependency container
        let pageContent = templateService.Render(template, viewModel) // &lt;-- render our template with the provided view model as string literal
        let htmlTemplate = &quot;&quot;&quot;
            &lt;!DOCTYPE html&gt;
            &lt;html&gt;
            &lt;head&gt;
                &lt;meta charset=&quot;utf-8&quot;&gt;
                &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
                &lt;title&gt;{{title}}&lt;/title&gt;
            &lt;/head&gt;
            &lt;body&gt;
                {{content}}
            &lt;/body&gt;
            &lt;/html&gt;
        &quot;&quot;&quot;
        // ^ these triple quoted strings auto-escape characters like double quotes for us
        //   very practical for things like HTML

        let html = templateService.Render(htmlTemplate, {| Title = pageTitle; Content = pageContent |})

        Response.ofHtmlString html ctx // &lt;-- return template literal as &quot;text/html; charset=utf-8&quot; response
</code></pre>
<p>In this function we obtain the instance of our template engine, and immediately render the user-provided template and model. Next, we define a local template literal to serve as our layout. Assigning two simple inputs, <code>{{title}}</code> and <code>{{content}}</code>. Then we render the layout template using our template engine and an anonymous object literal <code>{| Title = pageTitle; Content = pageContent |}</code>, responding with the result of this as <code>text/html</code>.</p>
<p>To render pages, we simply need to create a localized template literal, and feed it into our <code>renderPage</code> function. Below we define a home and 404 page.</p>
<pre><code class="language-fsharp">    let homepage : HttpHandler = fun ctx -&gt;
        let query = Request.getQuery ctx // &lt;-- obtain access to strongly-typed representation of the query string
        let viewModel = {| Name = query?name.AsStringNonEmpty(&quot;World&quot;) |} // &lt;-- access 'name' from query, or default to 'World'
        let template = &quot;&quot;&quot;
            &lt;h1&gt;Hello {{ name }}!&lt;/h1&gt;
        &quot;&quot;&quot;
        renderPage $&quot;Hello {viewModel.Name}&quot; template viewModel ctx

    let notFound : HttpHandler =
        let template = &quot;&quot;&quot;
            &lt;h1&gt;Page not found&lt;/h1&gt;
        &quot;&quot;&quot;
        renderPage &quot;Page Not Found&quot; template {||}
</code></pre>
<h2 id="registering-the-template-engine">Registering the Template Engine</h2>
<p>Since our Scriban template engine is stateless and dependency-free, we can use the generic extension method to register it as a singleton.</p>
<blockquote>
<p>Note: <code>Transient</code> and <code>Scoped</code> lifetimes would also work here.</p>
</blockquote>
<pre><code>open Falco
open Falco.Routing
open Microsoft.AspNetCore.Builder
open Microsoft.Extensions.DependencyInjection

[&lt;EntryPoint&gt;]
let main args =
    let bldr = WebApplication.CreateBuilder(args)

    bldr.Services
        .AddSingleton&lt;ITemplate, ScribanTemplate&gt;() // &lt;-- register ITemplates implementation as a dependency
        |&gt; ignore

    let endpoints =
        [ get &quot;/&quot; Pages.homepage ]

    let wapp = bldr.Build()

    wapp.UseRouting()
        .UseFalco(endpoints)
        .UseFalcoNotFound(Pages.notFound)
        .Run()

    0 // Exit code
</code></pre>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>This example demonstrates how to effectively integrate an external view engine into your Falco application. By defining a simple interface, implementing it with Scriban and adding it to the dependency container, we can render HTML pages dynamically based on user input.</p>
<p><a href="example-basic-rest-api.html">Next: Example - Basic REST API</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/example-hello-world-mvc.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Example - Hello World MVC - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="example-hello-world-mvc">Example - Hello World MVC</h1>
<p>Let's take our basic <a href="example-hello-world.html">Hello World</a> to the next level. This means we're going to dial up the complexity a little bit. But we'll do this using the well recognized MVC pattern. We'll contain the app to a single file to make &quot;landscaping&quot; the pattern more straight-forward.</p>
<p>The code for this example can be found <a href="https://github.com/FalcoFramework/Falco/tree/master/examples/HelloWorldMvc">here</a>.</p>
<h2 id="creating-the-application-manually">Creating the Application Manually</h2>
<pre><code class="language-shell">&gt; dotnet new falco -o HelloWorldMvcApp
</code></pre>
<h2 id="model">Model</h2>
<p>Since this app has no persistence, the model is somewhat boring. But included here to demonstrate the concept.</p>
<p>We define two simple record types. One to contain the patron name, the other to contain a <code>string</code> message.</p>
<pre><code class="language-fsharp">module Model =
    type NameGreeting =
        { Name : string }

    type Greeting =
        { Message : string }
</code></pre>
<h2 id="routing">Routing</h2>
<p>As the project scales, it is generally helpful to have static references to your URLs and/or URL generating functions for dynamic resources.</p>
<p><a href="routing.html">Routing</a> begins with a route template, so it's only natural to define those first.</p>
<pre><code class="language-fsharp">module Route =
    let index = &quot;/&quot;
    let greetPlainText = &quot;/greet/text/{name}&quot;
    let greetJson = &quot;/greet/json/{name}&quot;
    let greetHtml = &quot;/greet/html/{name}&quot;
</code></pre>
<p>Here you can see we define one static route, and 3 dynamic route templates. We can provide URL generation from these dynamic route templates quite easily with some simple functions.</p>
<pre><code class="language-fsharp">module Url =
    let greetPlainText name = Route.greetPlainText.Replace(&quot;{name}&quot;, name)
    let greetJson name = Route.greetJson.Replace(&quot;{name}&quot;, name)
    let greetHtml name = Route.greetHtml.Replace(&quot;{name}&quot;, name)
</code></pre>
<p>These 3 functions take a string input called <code>name</code> and plug it into the <code>{name}</code> placeholder in the route template. This gives us a nice little typed API for creating our application URLs.</p>
<h2 id="view">View</h2>
<p>Falco comes packaged with a <a href="https://github.com/FalcoFramework/Falco.Markup/">lovely little HTML DSL</a>. It can produce any form of angle-markup, and does so very <a href="https://github.com/FalcoFramework/Falco.Markup/?tab=readme-ov-file#performance">efficiently</a>. The main benefit is that our views are <em>pure</em> F#, compile-time checked and live alongside the rest of our code.</p>
<p>First we define a shared HTML5 <code>layout</code> function, that references our project <code>style.css</code>. Next, we define a module to contain the views for our greetings.</p>
<blockquote>
<p>You'll notice the <code>style.css</code> file resides in a folder called <code>wwwroot</code>. This is an <a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/static-files">ASP.NET convention</a> which we'll enable later when we <a href="#web-server">build the web server</a>.</p>
</blockquote>
<pre><code class="language-fsharp">module View =
    open Model

    let layout content =
        Templates.html5 &quot;en&quot;
            [ _link [ _href_ &quot;/style.css&quot;; _rel_ &quot;stylesheet&quot; ] ]
            content

    module GreetingView =
        /// HTML view for /greet/html
        let detail greeting =
            layout [
                _h1' $&quot;Hello {greeting.Name} from /html&quot;
                _hr []
                _p' &quot;Greet other ways:&quot;
                _nav [] [
                    _a
                        [ _href_ (Url.greetPlainText greeting.Name) ]
                        [ _text &quot;Greet in text&quot;]
                    _text &quot; | &quot;
                    _a
                        [ _href_ (Url.greetJson greeting.Name) ]
                        [ _text &quot;Greet in JSON &quot; ]
                ]
            ]
</code></pre>
<p>The markup code is fairly self-explanatory. But essentially:</p>
<ul>
<li><code>Elem</code> produces HTML elements.</li>
<li><code>Attr</code> produces HTML element attributes.</li>
<li><code>Text</code> produces HTML text nodes.</li>
</ul>
<p>Each of these modules matches (or tries to) the full HTML spec. You'll also notice two of our URL generators at work.</p>
<h2 id="errors">Errors</h2>
<p>We'll define a couple static error pages to help prettify our error output.</p>
<pre><code class="language-fsharp">module Controller =
    open Model
    open View

    module ErrorController =
        let notFound : HttpHandler =
            Response.withStatusCode 404 &gt;&gt;
            Response.ofHtml (View.layout [ _h1' &quot;Not Found&quot; ])

        let serverException : HttpHandler =
            Response.withStatusCode 500 &gt;&gt;
            Response.ofHtml (View.layout [ _h1' &quot;Server Error&quot; ])
</code></pre>
<p>Here we see the <a href="repsonse.html#response-modifiers"><code>HttpResponseModifier</code></a> at play, which set the status code before buffering out the HTML response. We'll reference these pages later when be <a href="#web-server">build the web server</a>.</p>
<h2 id="controller">Controller</h2>
<p>Our controller will be responsible for four actions, as defined in our <a href="#routing">route</a> module. We define four handlers, one parameterless greeting and three others which output the user provided &quot;name&quot; in different ways: plain text, JSON and HTML.</p>
<pre><code class="language-fsharp">module Controller =
    open Model
    open View

    module ErrorController =
        // ...

    module GreetingController =
        let index =
            Response.ofPlainText &quot;Hello world&quot;

        let plainTextDetail name =
            Response.ofPlainText $&quot;Hello {name}&quot;

        let jsonDetail name =
            let message = { Message = $&quot;Hello {name} from /json&quot; }
            Response.ofJson message

        let htmlDetail name =
            { Name = name }
            |&gt; GreetingView.detail
            |&gt; Response.ofHtml

        let endpoints =
            let mapRoute (r : RequestData) =
                r?name.AsString()

            [ get Route.index index
              mapGet Route.greetPlainText mapRoute plainTextDetail
              mapGet Route.greetJson mapRoute jsonDetail
              mapGet Route.greetHtml mapRoute htmlDetail ]
</code></pre>
<p>You'll notice that the controller defines its own <code>endpoints</code>. This associates a route to a handler when passed into Falco (we'll do this later). Defining this within the controller is personal preference. But considering controller actions usually operate against a common URL pattern, it allows a private, reusable route mapping to exist (see <code>mapRoute</code>).</p>
<h2 id="web-server">Web Server</h2>
<p>This is a great opportunity to demonstrate further how to configure a more complex web server than we saw in the basic hello world example.</p>
<p>To do that, we'll define an explicit entry point function which gives us access to the command line argument. By then forwarding these into the web application, we gain further <a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration#command-line">configurability</a>. You'll notice the application contains a file called <code>appsettings.json</code>, this is another <a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration#default-application-configuration-sources">ASP.NET convention</a> that provides fully-featured and extensible configuration functionality.</p>
<p>Next we define an explicit collection of endpoints, which gets passed into the <code>.UseFalco(endpoints)</code> extension method.</p>
<p>In this example, we examine the environment name to create an &quot;is development&quot; toggle. We use this to determine the extensiveness of our error output. You'll notice we use our exception page from above when an exception occurs when not in development mode. Otherwise, we show a developer-friendly error page. Next we activate static file support, via the default web root of <code>wwwroot</code>.</p>
<p>We end off by registering a terminal handler, which functions as our &quot;not found&quot; response.</p>
<pre><code class="language-fsharp">module Program =
    open Controller

    let endpoints =
        [ get Route.index GreetingController.index
          get Route.greetPlainText GreetingController.plainTextDetail
          get Route.greetJson GreetingController.jsonDetail
          get Route.greetHtml GreetingController.htmlDetail ]


    /// By defining an explicit entry point, we gain access to the command line
    /// arguments which when passed into Falco are used as the creation arguments
    /// for the internal WebApplicationBuilder.
    [&lt;EntryPoint&gt;]
    let main args =
        let wapp = WebApplication.Create(args)

        let isDevelopment = wapp.Environment.EnvironmentName = &quot;Development&quot;

        wapp.UseIf(isDevelopment, DeveloperExceptionPageExtensions.UseDeveloperExceptionPage)
            .UseIf(not(isDevelopment), FalcoExtensions.UseFalcoExceptionHandler ErrorPage.serverException)
            .Use(StaticFileExtensions.UseStaticFiles)
            .UseFalco(endpoints)
            .UseFalcoNotFound(ErrorPage.notFound)
            .Run()

        0
</code></pre>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>This example was a leap ahead from our basic hello world. But having followed this, you know understand many of the patterns you'll need to know to build end-to-end server applications with Falco. Unsurprisingly, the entire program fits inside 118 LOC. One of the magnificent benefits of writing code in F#.</p>
<p><a href="example-dependency-injection.html">Next: Example - Dependency Injection</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/example-hello-world.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Example - Hello World - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="example-hello-world">Example - Hello World</h1>
<p>The goal of this program is to demonstrate the absolute bare bones hello world application, so that we can focus on the key elements when initiating a new web application.</p>
<p>The code for this example can be found <a href="https://github.com/FalcoFramework/Falco/tree/master/examples/HelloWorld">here</a>.</p>
<h2 id="creating-the-application-manually">Creating the Application Manually</h2>
<pre><code class="language-shell">&gt; dotnet new falco -o HelloWorldApp
</code></pre>
<h2 id="code-overview">Code Overview</h2>
<pre><code class="language-fsharp">open Falco
open Falco.Routing
open Microsoft.AspNetCore.Builder
// ^-- this import adds many useful extensions

let wapp = WebApplication.Create()

wapp.UseRouting()
    .UseFalco([
    // ^-- activate Falco endpoint source
        get &quot;/&quot; (Response.ofPlainText &quot;Hello World!&quot;)
        // ^-- associate GET / to plain text HttpHandler
    ])
    .Run(Response.ofPlainText &quot;Not found&quot;)
    // ^-- activate Falco endpoint source
</code></pre>
<p>First, we open the required namespaces. <code>Falco</code> bring into scope the ability to activate the library and some other extension methods to make the fluent API more user-friendly.</p>
<p><code>Microsoft.AspNetCore.Builder</code> enables us to create web applications in a number of ways, we're using <code>WebApplication.Create()</code> above. It also adds many other useful extension methods, that you'll see later.</p>
<p>After creating the web application, we:</p>
<ul>
<li>Activate Falco using <code>wapp.UseFalco()</code>. This enables us to create endpoints.</li>
<li>Register <code>GET /</code> endpoint to a handler which responds with &quot;hello world&quot;.</li>
<li>Run the app.</li>
</ul>
<p><a href="example-hello-world-mvc.html">Next: Example - Hello World MVC</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/example-htmx.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Example - HTMX - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="example-htmx">Example - HTMX</h1>
<p><a href="https://github.com/FalcoFramework/Falco.Htmx">Falco.Htmx</a> brings type-safe <a href="https://htmx.org/">htmx</a> support to <a href="https://github.com/FalcoFramework/Falco">Falco</a>. It provides a complete mapping of all attributes, typed request data and ready-made response modifiers.</p>
<p>In this example, we'll demonstrate some of the more common htmx attributes and how to use them with Falco.</p>
<p>At this point, we'll assume you have reviewed the docs, other examples and understand the basics of Falco. We don't be covering any of the basics in the code review.</p>
<p>The code for this example can be found <a href="https://github.com/FalcoFramework/Falco/tree/master/examples/Htmx">here</a>.</p>
<h2 id="creating-the-application-manually">Creating the Application Manually</h2>
<pre><code class="language-shell">&gt; dotnet new falco -o HtmxApp
&gt; cd HtmxApp
&gt; dotnet add package Falco.Htmx
</code></pre>
<h2 id="layout">Layout</h2>
<p>First we'll define a simple layout and enable htmx by including the script. Notice the strongly typed reference, <code>HtmxScript.cdnSrc</code>, which is provided by Falco.Htmx and resolves to the official CDN URL.</p>
<pre><code class="language-fsharp">module View =
    let template content =
        _html [ _lang_ &quot;en&quot; ] [
            _head [] [
                _script [ _src_ HtmxScript.cdnSrc ] [] ]
            _body [] content ]
</code></pre>
<p>With our layout defined, we can create a view to represent our starting state.</p>
<pre><code class="language-fsharp">module View =
    // Layout ...

    let clickAndSwap =
        template [
            _h1' &quot;Example: Click &amp; Swap&quot;
            _div [ _id_ &quot;content&quot; ] [
                _button [
                    _id_ &quot;clicker&quot;
                    Hx.get &quot;/click&quot;
                    Hx.swapOuterHtml ]
                    [ _text &quot;Click Me&quot; ] ] ]
</code></pre>
<p>This view contains a button that, when clicked, will send a GET request to the <code>/click</code> endpoint. The response from that request will replace the button with the response from the server.</p>
<h2 id="components">Components</h2>
<p>A nice convention when working with Falco.Markup is to create a <code>Components</code> module within your <code>View</code> module. We'll define one component here.</p>
<p>All of the htmx attributes and properties are mapped within the <code>Hx</code> module. Wherever a limited scope of options exist, strongly typed references are provided. For example, <code>Hx.swapInnerHtml</code> is a strongly typed reference to the <code>hx-swap</code> attribute with the value <code>innerHTML</code>. This is a great way to avoid typos and ensure that your code is type-safe.</p>
<pre><code class="language-fsharp">module View =
    // Layout &amp; view ...

    module Components =
        let resetter =
            _div [ _id_ &quot;resetter&quot; ] [
                _h2' &quot;Way to go! You clicked it!&quot;
                _br []
                _button [
                    Hx.get &quot;/reset&quot;
                    Hx.swapOuterHtml
                    Hx.targetCss &quot;#resetter&quot; ]
                    [ _text &quot;Reset&quot; ] ]
</code></pre>
<p>The <code>resetter</code> component is a simple button that will send a GET request to the server when clicked. The response will replace the entire <code>div</code> with the ID of <code>resetter</code> with the response from the server.</p>
<h2 id="handlers">Handlers</h2>
<p>Next we define a couple basic handlers to handle the requests for the original document and ajax requests.</p>
<pre><code class="language-fsharp">module App =
    let handleIndex : HttpHandler =
        Response.ofHtml View.clickAndSwap

    let handleClick : HttpHandler =
        Response.ofHtml View.Components.resetter

    let handleReset : HttpHandler =
        Response.ofFragment &quot;clicker&quot; View.clickAndSwap
</code></pre>
<p>The <code>handleIndex</code> handler is returning our full click-and-swap view, containing the clicker button. Clicking it triggers a request to the <code>handleClick</code> handler, which returns the resetter component. Clicking the reset button triggers a request to the <code>handleReset</code> handler, which returns the original clicker button as a [template fragment], extracted from the same view as the original state.</p>
<h2 id="web-server">Web Server</h2>
<p>To finish things off, we'll map our handlers to the expected routes and initialize the web server.</p>
<pre><code class="language-fsharp">let wapp = WebApplication.Create()

let endpoints =
    [
        get &quot;/&quot; App.handleIndex
        get &quot;/click&quot; App.handleClick
        get &quot;/reset&quot; App.handleReset
    ]

wapp.UseRouting()
    .UseFalco(endpoints)
    .Run()
</code></pre>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>That's it! You now have a simple web application that uses htmx to swap out components on the page without a full page reload. This is just the beginning of what you can do with htmx and Falco. You can use the same principles to create more complex interactions and components.</p>
<p>For more information about the htmx integration, check out the <a href="https://github.com/FalcoFramework/Falco.Htmx">Falco.Htmx</a> repository. It contains a full list of all the attributes and properties that are available, as well as examples of how to use them.</p>
<p><a href="/docs">Go back to docs home</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/example-open-api.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Example - Open API - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="example-open-api">Example - Open API</h1>
<p>Open API is a specification for defining APIs in a machine-readable format. It allows developers to describe the structure of their APIs, including endpoints, request/response formats, and authentication methods.</p>
<p><a href="https://github.com/FalcoFramework/Falco.OpenAPI">Falco.OpenAPI</a> is a library for generating OpenAPI documentation for Falco applications. It provides a set of combinators for annotating Falco routes with OpenAPI metadata, which can be used to generate OpenAPI documentation.</p>
<p>We'll dial back the complexity a bit from the <a href="example-basic-rest-api.html">Basic REST API</a> example and create a simple &quot;fortune teller&quot; Falco application that serves OpenAPI documentation.</p>
<p>The code for this example can be found <a href="https://github.com/FalcoFramework/Falco/tree/master/examples/OpenApi">here</a>.</p>
<h2 id="creating-the-application-manually">Creating the Application Manually</h2>
<pre><code class="language-shell">&gt; dotnet new falco -o OpenApiApi
&gt; cd OpenApiApp
&gt; dotnet add package Falco.OpenApi
</code></pre>
<h2 id="fortunes">Fortunes</h2>
<p>Our fortune teller will return fortune for the name of the person specified. To model this, we'll create two simple record types.</p>
<pre><code class="language-fsharp">type FortuneInput =
    { Name : string }

type Fortune =
    { Description : string }
</code></pre>
<p>For simplicity, we'll use a static member to return a fortune. In a real application, you would likely retrieve this from a database or an external service.</p>
<pre><code class="language-fsharp">module Fortune =
    let create age input =
        match age with
        | Some age when age &gt; 0 -&gt;
            { Description = $&quot;{input.Name}, you will experience great success when you are {age + 3}.&quot; }
        | _ -&gt;
            { Description = $&quot;{input.Name}, your future is unclear.&quot; }
</code></pre>
<h2 id="openapi-annotations">OpenAPI Annotations</h2>
<p>Next, we'll annotate our route with OpenAPI metadata. This is done using the <code>OpenApi</code> module from the <code>Falco.OpenAPI</code> package. Below is the startup code for our fortune teller application. We'll dissect it after the code block, and then add the OpenAPI annotations.</p>
<pre><code class="language-fsharp">[&lt;EntryPoint&gt;]
let main args =
    let bldr = WebApplication.CreateBuilder(args)

    bldr.Services
        .AddFalcoOpenApi()
        // ^-- add OpenAPI services
        .AddSwaggerGen()
        // ^-- add Swagger services
        |&gt; ignore

    let wapp = bldr.Build()

    wapp.UseHttpsRedirection()
        .UseSwagger()
        .UseSwaggerUI()
    |&gt; ignore

    let endpoints =
        [
            mapPost &quot;/fortune&quot;
                (fun r -&gt; r?age.AsIntOption())
                (fun ageOpt -&gt;
                    Request.mapJson&lt;FortuneInput&gt; (Fortune.create ageOpt &gt;&gt; Response.ofJson))
                // we'll add OpenAPI annotations here
        ]

    wapp.UseRouting()
        .UseFalco(endpoints)
        .Run()

    0
</code></pre>
<p>We've created a simple Falco application that listens for POST requests to the <code>/fortune</code> endpoint. The request body is expected to be a JSON object with a <code>name</code> property. The response will be a JSON object with a <code>description</code> property.</p>
<p>Now, let's add the OpenAPI annotations to our route.</p>
<pre><code class="language-fsharp">[&lt;EntryPoint&gt;]
let main args =
    // ... application setup code ...
    let endpoints =
        [
            mapPost &quot;/fortune&quot;
                (fun r -&gt; r?age.AsIntOption())
                (fun ageOpt -&gt;
                    Request.mapJson&lt;FortuneInput&gt; (Fortune.create ageOpt &gt;&gt; Response.ofJson))
                |&gt; OpenApi.name &quot;Fortune&quot;
                |&gt; OpenApi.summary &quot;A mystic fortune teller&quot;
                |&gt; OpenApi.description &quot;Get a glimpse into your future, if you dare.&quot;
                |&gt; OpenApi.query [
                    { Type = typeof&lt;int&gt;; Name = &quot;Age&quot;; Required = false } ]
                |&gt; OpenApi.acceptsType typeof&lt;FortuneInput&gt;
                |&gt; OpenApi.returnType typeof&lt;Fortune&gt;
        ]

    // ... application startup code ...

    0 // Exit code
</code></pre>
<p>In the code above, we use the <code>OpenApi</code> module to annotate our route with metadata.</p>
<p>Here's a breakdown of the annotations:</p>
<ul>
<li><code>OpenApi.name</code>: Sets the name of the operation.</li>
<li><code>OpenApi.summary</code>: Provides a short summary of the operation.</li>
<li><code>OpenApi.description</code>: Provides a detailed description of the operation.</li>
<li><code>OpenApi.query</code>: Specifies the query parameters for the operation. In this case, we have an optional <code>age</code> parameter.</li>
<li><code>OpenApi.acceptsType</code>: Specifies the expected request body type. In this case, we expect a JSON object that can be deserialized into a <code>FortuneInput</code> record.</li>
<li><code>OpenApi.returnType</code>: Specifies the response type. In this case, we return a JSON object that can be serialized into a <code>Fortune</code> record.</li>
</ul>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>That's it! You've successfully created a simple Falco application with OpenAPI documentation. You can now use the generated OpenAPI specification to generate client code, create API documentation, or integrate with other tools that support OpenAPI.</p>
<p><a href="example-htmx.html">Next: Example - htmx</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/get-started.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Getting Started - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="getting-started">Getting Started</h1>
<h2 id="using-dotnet-new">Using <code>dotnet new</code></h2>
<p>The easiest way to get started with Falco is by installing the <code>Falco.Template</code> package, which adds a new template to your <code>dotnet new</code> command line tool:</p>
<pre><code class="language-shell">&gt; dotnet new install &quot;Falco.Template::*&quot;
</code></pre>
<p>Afterwards you can create a new Falco application by running:</p>
<pre><code class="language-shell">&gt; dotnet new falco -o HelloWorldApp
&gt; cd HelloWorldApp
&gt; dotnet run
</code></pre>
<h2 id="manually-installing">Manually installing</h2>
<p>Create a new F# web project:</p>
<pre><code class="language-shell">&gt; dotnet new web -lang F# -o HelloWorldApp
&gt; cd HelloWorldApp
</code></pre>
<p>Install the nuget package:</p>
<pre><code class="language-shell">&gt; dotnet add package Falco
</code></pre>
<p>Remove any <code>*.fs</code> files created automatically, create a new file named <code>Program.fs</code> and set the contents to the following:</p>
<pre><code class="language-fsharp">open Falco
open Falco.Routing
open Microsoft.AspNetCore.Builder
// ^-- this import adds many useful extensions

let endpoints =
    [
        get &quot;/&quot; (Response.ofPlainText &quot;Hello World!&quot;)
        // ^-- associate GET / to plain text HttpHandler
    ]

let wapp = WebApplication.Create()

wapp.UseRouting()
    .UseFalco(endpoints)
    // ^-- activate Falco endpoint source
    .Run(Response.ofPlainText &quot;Not found&quot;)
    // ^-- run app and register terminal (i.e., not found) middleware
</code></pre>
<p>Run the application:</p>
<pre><code class="language-shell">&gt; dotnet run
</code></pre>
<p>And there you have it, an industrial-strength <a href="https://github.com/FalcoFramework/Falco/tree/master/examples/HelloWorld">Hello World</a> web app. Pretty sweet!</p>
<p><a href="routing.html">Next: Routing</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/host-configuration.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Host Configuration - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="host-configuration">Host Configuration</h1>
<p>As your app becomes more complex, you'll inevitably need to reach for some additional host configuration. This is where the <code>Microsoft.AspNetCore.Builder</code> import comes in. This assembly contains many useful extensions for configuring the server (ex: static files, authentication, authorization etc.).</p>
<p>Most of the extension methods have existed since the early days of ASP.NET Core and operate against <code>IApplicationBuilder</code>. But more recent version of ASP.NET Core have introduced a new <code>WebApplication</code> type that implements <code>IApplicationBuilder</code> and provides some additional functionality,  notably endpoint configuration. This dichotomy makes pipelining next to impossible. In C# you don't feel the sting of this as much because of <code>void</code> returns. But in F# this results in an excess amount of <code>|&gt; ignore</code> calls.</p>
<p>Let's take the hero code from the <a href="get-started.html">Getting Started</a> page and add the static file middleware to it:</p>
<pre><code class="language-fsharp">module Program

open Falco
open Falco.Routing
open Microsoft.AspNetCore.Builder

let wapp = WebApplication.Create()

wapp.UseRouting()
    .UseDefaultFiles() // you might innocently think this is fine
    .UseStaticFiles()  // and so is this
                       // but uknowingly, the underlying type has changed
    .UseFalco([
        get &quot;/&quot; (Response.ofPlainText &quot;Hello World!&quot;)
    ])
    .Run(Response.ofPlainText &quot;Not found&quot;)
    // ^-- this is no longer starts up our application

// one way to fix this:
wapp.UseRouting() |&gt; ignore
wapp.UseDefaultFiles().UseStaticFiles() |&gt; ignore

wapp.UseFalco([
        get &quot;/&quot; (Response.ofPlainText &quot;Hello World!&quot;)
    ])
    .Run(Response.ofPlainText &quot;Not found&quot;)

// but we can do better
</code></pre>
<p>To salve this, Falco comes with a several shims. The most important of these are <code>WebApplication.Use</code> and <code>WebApplication.UseIf</code> which allow you to compose a pipeline entirely driven by <code>WebApplication</code> while at the same time taking advantage of the existing ASP.NET Core extensions.</p>
<pre><code class="language-fsharp">wapp.UseRouting()
    .Use(fun (appl : IApplicationBuilder) -&gt;
        appl.UseDefaultFiles()
            .UseStaticFiles())
    .UseFalco([
        get &quot;/&quot; (Response.ofPlainText &quot;Hello World!&quot;)
    ])
    .Run(Response.ofPlainText &quot;Not found&quot;)
</code></pre>
<p>The optional, but recommended way to take advantage of these is to utilize the static methods that server as the underpinning to the various extension methods available. The code below will attempt to highlight this more clearly:</p>
<pre><code class="language-fsharp">// better yet
wapp.UseRouting()
    .Use(DefaultFilesExtensions.UseDefaultFiles)
    .Use(StaticFileExtensions.UseStaticFiles)
      // ^-- most IApplicationBuilder extensions are available as static methods similar to this
    .UseFalco([
        get &quot;/&quot; (Response.ofPlainText &quot;Hello World!&quot;)
    ])
    .Run(Response.ofPlainText &quot;Not found&quot;)
</code></pre>
<p>Next, we can use the <code>UseIf</code> extension method to conditionally add middleware to the pipeline. This is useful for things like development exception pages, or other middleware that you only want in certain environments.</p>
<pre><code class="language-fsharp">let isDevelopment = wapp.Environment.EnvironmentName = &quot;Development&quot;
wapp.UseRouting()
    .UseIf(isDevelopment, DeveloperExceptionPageExtensions.UseDeveloperExceptionPage)
    .UseIf(not(isDevelopment), FalcoExtensions.UseFalcoExceptionHandler ErrorPage.serverException)
    .Use(DefaultFilesExtensions.UseDefaultFiles)
    .Use(StaticFileExtensions.UseStaticFiles)
    .UseFalco([
        get &quot;/&quot; (Response.ofPlainText &quot;Hello World!&quot;)
    ])
    .Run(Response.ofPlainText &quot;Not found&quot;)
</code></pre>
<p>This is a great way to keep your code clean and readable, while still taking advantage of the powerful middleware pipeline that ASP.NET Core provides.</p>
<p><a href="deployment.html">Next: Deployment</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/index.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Welcome to Falco's Documentation - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Project Links</h3><a href="/">Project Homepage</a><a class="db" href="https://github.com/FalcoFramework/Falco" target="_blank">Source Code</a><a class="db" href="https://github.com/FalcoFramework/Falco/issues" target="_blank">Issue Tracker</a><a class="db" href="https://github.com/FalcoFramework/Falco/discussions" target="_blank">Discussion</a><a class="db" href="https://twitter.com/falco_framework" target="_blank">Twitter</a></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="welcome-to-falcos-documentation">Welcome to Falco's Documentation</h1>
<p>Visit the <a href="get-started.html">getting started</a> page for installation and a brief overview. There are also more detailed <a href="example-hello-world.html">examples</a> that shows how to create a small but complete application with Falco. The rest of the docs describe each component of Falco in detail.</p>
<h2 id="guides">Guides</h2>
<p>Falco depends only on the high-performance base components of .NET and ASP.NET Core, and provides a toolset to build a working full-stack web application. This section of the documentation explains the different parts of Falco and how they can be used, customized, and extended.</p>
<ul>
<li><a href="get-started.html">Getting Started</a></li>
<li><a href="routing.html">Routing</a></li>
<li><a href="response.html">Writing responses</a></li>
<li><a href="request.html">Accessing request data</a></li>
<li><a href="markup.html">View engine</a></li>
<li>Security
<ul>
<li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li>
<li><a href="authentication.html">Authentication &amp; Authorization</a></li>
</ul>
</li>
<li><a href="host-configuration.html">Host Configuration</a></li>
<li><a href="deployment.html">Deployment</a></li>
<li>Examples
<ul>
<li><a href="example-hello-world.html">Hello World</a></li>
<li><a href="example-hello-world-mvc.html">Hello World MVC</a></li>
<li><a href="example-dependency-injection.html">Dependency Injection</a></li>
<li><a href="example-external-view-engine.html">External View Engine</a></li>
<li><a href="example-basic-rest-api.html">Basic REST API</a></li>
<li><a href="example-open-api.html">Open API</a></li>
<li><a href="example-htmx.html">HTMX</a></li>
</ul>
</li>
</ul>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/markup.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Markup - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="markup">Markup</h1>
<p>Falco.Markup is broken down into three primary modules, <code>Elem</code>, <code>Attr</code> and <code>Text</code>, which are used to generate elements, attributes and text nodes respectively. Each module contain a suite of functions mapping to the various element/attribute/node names. But can also be extended to create custom elements and attributes.</p>
<p>Primary elements are broken down into two types, <code>ParentNode</code> or <code>SelfClosingNode</code>.</p>
<p><code>ParentNode</code> elements are those that can contain other elements. Represented as functions that receive two inputs: attributes and optionally elements.</p>
<p>Each of the primary modules can be access using the name directly, or using the &quot;underscore syntax&quot; seen below.</p>
<table>
<thead>
<tr>
<th>Module</th>
<th>Syntax</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Elem</code></td>
<td><code>_h1 [] []</code></td>
</tr>
<tr>
<td><code>Attr</code></td>
<td><code>_class_ &quot;my-class&quot;</code></td>
</tr>
<tr>
<td><code>Text</code></td>
<td><code>_text &quot;Hello world!&quot;</code></td>
</tr>
<tr>
<td><code>Text</code> shortcuts</td>
<td><code>_h1' &quot;Hello world&quot;</code> (note the trailing apostrophe)</td>
</tr>
</tbody>
</table>
<pre><code class="language-fsharp">let markup =
    _div [ _class_ &quot;heading&quot; ] [
        _h1' &quot;Hello world!&quot; ]
</code></pre>
<p><code>SelfClosingNode</code> elements are self-closing tags. Represented as functions that receive one input: attributes.</p>
<pre><code class="language-fsharp">let markup =
    _div [ _class_ &quot;divider&quot; ] [
        _hr [] ]
</code></pre>
<p>Text is represented using the <code>TextNode</code> and created using one of the functions in the <code>Text</code> module.</p>
<pre><code class="language-fsharp">let markup =
    _div [] [
        _p' &quot;A paragraph&quot;
        _p [] [ _textf &quot;Hello %s&quot; &quot;Jim&quot; ]
        _code [] [ _textEnc &quot;&lt;div&gt;Hello&lt;/div&gt;&quot; ] // HTML encodes text before rendering
    ]
</code></pre>
<p>Attributes contain two subtypes as well, <code>KeyValueAttr</code> which represent key/value attributes or <code>NonValueAttr</code> which represent boolean attributes.</p>
<pre><code class="language-fsharp">let markup =
    _input [ _type_ &quot;text&quot;; _required_ ]
</code></pre>
<p>Most <a href="https://developer.mozilla.org/en-US/docs/Web/Events">JavaScript Events</a> have also been mapped in the <code>Attr</code> module. All of these events are prefixed with the word &quot;on&quot; (i.e., <code>_onclick_</code>, <code>_onfocus_</code> etc.)</p>
<pre><code class="language-fsharp">let markup =
    _button [ _onclick_ &quot;console.log(\&quot;hello world\&quot;)&quot; ] [ _text &quot;Click me&quot; ]
</code></pre>
<h2 id="html">HTML</h2>
<p>Though Falco.Markup can be used to produce any markup. It is first and foremost an HTML library.</p>
<h3 id="combining-views-to-create-complex-output">Combining views to create complex output</h3>
<pre><code class="language-fsharp">open Falco.Markup

// Components
let divider =
    _hr [ _class_ &quot;divider&quot; ]

// Template
let master (title : string) (content : XmlNode list) =
    _html [ _lang_ &quot;en&quot; ] [
        _head [] [
            _title [] [ _text title ]
        ]
        _body [] content
    ]

// Views
let homeView =
    master &quot;Homepage&quot; [
        _h1' &quot;Homepage&quot;
        divider
        _p' &quot;Lorem ipsum dolor sit amet, consectetur adipiscing.&quot;
    ]

let aboutView =
    master &quot;About Us&quot; [
        _h1' &quot;About&quot;
        divider
        _p' &quot;Lorem ipsum dolor sit amet, consectetur adipiscing.&quot;
    ]
</code></pre>
<h3 id="strongly-typed-views">Strongly-typed views</h3>
<pre><code class="language-fsharp">open Falco.Markup

type Person =
    { FirstName : string
      LastName : string }

let doc (person : Person) =
    _html [ _lang_ &quot;en&quot; ] [
        _head [] [
            _title [] [ _text &quot;Sample App&quot; ]
        ]
        _body [] [
            _main [] [
                _h1' &quot;Sample App&quot;
                _p' $&quot;{person.First} {person.Last}&quot;
            ]
        ]
    ]
</code></pre>
<h3 id="forms">Forms</h3>
<p>Forms are the lifeblood of HTML applications. A basic form using the markup module would like the following:</p>
<pre><code class="language-fsharp">let dt = DateTime.Now

_form [ _methodPost_; _action_ &quot;/submit&quot; ] [
    _label [ _for_' &quot;name&quot; ] [ _text &quot;Name&quot; ]
    _input [ _id_ &quot;name&quot;; _name_ &quot;name&quot;; _typeText_ ]

    _label [ _for_' &quot;birthdate&quot; ] [ _text &quot;Birthday&quot; ]
    _input [ _id_ &quot;birthdate&quot;; _name_ &quot;birthdate&quot;; _typeDate_; _valueDate_ dt ]

    _input [ _typeSubmit_ ]
]
</code></pre>
<p>Expanding on this, we can create a more complex form involving multiple inputs and input types as follows:</p>
<pre><code class="language-fsharp">_form [ _methodPost_; _action_ &quot;/submit&quot; ] [
    _label [ _for_' &quot;name&quot; ] [ _text &quot;Name&quot; ]
    _input [ _id_ &quot;name&quot;; _name_ &quot;name&quot; ]

    _label [ _for_' &quot;bio&quot; ] [ _text &quot;Bio&quot; ]
    _textarea [ _name_ &quot;id&quot;; _name_ &quot;bio&quot; ] []

    _label [ _for_' &quot;hobbies&quot; ] [ _text &quot;Hobbies&quot; ]
    _select [ _id_ &quot;hobbies&quot;; _name_ &quot;hobbies&quot;; _multiple_ ] [
        _option [ _value_ &quot;programming&quot; ] [ _text &quot;Programming&quot; ]
        _option [ _value_ &quot;diy&quot; ] [ _text &quot;DIY&quot; ]
        _option [ _value_ &quot;basketball&quot; ] [ _text &quot;Basketball&quot; ]
    ]

    _fieldset [] [
        _legend [] [ _text &quot;Do you like chocolate?&quot; ]
        _label [] [
            _text &quot;Yes&quot;
            _input [ _typeRadio_; _name_ &quot;chocolate&quot;; _value_ &quot;yes&quot; ] ]
        _label [] [
            _text &quot;No&quot;
            _input [ _typeRadio_; _name_ &quot;chocolate&quot;; _value_ &quot;no&quot; ] ]
    ]

    _fieldset [] [
        _legend [] [ _text &quot;Subscribe to our newsletter&quot; ]
        _label [] [
            _text &quot;Receive updates about product&quot;
            _input [ _typeCheckbox_; _name_ &quot;newsletter&quot;; _value_ &quot;product&quot; ] ]
        _label [] [
            _text &quot;Receive updates about company&quot;
            _input [ _typeCheckbox_; _name_ &quot;newsletter&quot;; _value_ &quot;company&quot; ] ]
    ]

    _input [ _typeSubmit_ ]
]
</code></pre>
<p>A simple but useful <em>meta</em>-element <code>_control</code> can reduce the verbosity required to create form outputs. The same form would look like:</p>
<pre><code class="language-fsharp">_form [ _methodPost_; _action_ &quot;/submit&quot; ] [
    _control &quot;name&quot; [] [ _text &quot;Name&quot; ]

    _controlTextarea &quot;bio&quot; [] [ _text &quot;Bio&quot; ] []

    _controlSelect &quot;hobbies&quot; [ _multiple_ ] [ _text &quot;Hobbies&quot; ] [
        _option [ _value_ &quot;programming&quot; ] [ _text &quot;Programming&quot; ]
        _option [ _value_ &quot;diy&quot; ] [ _text &quot;DIY&quot; ]
        _option [ _value_ &quot;basketball&quot; ] [ _text &quot;Basketball&quot; ]
    ]

    _fieldset [] [
        _legend [] [ _text &quot;Do you like chocolate?&quot; ]
        _control &quot;chocolate&quot; [ _id_ &quot;chocolate_yes&quot;; _typeRadio_ ] [ _text &quot;yes&quot; ]
        _control &quot;chocolate&quot; [ _id_ &quot;chocolate_no&quot;; _typeRadio_ ] [ _text &quot;no&quot; ]
    ]

    _fieldset [] [
        _legend [] [ _text &quot;Subscribe to our newsletter&quot; ]
        _control &quot;newsletter&quot; [ _id_ &quot;newsletter_product&quot;; _typeCheckbox_ ] [ _text &quot;Receive updates about product&quot; ]
        _control &quot;newsletter&quot; [ _id_ &quot;newsletter_company&quot;; _typeCheckbox_ ] [ _text &quot;Receive updates about company&quot; ]
    ]

    _input [ _typeSubmit_ ]
]
</code></pre>
<h3 id="attribute-value">Attribute Value</h3>
<p>One of the more common places of sytanctic complexity is with <code>_value_</code> which expects, like all <code>Attr</code> functions, <code>string</code> input. Some helpers exist to simplify this.</p>
<pre><code class="language-fsharp">let dt = DateTime.Now

_input [ _typeDate_; _valueStringf_ &quot;yyyy-MM-dd&quot; dt ]

// you could also just use:
_input [ _typeDate_; _valueDate_ dt ] // formatted to ISO-8601 yyyy-MM-dd

// or,
_input [ _typeMonth_; _valueMonth_ dt ] // formatted to ISO-8601 yyyy-MM

// or,
_input [ _typeWeek_; _valueWeek_ dt ] // formatted to Gregorian yyyy-W#

// it works for TimeSpan too:
let ts = TimeSpan(12,12,0)
_input [ _typeTime_; _valueTime_ ts ] // formatted to hh:mm

// there is a helper for Option too:
let someTs = Some ts
_input [ _typeTime_; _valueOption_ _valueTime_ someTs ]
</code></pre>
<h3 id="merging-attributes">Merging Attributes</h3>
<p>The markup module allows you to easily create components, an excellent way to reduce code repetition in your UI. To support runtime customization, it is advisable to ensure components (or reusable markup blocks) retain a similar function &quot;shape&quot; to standard elements. That being, <code>XmlAttribute list -&gt; XmlNode list -&gt; XmlNode</code>.</p>
<p>This means that you will inevitably end up needing to combine your predefined <code>XmlAttribute list</code> with a list provided at runtime. To facilitate this, the <code>Attr.merge</code> function will group attributes by key, and intelligently concatenate the values in the case of additive attributes (i.e., <code>class</code>, <code>style</code> and <code>accept</code>).</p>
<pre><code class="language-fsharp">open Falco.Markup

// Components
let heading (attrs : XmlAttribute list) (content : XmlNode list) =
    // safely combine the default XmlAttribute list with those provided
    // at runtime
    let attrs' =
        Attr.merge [ _class_ &quot;text-large&quot; ] attrs

    _div [] [
        _h1 [ attrs' ] content
    ]

// Template
let master (title : string) (content : XmlNode list) =
    _html [ _lang_ &quot;en&quot; ] [
        _head [] [
            _title [] [ _text title ]
        ]
        _body [] content
    ]

// Views
let homepage =
    master &quot;Homepage&quot; [
        heading [ _class_ &quot;red&quot; ] [ _text &quot;Welcome to the homepage&quot; ]
        _p' &quot;Lorem ipsum dolor sit amet, consectetur adipiscing.&quot;
    ]

let homepage =
    master &quot;About Us&quot; [
        heading [ _class_ &quot;purple&quot; ] [ _text &quot;This is what we're all about&quot; ]
        _p' &quot;Lorem ipsum dolor sit amet, consectetur adipiscing.&quot;
    ]
</code></pre>
<h2 id="custom-elements-attributes">Custom Elements &amp; Attributes</h2>
<p>Every effort has been taken to ensure the HTML and SVG specs are mapped to functions in the module. In the event an element or attribute you need is missing, you can either file an <a href="https://github.com/pimbrouwers/Falco.Markup/issues">issue</a>, or more simply extend the module in your project.</p>
<p>An example creating custom XML elements and using them to create a structured XML document:</p>
<pre><code class="language-fsharp">open Falco.Makrup

module XmlElem =
    let books = Attr.create &quot;books&quot;
    let book = Attr.create &quot;book&quot;
    let name = Attr.create &quot;name&quot;

module XmlAttr =
    let soldOut = Attr.createBool &quot;soldOut&quot;

let xmlDoc =
    XmlElem.books [] [
        XmlElem.book [ XmlAttr.soldOut ] [
            XmlElem.name [] [ _text &quot;To Kill A Mockingbird&quot; ]
        ]
    ]

let xml = renderXml xmlDoc
</code></pre>
<h2 id="template-fragments">Template Fragments</h2>
<p>There are circumstances where you may want to render only a portion of your view. Especially common in <a href="https://htmx.org/essays/hypermedia-driven-applications/">hypermedia driven</a> applications. Supporting <a href="https://htmx.org/essays/template-fragments/">template fragments</a> is helpful in maintaining locality of behaviour, because it allows you to decompose a particular view for partial updates internally without pulling fragments of the template out to separate files for rendering, creating a large number of individual templates.</p>
<p>Falco.Markup supports this pattern by way of the <code>renderFragment</code> function, which will traverse the provided <code>XmlNode</code> tree and render only the child node matching the provided <code>id</code>. Otherwise, gracefully returning an empty string if no match is found.</p>
<pre><code class="language-fsharp">open Falco.Markup

let view =
    _div [ _id_ &quot;my-div&quot;; _class_ &quot;my-class&quot; ] [
        _h1 [ _id_ &quot;my-heading&quot; ] [ _text &quot;hello&quot; ] ]

let render = renderFragment doc &quot;my-heading&quot;
// produces: &lt;h1 id=&quot;my-heading&quot;&gt;hello&lt;/h1&gt;
</code></pre>
<h2 id="svg">SVG</h2>
<p>Much of the SVG spec has been mapped to element and attributes functions. There is also an SVG template to help initialize a new drawing with a valid viewbox.</p>
<pre><code class="language-fsharp">open Falco.Markup
open Falco.Markup.Svg

// https://developer.mozilla.org/en-US/docs/Web/SVG/Element/text#example
let svgDrawing =
    Templates.svg (0, 0, 240, 80) [
        _style [] [
            _text &quot;.small { font: italic 13px sans-serif; }&quot;
            _text &quot;.heavy { font: bold 30px sans-serif; }&quot;
            _text &quot;.Rrrrr { font: italic 40px serif; fill: red; }&quot;
        ]
        _text [ _x_ &quot;20&quot;; _y_ &quot;35&quot;; _class_ &quot;small&quot; ] [ _text &quot;My&quot; ]
        _text [ _x_ &quot;40&quot;; _y_ &quot;35&quot;; _class_ &quot;heavy&quot; ] [ _text &quot;cat&quot; ]
        _text [ _x_ &quot;55&quot;; _y_ &quot;55&quot;; _class_ &quot;small&quot; ] [ _text &quot;is&quot; ]
        _text [ _x_ &quot;65&quot;; _y_ &quot;55&quot;; _class_ &quot;Rrrrr&quot; ] [ _text &quot;Grumpy!&quot; ]
    ]

let svg = renderNode svgDrawing
</code></pre>
<p><a href="cross-site-request-forgery.html">Next: Cross-site Request Forgery (XSRF)</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/migrating-from-v4-to-v5.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Migrating from v4.x to v5.x - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="migrating-from-v4.x-to-v5.x">Migrating from v4.x to v5.x</h1>
<p>With Falco v5.x the main objective was to simplify the API and improve the overall devlopment experience long term. The idea being provide only what is necessary, or provides the most value in the most frequently developed areas.</p>
<p>This document will attempt to cover the anticipated transformations necessary to upgrade from v4.x to v5.x. Pull requests are welcome for missing scenarios, thank you in advance for your help.</p>
<h2 id="webhost-expression"><code>webHost</code> expression</h2>
<p>Perhaps the most significant change is the removal of the <code>webHost</code> expression, which attempted to make web application server construction more pleasant. Microsoft has made really nice strides in this area (i.e., <code>WebApplication</code>) and it's been difficult at times to stay sync with the breaking changes to the underlying interfaces. As such, we elected to remove it altogether.</p>
<p>Below demonstrates how to migrate a &quot;hello world&quot; app from v4 to v5 by replacing the <code>webHost</code> expression with the Microsoft provided <code>WebApplicationBuilder</code>.</p>
<table>
<tr>
<td>
<pre><code class="language-fsharp">// Falco v4.x
open Falco

webHost args {

    use_static_files

    endpoints [
        get &quot;/&quot;
            (Response.ofPlainText &quot;hello world&quot;)
    ]
}
</code></pre>
</td>
<td>
<pre><code class="language-fsharp">// Falco v5.x
open Falco
open Falco.Routing
open Microsoft.AspNetCore.Builder
// ^-- this import adds many useful extensions

let endpoints =
    [
        get &quot;/&quot; (Response.ofPlainText &quot;Hello World!&quot;)
        // ^-- associate GET / to plain text HttpHandler
    ]

let wapp = WebApplication.Create()

wapp.UseRouting()
    .UseFalco(endpoints)
    // ^-- activate Falco endpoint source
    .Run()
</code></pre>
</td>
</tr>
</table>
<h2 id="configuration-expression"><code>configuration</code> expression</h2>
<p>The configuration expression has also been removed. Again, the idea being to try and get in the way of potentially evolving APIs as much as possible. Even more so in the areas where the code was mostly decorative.</p>
<blockquote>
<p>Note: This example is entirely trivial since the <code>WebApplication.CreateBuilder()</code> configures a host with common, sensible defaults.</p>
</blockquote>
<table>
<tr>
<td>
<pre><code class="language-fsharp">open Falco
open Falco.HostBuilder

let config = configuration [||] {
    required_json &quot;appsettings.json&quot;
    optional_json &quot;appsettings.Development.json&quot;
}

webHost [||] {
    endpoints []
}
</code></pre>
</td>
<td>
<pre><code class="language-fsharp">open Falco
open Falco.Routing
open Microsoft.AspNetCore.Builder
open Microsoft.Extensions.Configuration
// ^-- this import adds access to Configuration

let bldr = WebApplication.CreateBuilder()
let conf =
    bldr.Configuration
        .AddJsonFile(&quot;appsettings.json&quot;, optional = false)
        .AddJsonFile(&quot;appsettings.Development.json&quot;)

let wapp = WebApplication.Create()

let endpoints = []

wapp.UseRouting()
    .UseFalco(endpoints)
    .Run()
</code></pre>
</td>
</tr>
</table>
<h2 id="stringcollectionreader-replaced-by-requestdata"><code>StringCollectionReader</code> replaced by <code>RequestData</code></h2>
<p>For the most part, this upgrade won't require any changes for the end user. Especially if the continuation-style functions in the <code>Request</code> module were used.</p>
<p>Explicit references to: <code>CookieCollectionReader</code>, <code>HeaderCollectionReader</code>, <code>RouteCollectionReader</code>, <code>QueryCollectionReader</code> will need to be updated to <code>RequestData</code>. <code>FormCollectionReader</code> has been replaced by <code>FormData</code>.</p>
<h2 id="form-streaming">Form Streaming</h2>
<p>Falco now automatically detects whether the form is transmiting <code>multipart/form-data</code>, which means deprecating the <code>Request</code> module streaming functions.</p>
<ul>
<li><code>Request.streamForm</code> becomes -&gt; <code>Request.mapForm</code></li>
<li><code>Request.streamFormSecure</code> becomes -&gt; <code>Request.mapFormSecure</code></li>
<li><code>Request.mapFormStream</code>  becomes -&gt; <code>Request.mapForm</code></li>
<li><code>Request.mapFormStreamSecure</code> becomes -&gt; <code>Request.mapFormSecure</code></li>
</ul>
<h2 id="removed-services.injectt1.t5">Removed <code>Services.inject&lt;'T1 .. 'T5&gt;</code></h2>
<p>This type was removed because it continued to pose problems for certain code analysis tools. To continue using the service locator pattern, you can now use the more versatile <code>HttpContext</code> extension method <code>ctx.Plug&lt;T&gt;()</code>. For example:</p>
<pre><code class="language-fsharp">let myHandler : HttpHandler =
    Services.inject&lt;MyService&gt; (fun myService ctx -&gt;
        let message = myService.CreateMessage()
        Response.ofPlainText $&quot;{message}&quot; ctx)

// becomes
let myHandler : HttpHandler = fun ctx -&gt;
    let myService = ctx.Plug&lt;MyService&gt;()
    let message = myService.CreateMessage()
    Response.ofPlainText $&quot;{message}&quot; ctx

</code></pre>
<h2 id="xss-module-renamed-to-xsrf"><code>Xss</code> module renamed to <code>Xsrf</code></h2>
<p>The <code>Xss</code> module has been renamed to <code>Xsrf</code> to better describe it's intent.</p>
<pre><code class="language-fsharp">    //before: Xss.antiforgeryInput
    Xsrf.antiforgeryInput // ..

    //before: Xss.getToken
    Xsrf.getToken // ..

    //before: Xss.validateToken
    Xsrf.validateToken // ..
</code></pre>
<h2 id="crypto-module-removed"><code>Crypto</code> module removed</h2>
<p>The Crypto module provided functionality for: random numbers, salt generation and key derivation. The code in this module was really a veneer on top of the cryptographic providers in the base library. Extracting this code into your project would be dead simple. The <a href="https://github.com/FalcoFramework/Falco/blob/25d828d832c0fde2dfff04775bea1eced9050458/src/Falco/Security.fs#L3">source</a> is permalinked here for such purposes.</p>
<h2 id="auth-module-removed"><code>Auth</code> module removed</h2>
<p>The <code>Auth</code> module functionality was ported one-to-one to the <code>Response</code> module.</p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/request.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Request Handling - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="request-handling">Request Handling</h1>
<p>Falco exposes a <strong>uniform API</strong> to obtain typed values from <code>IFormCollection</code>, <code>IQueryCollection</code>, <code>RouteValueDictionary</code>, <code>IHeaderCollection</code>, and <code>IRequestCookieCollection</code>. This is achieved by means of the <code>RequestData</code> type and it's derivative <code>FormData</code>. These abstractions are intended to make it easier to work with the url-encoded key/value collections.</p>
<blockquote>
<p>Take note of the similarities when interacting with the different sources of request data.</p>
</blockquote>
<h2 id="a-brief-aside-on-the-keyvalue-semantics">A brief aside on the key/value semantics</h2>
<p><code>RequestData</code> is supported by a recursive discriminated union called <code>RequestValue</code> which represents a parsed key/value collection.</p>
<p>The <code>RequestValue</code> parsing process provides some simple, yet powerful, syntax to submit objects and collections over-the-wire, to facilitate complex form and query submissions.</p>
<h3 id="key-syntax-object-notation">Key Syntax: Object Notation</h3>
<p>Keys using dot notation are interpreted as complex (i.e., nested values) objects.</p>
<p>Consider the following POST request:</p>
<pre><code>POST /my-form HTTP/1.1
Host: foo.example
Content-Type: application/x-www-form-urlencoded
Content-Length: 46

user.name=john%20doe&amp;user.email=abc@def123.com
</code></pre>
<p>This will be intepreted as the following <code>RequestValue</code>:</p>
<pre><code class="language-fsharp">RObject [
    &quot;user&quot;, RObject [
        &quot;name&quot;, RString &quot;john doe&quot;
        &quot;email&quot;, RString &quot;abc@def123.com&quot;
    ]
]
</code></pre>
<p>See <a href="#form-binding">form binding</a> for details on interacting with form data.</p>
<h3 id="key-syntax-list-notation">Key Syntax: List Notation</h3>
<p>Keys using square bracket notation are interpreted as lists, which can include both primitives and <a href="#key-syntax-object-notation">complex objects</a>. Both indexed and non-indexed variants are supported.</p>
<p>Consider the following request:</p>
<pre><code>GET /my-search?name=john&amp;season[0]=summer&amp;season[1]=winter&amp;hobbies[]=hiking HTTP/1.1
Host: foo.example
Content-Type: application/x-www-form-urlencoded
Content-Length: 68
</code></pre>
<p>This will be interpreted as the following <code>RequestValue</code>:</p>
<pre><code class="language-fsharp">RObject [
    &quot;name&quot;, RString &quot;john&quot;
    &quot;season&quot;, RList [ RString &quot;summer&quot;; RString &quot;winter&quot; ]
    &quot;hobbies&quot;, RList [ RString &quot;hking&quot; ]
]
</code></pre>
<p>See <a href="#query-binding">query binding</a> for details on interacting with form data.</p>
<h2 id="request-data-access">Request Data Access</h2>
<p><code>RequestData</code> provides the ability to safely read primitive types from flat and nested key/value collections.</p>
<pre><code class="language-fsharp">let requestData : RequestData = // From: Route | Query | Form

// Retrieve primitive options
let str : string option = requestData.TryGetString &quot;name&quot;
let flt : float option = requestData.TryGetFloat &quot;temperature&quot;

// Retrieve primitive, or default
let str : string = requestData.GetString &quot;name&quot;
let strOrDefault : string = requestData.GetString (&quot;name&quot;, &quot;John Doe&quot;)
let flt : float = requestData.GetFloat &quot;temperature&quot;

// Retrieve primitive list
let strList : string list = requestData.GetStringList &quot;hobbies&quot;
let grades : int list = requestData.GetInt32List &quot;grades&quot;

// Dynamic access, useful for nested/complex collections
// Equivalent to:
// requestData.Get(&quot;user&quot;).Get(&quot;email_address&quot;).AsString()
let userEmail = requestData?user?email_address.AsString()

</code></pre>
<h2 id="route-binding">Route Binding</h2>
<p>Provides access to the values found in the <code>RouteValueDictionary</code>.</p>
<pre><code class="language-fsharp">open Falco

// Assuming a route pattern of /{Name}
let manualRouteHandler : HttpHandler = fun ctx -&gt;
    let r = Request.getRoute ctx
    let name = r.GetString &quot;Name&quot;
    // Or, let name = r?Name.AsString()
    // Or, let name = r.TryGetString &quot;Name&quot; |&gt; Option.defaultValue &quot;&quot;
    Response.ofPlainText name ctx

let mapRouteHandler : HttpHandler =
    Request.mapRoute (fun r -&gt;
        r.GetString &quot;Name&quot;)
        Response.ofPlainText

</code></pre>
<h2 id="query-binding">Query Binding</h2>
<p>Provides access to the values found in the <code>IQueryCollection</code>, as well as the <code>RouteValueDictionary</code>. In the case of matching keys, the values in the <code>IQueryCollection</code> take precedence.</p>
<pre><code class="language-fsharp">open Falco

type Person =
    { FirstName : string
      LastName : string }

let form : HttpHandler =
    Response.ofHtmlCsrf view

let manualQueryHandler : HttpHandler = fun ctx -&gt;
    let q = Request.getQuery ctx

    let person =
        { FirstName = q.GetString (&quot;FirstName&quot;, &quot;John&quot;) // Get value or return default value
          LastName  = q.GetString (&quot;LastName&quot;, &quot;Doe&quot;) }

    Response.ofJson person ctx

let mapQueryHandler : HttpHandler =
    Request.mapQuery (fun q -&gt;
        let first = q.GetString (&quot;FirstName&quot;, &quot;John&quot;) // Get value or return default value
        let last = q.GetString (&quot;LastName&quot;, &quot;Doe&quot;)
        { FirstName = first; LastName = last })
        Response.ofJson
</code></pre>
<h2 id="form-binding">Form Binding</h2>
<p>Provides access to the values found in he <code>IFormCollection</code>, as well as the <code>RouteValueDictionary</code>. In the case of matching keys, the values in the <code>IFormCollection</code> take precedence.</p>
<p>The <code>FormData</code> inherits from <code>RequestData</code> type also exposes the <code>IFormFilesCollection</code> via the <code>_.Files</code> member and <code>_.TryGetFile(name : string)</code> method.</p>
<pre><code class="language-fsharp">type Person =
    { FirstName : string
      LastName : string }

let manualFormHandler : HttpHandler = fun ctx -&gt;
    task {
        let! f : FormData = Request.getForm ctx

        let person =
            { FirstName = f.GetString (&quot;FirstName&quot;, &quot;John&quot;) // Get value or return default value
              LastName = f.GetString (&quot;LastName&quot;, &quot;Doe&quot;) }

        return! Response.ofJson person ctx
    }

let mapFormHandler : HttpHandler =
    Request.mapForm (fun f -&gt;
        let first = f.GetString (&quot;FirstName&quot;, &quot;John&quot;) // Get value or return default value
        let last = f.GetString (&quot;LastName&quot;, &quot;Doe&quot;)
        { FirstName = first; LastName = last })
        Response.ofJson

let mapFormSecureHandler : HttpHandler =
    Request.mapFormSecure (fun f -&gt; // `Request.mapFormSecure` will automatically validate CSRF token for you.
        let first = f.GetString (&quot;FirstName&quot;, &quot;John&quot;) // Get value or return default value
        let last = f.GetString (&quot;LastName&quot;, &quot;Doe&quot;)
        { FirstName = first; LastName = last })
        Response.ofJson
        (Response.withStatusCode 400 &gt;&gt; Response.ofEmpty)

</code></pre>
<h3 id="multipartform-data-binding"><code>multipart/form-data</code> Binding</h3>
<p>Microsoft defines <a href="https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads#upload-large-files-with-streaming">large upload</a> as anything <strong>&gt; 64KB</strong>, which well... is most uploads. Anything beyond this size and they recommend streaming the multipart data to avoid excess memory consumption.</p>
<p>To make this process <strong>a lot</strong> easier Falco's form handlers will attempt to stream multipart form-data, or return an error message indicating the likely problem.</p>
<pre><code class="language-fsharp">let imageUploadHandler : HttpHandler =
    let formBinder (f : FormData) : IFormFile option =
        f.TryGetFormFile &quot;profile_image&quot;

    let uploadImage (profileImage : IFormFile option) : HttpHandler =
        // Process the uploaded file ...

    // Safely buffer the multipart form submission
    Request.mapForm formBinder uploadImage

let secureImageUploadHandler : HttpHandler =
    let formBinder (f : FormData) : IFormFile option =
        f.TryGetFormFile &quot;profile_image&quot;

    let uploadImage (profileImage : IFormFile option) : HttpHandler =
        // Process the uploaded file ...

    let handleInvalidCsrf : HttpHandler =
        Response.withStatusCode 400 &gt;&gt; Response.ofEmpty

    // Safely buffer the multipart form submission
    Request.mapFormSecure formBinder uploadImage handleInvalidCsrf
</code></pre>
<h2 id="json">JSON</h2>
<p>These handlers use the .NET built-in <code>System.Text.Json.JsonSerializer</code>.</p>
<pre><code class="language-fsharp">type Person =
    { FirstName : string
      LastName : string }

let jsonHandler : HttpHandler =
    Response.ofJson {
        FirstName = &quot;John&quot;
        LastName = &quot;Doe&quot; }

let mapJsonHandler : HttpHandler =
    let handleOk person : HttpHandler =
        let message = sprintf &quot;hello %s %s&quot; person.First person.Last
        Response.ofPlainText message

    Request.mapJson handleOk

let mapJsonOptionsHandler : HttpHandler =
    let options = JsonSerializerOptions()
    options.DefaultIgnoreCondition &lt;- JsonIgnoreCondition.WhenWritingNull

    let handleOk person : HttpHandler =
        let message = sprintf &quot;hello %s %s&quot; person.First person.Last
        Response.ofPlainText message

    Request.mapJsonOption options handleOk
</code></pre>
<p><a href="markup.html">Next: View engine</a></p>
</main></div><footer class="cl pa3 bg-merlot"><div class="f7 tc white-70">&copy; 2020-2025 Pim Brouwers & contributors.</div></footer><script src="/prism.js"></script></body></html>

================================================
FILE: docs/docs/response.html
================================================
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Response Writing - Falco Documentation</title><meta name="description" content="A functional-first toolkit for building brilliant ASP.NET Core applications using F#." /><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" href="/favicon.ico" type="image/x-icon" /><link rel="preconnect" href="https://fonts.gstatic.com" /><link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet" /><link href="/prism.css" rel="stylesheet" /><link href="/tachyons.css" rel="stylesheet" /><link href="/style.css" rel="stylesheet" /><script async src="https://www.googletagmanager.com/gtag/js?id=G-D62HSJHMNZ"></script><script>window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-D62HSJHMNZ');</script></head><body class="noto lh-copy"><div class="min-vh-100 mw9 center pa3 overflow-hidden"><nav class="sidebar w-20-l fl-l mb3 mb0-l"><div class="flex items-center"><a href="/docs" class="db w3 w4-l"><img src="/brand.svg" class="br3" /></a><h2 class="dn-l mt3 ml3 fw4 gray">Falco Documentation</h2></div><div class="dn db-l"><h3>Contents</h3><ul class="nl3 f6"><li><a href="get-started.html">Getting Started</a></li><li><a href="routing.html">Routing</a></li><li><a href="response.html">Response Writing</a></li><li><a href="request.html">Request Handling</a></li><li><a href="markup.html">Markup</a></li><li>Security<ul><li><a href="cross-site-request-forgery.html">Cross Site Request Forgery (XSRF)</a></li><li><a href="authentication.html">Authentication & Authorization</a></li></ul></li><li><a href="host-configuration.html">Host Configuration</a></li><li><a href="deployment.html">Deployment</a></li><li>Examples<ul><li><a href="example-hello-world.html">Hello World</a></li><li><a href="example-hello-world-mvc.html">Hello World MVC</a></li><li><a href="example-dependency-injection.html">Dependency Injection</a></li><li><a href="example-external-view-engine.html">External View Engine</a></li><li><a href="example-basic-rest-api.html">Basic REST API</a></li><li><a href="example-open-api.html">Open API</a></li><li><a href="example-htmx.html">htmx</a></li></ul></li><li><a href="migrating-from-v4-to-v5.html">V5 Migration Guide</a></li></ul></div></nav><main class="w-80-l fl-l pl3-l"><h1 id="response-writing">Response Writing</h1>
<p>The <code>HttpHandler</code> 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: <code>HttpContext -&gt; Task</code>. Handlers will typically involve some combination of: <a href="request.html#route-binding">route inspection</a>, <a href="request.html#form-binding">form</a>/<a href="request.html#query-binding">query</a> binding, business logic and finally response writing. With access to the <code>HttpContext</code> you are able to inspect all components of the request, and manipulate the response in any way you choose.</p>
<h2 id="plain-text-responses">Plain Text responses</h2>
<pre><code class="language-fsharp">let textHandler : HttpHandler =
    Response.ofPlainText &quot;hello world&quot;
</code></pre>
<h2 id="html-responses">HTML responses</h2>
<p>Write your views in plain F#, directly in your assembly, using the <a href="markup.html">Markup</a> module. A performant F# DSL capable of generating any angle-bracket markup. Also available directly as a standalone <a href="https://www.nuget.org/packages/Falco.Markup">NuGet</a> package.</p>
<pre><code class="language-fsharp">let htmlHandler : HttpHandler =
    let html =
        _html [ _lang_ &quot;en&quot; ] [
            _head [] []
            _body [] [
                _h1' &quot;Sample App&quot; // shorthand for: `_h1 [] [ Text.raw &quot;Sample App&quot; ]`
            ]
        ]

    Response.ofHtml html

// Automatically protect against XSS attacks
let secureHtmlHandler : HttpHandler =
    let html token =
        _html [] [
            _body [] [
                _form [ _method_ &quot;post&quot; ] [
                    _input [ _name_ &quot;first_name&quot; ]
                    _input [ _name_ &quot;last_name&quot; ]
                    // using the CSRF HTML helper
                    Xsrf.antiforgeryInput token
                    _input [ _type_ &quot;submit&quot;; _value_ &quot;Submit&quot; ]
                ]
            ]
        ]

    Response.ofHtmlCsrf html
</code></pre>
<p>Alternatively, if you're using an external view engine and want to return an HTML response from a string literal, then you can use <code>Response.ofHtmlString</code>.</p>
<pre><code class="language-fsharp">let htmlHandler : HttpHandler =
    Response.ofHtmlString &quot;&lt;html&gt;...&lt;/html&gt;&quot;
</code></pre>
<h2 id="template-fragments">Template Fragments</h2>
<p>If you want to return a <a href="https://htmx.org/essays/template-fragments/">fragment of HTML</a>, for example when working with <a href="https://htmx.org/">htmx</a>, you can use <code>Response.ofFragment</code> (or <code>Response.ofFragmentCsrf</code>). This function takes an element ID as its first argument, and a <code>XmlNode</code> as its second argument. The server will return only the contents of the node with the specified ID.</p>
<pre><code class="language-fsharp">let fragmentHandler : HttpHandler =
    let html =
        _div [ _id_ &quot;greeting&quot; ] [
            _h1 [ _id_ &quot;heading&quot; ] [ _text &quot;Hello, World!&quot; ]
        ]

    Response.ofFragment &quot;heading&quot; html
</code></pre>
<p>This will return only the contents of the <code>h1</code> element, i.e. <code>&lt;h1 id=&quot;heading&quot;&gt;Hello, World!&lt;/h1&gt;</code>. 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.</p>
<h2 id="json-responses">JSON responses</h2>
<p>These handlers use the .NET built-in <code>System.Text.Json.JsonSerializer</code>.</p>
<pre><code class="language-fsharp">type Person =
    { First : string
      Last  : string }

let jsonHandler : HttpHandler =
    let name = { First = &quot;John&quot;; Last = &quot;Doe&quot; }
    Response.ofJson name

let jsonOptionsHandler : HttpHandler =
    let options = JsonSerializerOptions()
    options.DefaultIgnoreCondition &lt;- JsonIgnoreCondition.WhenWritingNull
    let name = { First = &quot;John&quot;; Last = &quot;Doe&quot; }
    Response.ofJsonOptions options name
</code></pre>
<h2 id="redirect-301302-response">Redirect (301/302) Response</h2>
<pre><code class="language-fsharp">let oldUrlHandler : HttpHandler =
    Response.redirectPermanently &quot;/new-url&quot; // HTTP 301

let redirectUrlHandler : HttpHandler =
    Response.redirectTemporarily &quot;/new-url&quot; // HTTP 302
</code></pre>
<h2 id="content-disposition">Content Disposition</h2>
<pre><code class="language-fsharp">let inlineBinaryHandler : HttpHandler =
    let contentType = &quot;image/jpeg&quot;
    let headers = [ HeaderNames.CacheControl,  &quot;no-store, max-age=0&quot; ]
    let bytes = // ... binary data
    Response.ofBinary contentType headers bytes

let attachmentHandler : HttpHandler =
    let filename = &quot;profile.jpg&quot;
    let contentType = &quot;image/jpeg&quot;
    let headers = [ HeaderNames.CacheControl,  &quot;no-store, max-age=0&quot; ]
    let bytes = // ... binary data
    Response.ofAttachment filename contentType headers bytes
</code></pre>
<h2 id="response-modifiers">Response Modifiers</h2>
<p>Response modifiers can be thought of as the in-and-out modification of the <code>HttpResponse</code>. A preamble to writing and returning. Since these functions receive the <code>Httpcontext</code> as input and return it as the only output, they can take advantage of function compoistion.</p>
<h3 id="set-the-status-code-of-the-response">Set the status code of the response</h3>
<pre><code class="language-fsharp">let notFoundHandler : HttpHandler =
    Response.withStatusCode 404
    &gt;&gt; Response.ofPlainText &quot;Not found&quot;
</code></pre>
<h3 id="add-a-headers-to-the-response">Add a header(s) to the response</h3>
<pre><code class="language-fsharp">let handlerWithHeaders : HttpHandler =
    Response.withHeaders [ &quot;Content-Language&quot;, &quot;en-us&quot; ]
    &gt;&gt; Response.ofPlainText &quot;Hello world&quot;
</code></pre>
<h3 id="add-a-cookie-to-the-response">Add a cookie to the response</h3>
<blockquote>
<p>IMPORTANT: <em>Do not</em> use this for authentication. Instead use the <code>Response.signInAndRedirect</code> and <code>Respons
Download .txt
gitextract_7tuo7p7z/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── build.yml
├── .gitignore
├── Build.ps1
├── CHANGELOG.md
├── CNAME
├── Falco.sln
├── LICENSE
├── README.md
├── docs/
│   ├── CNAME
│   ├── docs/
│   │   ├── authentication.html
│   │   ├── cross-site-request-forgery.html
│   │   ├── deployment.html
│   │   ├── example-basic-rest-api.html
│   │   ├── example-dependency-injection.html
│   │   ├── example-external-view-engine.html
│   │   ├── example-hello-world-mvc.html
│   │   ├── example-hello-world.html
│   │   ├── example-htmx.html
│   │   ├── example-open-api.html
│   │   ├── get-started.html
│   │   ├── host-configuration.html
│   │   ├── index.html
│   │   ├── markup.html
│   │   ├── migrating-from-v4-to-v5.html
│   │   ├── request.html
│   │   ├── response.html
│   │   └── routing.html
│   ├── index.html
│   ├── prism.css
│   ├── prism.js
│   ├── style.css
│   └── tachyons.css
├── documentation/
│   ├── authentication.md
│   ├── cross-site-request-forgery.md
│   ├── deployment.md
│   ├── example-basic-rest-api.md
│   ├── example-dependency-injection.md
│   ├── example-external-view-engine.md
│   ├── example-hello-world-mvc.md
│   ├── example-hello-world.md
│   ├── example-htmx.md
│   ├── example-open-api.md
│   ├── get-started.md
│   ├── host-configuration.md
│   ├── markup.md
│   ├── migrating-from-v4-to-v5.md
│   ├── migrating-from-v5-to-v6.md
│   ├── readme.md
│   ├── request.md
│   ├── response.md
│   └── routing.md
├── examples/
│   ├── BasicRestApi/
│   │   ├── BasicRestApi.fs
│   │   ├── BasicRestApi.fsproj
│   │   └── appsettings.json
│   ├── DependencyInjection/
│   │   ├── DependencyInjection.fs
│   │   └── DependencyInjection.fsproj
│   ├── ExternalViewEngine/
│   │   ├── ExternalViewEngine.fs
│   │   └── ExternalViewEngine.fsproj
│   ├── Falco.Examples.sln
│   ├── HelloWorld/
│   │   ├── HelloWorld.fs
│   │   └── HelloWorld.fsproj
│   ├── HelloWorldMvc/
│   │   ├── HelloWorldMvc.fs
│   │   ├── HelloWorldMvc.fsproj
│   │   ├── appsettings.json
│   │   └── wwwroot/
│   │       └── style.css
│   ├── Htmx/
│   │   ├── Htmx.fs
│   │   ├── Htmx.fsproj
│   │   └── appsettings.json
│   └── OpenApi/
│       ├── OpenApi.fs
│       └── OpenApi.fsproj
├── global.json
├── site/
│   ├── Site.fs
│   └── Site.fsproj
├── src/
│   └── Falco/
│       ├── Core.fs
│       ├── Falco.fsproj
│       ├── Multipart.fs
│       ├── Request.fs
│       ├── RequestData.fs
│       ├── RequestValue.fs
│       ├── Response.fs
│       ├── Routing.fs
│       ├── Security.fs
│       ├── String.fs
│       └── WebApplication.fs
└── test/
    ├── Falco.IntegrationTests/
    │   ├── Falco.IntegrationTests.fsproj
    │   └── Program.fs
    ├── Falco.IntegrationTests.App/
    │   ├── Falco.IntegrationTests.App.fsproj
    │   └── Program.fs
    └── Falco.Tests/
        ├── Common.fs
        ├── Falco.Tests.fsproj
        ├── MultipartTests.fs
        ├── Program.fs
        ├── RequestDataTests.fs
        ├── RequestTests.fs
        ├── RequestValueTests.fs
        ├── ResponseTests.fs
        ├── RoutingTests.fs
        ├── SecurityTests.fs
        ├── StringTests.fs
        └── WebApplicationTests.fs
Download .txt
SYMBOL INDEX (12 symbols across 1 files)

FILE: docs/prism.js
  function o (line 3) | function o(e){l.highlightedCode=e,_.hooks.run("before-insert",l),l.eleme...
  function M (line 3) | function M(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=...
  function W (line 3) | function W(e,n,t,r){e.lastIndex=n;var a=e.exec(t);if(a&&r&&a[1]){var i=a...
  function i (line 3) | function i(){var e={value:null,prev:null,next:null},n={value:null,prev:e...
  function z (line 3) | function z(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a...
  function I (line 3) | function I(e,n,t){for(var r=n.next,a=0;a<t&&r!==e.tail;a++)r=r.next;(n.n...
  function t (line 3) | function t(){_.manual||_.highlightAll()}
  function a (line 6) | function a(e,s){return e.replace(/<<(\d+)>>/g,function(e,n){return"(?:"+...
  function t (line 6) | function t(e,n,s){return RegExp(a(e,n),s||"")}
  function e (line 6) | function e(e,n){for(var s=0;s<n;s++)e=e.replace(/<<self>>/g,function(){r...
  function l (line 6) | function l(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}
  function U (line 6) | function U(e,n){return{interpolation:{pattern:t("((?:^|[^{])(?:\\{\\{)*)...
Condensed preview — 101 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (708K chars).
[
  {
    "path": ".editorconfig",
    "chars": 174,
    "preview": "root=true\r\n\r\n[*]\r\ncharset=utf-8\r\nend_of_line=lf\r\ntrim_trailing_whitespace=true\r\ninsert_final_newline=true\r\nindent_style="
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 709,
    "preview": "name: build\n\non:\n  push:\n    branches: [master]\n    paths-ignore:\n      - '**/*.md'\n      - 'docs/**'\n  pull_request:\n\nj"
  },
  {
    "path": ".gitignore",
    "chars": 6175,
    "preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
  },
  {
    "path": "Build.ps1",
    "chars": 1902,
    "preview": "[CmdletBinding()]\nparam (\n    [Parameter(HelpMessage=\"The action to execute.\")]\n    [ValidateSet(\"Build\", \"Test\", \"Integ"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 18960,
    "preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## [6.0.0] - _unreleased_\n\n### Added\n"
  },
  {
    "path": "CNAME",
    "chars": 22,
    "preview": "www.falcoframework.com"
  },
  {
    "path": "Falco.sln",
    "chars": 5736,
    "preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.3190"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 5687,
    "preview": "# Falco\n\n[![NuGet Version](https://img.shields.io/nuget/v/Falco.svg)](https://www.nuget.org/packages/Falco)\n[![build](ht"
  },
  {
    "path": "docs/CNAME",
    "chars": 22,
    "preview": "www.falcoframework.com"
  },
  {
    "path": "docs/docs/authentication.html",
    "chars": 5262,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/cross-site-request-forgery.html",
    "chars": 5376,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/deployment.html",
    "chars": 5948,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/example-basic-rest-api.html",
    "chars": 14412,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/example-dependency-injection.html",
    "chars": 7920,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/example-external-view-engine.html",
    "chars": 9093,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/example-hello-world-mvc.html",
    "chars": 12882,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/example-hello-world.html",
    "chars": 4657,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/example-htmx.html",
    "chars": 8314,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/example-open-api.html",
    "chars": 8471,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/get-started.html",
    "chars": 4702,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/host-configuration.html",
    "chars": 7044,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/index.html",
    "chars": 3870,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/markup.html",
    "chars": 17019,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/migrating-from-v4-to-v5.html",
    "chars": 9159,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/request.html",
    "chars": 12696,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/response.html",
    "chars": 9723,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/docs/routing.html",
    "chars": 7626,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/index.html",
    "chars": 11307,
    "preview": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome"
  },
  {
    "path": "docs/prism.css",
    "chars": 2411,
    "preview": "code[class*=\"language-\"],pre[class*=\"language-\"]{color:#ccc;background:none;font-family:Consolas, Monaco, 'Andale Mono',"
  },
  {
    "path": "docs/prism.js",
    "chars": 24293,
    "preview": "/* PrismJS 1.22.0\nhttps://prismjs.com/download.html#themes=prism-tomorrow&languages=css+clike+csharp+fsharp+powershell+s"
  },
  {
    "path": "docs/style.css",
    "chars": 2280,
    "preview": ":root {\n  --gray: rgba(51,51,51,.6);\n  --silver: rgb(204, 204, 204);\n  --slate: rgb(51, 51, 51);\n  --merlot: rgb(59, 3, "
  },
  {
    "path": "docs/tachyons.css",
    "chars": 73849,
    "preview": "html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-"
  },
  {
    "path": "documentation/authentication.md",
    "chars": 1823,
    "preview": "# Authentication & Authorization.\n\nASP.NET Core has built-in support for authentication and authorization. Falco include"
  },
  {
    "path": "documentation/cross-site-request-forgery.md",
    "chars": 2272,
    "preview": "# Cross-site Scripting (XSS) Attacks\n\nCross-site scripting attacks are extremely common since they are quite simple to c"
  },
  {
    "path": "documentation/deployment.md",
    "chars": 2728,
    "preview": "# Deployment\n\nOne of the key features of Falco is that it contains little to no \"magic\" (i.e., no hidden reflection or d"
  },
  {
    "path": "documentation/example-basic-rest-api.md",
    "chars": 9899,
    "preview": "# Example - Basic REST API\n\nThis example demonstrates how to create a basic REST API using Falco. The API will allow use"
  },
  {
    "path": "documentation/example-dependency-injection.md",
    "chars": 4498,
    "preview": "# Example - Dependency Injection\n\nAn important and nuanced subject to discuss is dependency injection. There's a myriad "
  },
  {
    "path": "documentation/example-external-view-engine.md",
    "chars": 5322,
    "preview": "# Example - External View Engine\n\nFalco comes packaged with a [built-in view engine](markup.md). But if you'd prefer to "
  },
  {
    "path": "documentation/example-hello-world-mvc.md",
    "chars": 8883,
    "preview": "# Example - Hello World MVC\n\nLet's take our basic [Hello World](example-hello-world.md) to the next level. This means we"
  },
  {
    "path": "documentation/example-hello-world.md",
    "chars": 1528,
    "preview": "# Example - Hello World\n\nThe goal of this program is to demonstrate the absolute bare bones hello world application, so "
  },
  {
    "path": "documentation/example-htmx.md",
    "chars": 4693,
    "preview": "# Example - HTMX\n\n[Falco.Htmx](https://github.com/FalcoFramework/Falco.Htmx) brings type-safe [htmx](https://htmx.org/) "
  },
  {
    "path": "documentation/example-open-api.md",
    "chars": 4846,
    "preview": "# Example - Open API\n\nOpen API is a specification for defining APIs in a machine-readable format. It allows developers t"
  },
  {
    "path": "documentation/get-started.md",
    "chars": 1456,
    "preview": "# Getting Started\n\n## Using `dotnet new`\n\nThe easiest way to get started with Falco is by installing the `Falco.Template"
  },
  {
    "path": "documentation/host-configuration.md",
    "chars": 3752,
    "preview": "# Host Configuration\n\nAs your app becomes more complex, you'll inevitably need to reach for some additional host configu"
  },
  {
    "path": "documentation/markup.md",
    "chars": 11347,
    "preview": "# Markup\n\nFalco.Markup is broken down into three primary modules, `Elem`, `Attr` and `Text`, which are used to generate "
  },
  {
    "path": "documentation/migrating-from-v4-to-v5.md",
    "chars": 5137,
    "preview": "# Migrating from v4.x to v5.x\n\nWith Falco v5.x the main objective was to simplify the API and improve the overall devlop"
  },
  {
    "path": "documentation/migrating-from-v5-to-v6.md",
    "chars": 1848,
    "preview": "# Migrating from v5.x to v6.x\n\nThe objective of Falco v6.x is to continue to simplify the API and improve the overall de"
  },
  {
    "path": "documentation/readme.md",
    "chars": 1347,
    "preview": "# Welcome to Falco's Documentation\n\nVisit the [getting started](get-started.md) page for installation and a brief overvi"
  },
  {
    "path": "documentation/request.md",
    "chars": 8202,
    "preview": "# Request Handling\n\nFalco exposes a __uniform API__ to obtain typed values from `IFormCollection`, `IQueryCollection`, `"
  },
  {
    "path": "documentation/response.md",
    "chars": 5493,
    "preview": "# Response Writing\n\nThe `HttpHandler` type is used to represent the processing of a request. It can be thought of as the"
  },
  {
    "path": "documentation/routing.md",
    "chars": 3957,
    "preview": "# Routing\n\nRouting is responsible for matching incoming HTTP requests and dispatching those requests to the app's `HttpH"
  },
  {
    "path": "examples/BasicRestApi/BasicRestApi.fs",
    "chars": 6033,
    "preview": "namespace BasicRestApi\n\nopen System.Data\nopen Donald\n// ^-- external package that makes using databases simpler\nopen Fal"
  },
  {
    "path": "examples/BasicRestApi/BasicRestApi.fsproj",
    "chars": 451,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup"
  },
  {
    "path": "examples/BasicRestApi/appsettings.json",
    "chars": 96,
    "preview": "{\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    }\n}\n"
  },
  {
    "path": "examples/DependencyInjection/DependencyInjection.fs",
    "chars": 1072,
    "preview": "open Falco\nopen Falco.Routing\nopen Microsoft.AspNetCore.Builder\nopen Microsoft.Extensions.DependencyInjection\n\ntype IGre"
  },
  {
    "path": "examples/DependencyInjection/DependencyInjection.fsproj",
    "chars": 306,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup"
  },
  {
    "path": "examples/ExternalViewEngine/ExternalViewEngine.fs",
    "chars": 2580,
    "preview": "module Falco.Scriban.Program\n\nopen Falco\nopen Falco.Routing\nopen Microsoft.AspNetCore.Builder\nopen Microsoft.Extensions."
  },
  {
    "path": "examples/ExternalViewEngine/ExternalViewEngine.fsproj",
    "chars": 465,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGro"
  },
  {
    "path": "examples/Falco.Examples.sln",
    "chars": 9455,
    "preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.3190"
  },
  {
    "path": "examples/HelloWorld/HelloWorld.fs",
    "chars": 239,
    "preview": "open Falco\nopen Falco.Routing\nopen Microsoft.AspNetCore.Builder\n\nlet wapp = WebApplication.Create()\n\nwapp.UseRouting()\n "
  },
  {
    "path": "examples/HelloWorld/HelloWorld.fsproj",
    "chars": 297,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup"
  },
  {
    "path": "examples/HelloWorldMvc/HelloWorldMvc.fs",
    "chars": 3491,
    "preview": "namespace HelloWorldMvc\n\nopen Falco\nopen Falco.Markup\nopen Falco.Routing\nopen Microsoft.AspNetCore.Builder\n\nmodule Model"
  },
  {
    "path": "examples/HelloWorldMvc/HelloWorldMvc.fsproj",
    "chars": 298,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup"
  },
  {
    "path": "examples/HelloWorldMvc/appsettings.json",
    "chars": 96,
    "preview": "{\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    }\n}\n"
  },
  {
    "path": "examples/HelloWorldMvc/wwwroot/style.css",
    "chars": 39,
    "preview": "body { font-family: 'Comic Sans MS' }\n"
  },
  {
    "path": "examples/Htmx/Htmx.fs",
    "chars": 1459,
    "preview": "open System\nopen Falco\nopen Falco.Markup\nopen Falco.Routing\nopen Falco.Htmx\nopen Microsoft.AspNetCore.Builder\n\nmodule V"
  },
  {
    "path": "examples/Htmx/Htmx.fsproj",
    "chars": 378,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup"
  },
  {
    "path": "examples/Htmx/appsettings.json",
    "chars": 96,
    "preview": "{\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    }\n}\n"
  },
  {
    "path": "examples/OpenApi/OpenApi.fs",
    "chars": 1570,
    "preview": "open Falco\nopen Falco.OpenApi\nopen Falco.Routing\nopen Microsoft.AspNetCore.Builder\nopen Microsoft.Extensions.DependencyI"
  },
  {
    "path": "examples/OpenApi/OpenApi.fsproj",
    "chars": 456,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup"
  },
  {
    "path": "global.json",
    "chars": 124,
    "preview": "{\n    \"sdk\": {\n        \"version\": \"10.0.100\",\n        \"rollForward\": \"latestMinor\",\n        \"allowPrerelease\": false\n   "
  },
  {
    "path": "site/Site.fs",
    "chars": 15729,
    "preview": "open System\nopen System.IO\nopen System.Text.RegularExpressions\nopen Falco.Markup\nopen Markdig\nopen Markdig.Syntax.Inline"
  },
  {
    "path": "site/Site.fsproj",
    "chars": 378,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net10.0</Tar"
  },
  {
    "path": "src/Falco/Core.fs",
    "chars": 980,
    "preview": "namespace Falco\n\nopen System\nopen System.Threading.Tasks\nopen Microsoft.AspNetCore.Http\n\n/// The eventual return of asyn"
  },
  {
    "path": "src/Falco/Falco.fsproj",
    "chars": 2675,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <AssemblyName>Falco</AssemblyName>\n    <Version>6.0.0-alpha1</Ve"
  },
  {
    "path": "src/Falco/Multipart.fs",
    "chars": 6971,
    "preview": "namespace Falco\n\nopen System\nopen System.IO\nopen System.Net\nopen System.Threading\nopen System.Threading.Tasks\nopen Micro"
  },
  {
    "path": "src/Falco/Request.fs",
    "chars": 19953,
    "preview": "[<RequireQualifiedAccess>]\nmodule Falco.Request\n\nopen System\nopen System.IO\nopen System.Security.Claims\nopen System.Text"
  },
  {
    "path": "src/Falco/RequestData.fs",
    "chars": 14885,
    "preview": "namespace Falco\n\nopen System\nopen System.Collections.Generic\nopen Microsoft.AspNetCore.Http\nopen Microsoft.FSharp.Core.O"
  },
  {
    "path": "src/Falco/RequestValue.fs",
    "chars": 13597,
    "preview": "namespace Falco\n\nopen System\nopen System.Collections.Generic\nopen System.Net\nopen System.Text.RegularExpressions\nopen Mi"
  },
  {
    "path": "src/Falco/Response.fs",
    "chars": 15385,
    "preview": "[<RequireQualifiedAccess>]\nmodule Falco.Response\n\nopen System\nopen System.IO\nopen System.Security.Claims\nopen System.Tex"
  },
  {
    "path": "src/Falco/Routing.fs",
    "chars": 13533,
    "preview": "namespace Falco\n\nopen System\nopen System.Collections.Generic\nopen Microsoft.AspNetCore.Builder\nopen Microsoft.AspNetCor"
  },
  {
    "path": "src/Falco/Security.fs",
    "chars": 2030,
    "preview": "module Falco.Security\n\nmodule Xsrf =\n    open System\n    open System.Threading.Tasks\n    open Falco.Markup\n    open Micr"
  },
  {
    "path": "src/Falco/String.fs",
    "chars": 3303,
    "preview": "namespace Falco\n\nopen System\nopen System.Collections.Generic\nopen System.Globalization\n\nmodule internal StringUtils =\n  "
  },
  {
    "path": "src/Falco/WebApplication.fs",
    "chars": 6365,
    "preview": "namespace Falco\n\n[<AutoOpen>]\nmodule Extensions =\n    open Microsoft.AspNetCore.Builder\n    open Microsoft.AspNetCore.Ht"
  },
  {
    "path": "test/Falco.IntegrationTests/Falco.IntegrationTests.fsproj",
    "chars": 1256,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <IsPackable>f"
  },
  {
    "path": "test/Falco.IntegrationTests/Program.fs",
    "chars": 6953,
    "preview": "namespace Falco.IntegrationTests\n\nopen System.Net.Http\nopen System.Text\nopen System.Text.Json\nopen Microsoft.AspNetCore."
  },
  {
    "path": "test/Falco.IntegrationTests.App/Falco.IntegrationTests.App.fsproj",
    "chars": 483,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup"
  },
  {
    "path": "test/Falco.IntegrationTests.App/Program.fs",
    "chars": 2271,
    "preview": "module Falco.IntegrationTests.App\n\nopen Falco\nopen Falco.Markup\nopen Falco.Routing\nopen Microsoft.AspNetCore.Builder\nope"
  },
  {
    "path": "test/Falco.Tests/Common.fs",
    "chars": 4780,
    "preview": "[<AutoOpen>]\nmodule Falco.Tests.Common\n\n#nowarn \"44\"\n\nopen System\nopen System.IO\nopen System.IO.Pipelines\nopen System.S"
  },
  {
    "path": "test/Falco.Tests/Falco.Tests.fsproj",
    "chars": 1565,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <IsPackable>false"
  },
  {
    "path": "test/Falco.Tests/MultipartTests.fs",
    "chars": 10115,
    "preview": "module Falco.Tests.Multipart\n\nopen System\nopen System.IO\nopen System.Text\nopen System.Threading\nopen System.Threading.Ta"
  },
  {
    "path": "test/Falco.Tests/Program.fs",
    "chars": 47,
    "preview": "module Program = let [<EntryPoint>] main _ = 0\n"
  },
  {
    "path": "test/Falco.Tests/RequestDataTests.fs",
    "chars": 17500,
    "preview": "module Falco.Tests.RequestData\n\nopen System\nopen System.Globalization\nopen System.IO\nopen System.Threading\nopen System.T"
  },
  {
    "path": "test/Falco.Tests/RequestTests.fs",
    "chars": 15476,
    "preview": "module Falco.Tests.Request\n\nopen System\nopen System.Collections.Generic\nopen System.IO\nopen System.Text\nopen System.Tex"
  },
  {
    "path": "test/Falco.Tests/RequestValueTests.fs",
    "chars": 9341,
    "preview": "module Falco.Tests.RequestValue\n\nopen Falco\nopen FsUnit.Xunit\nopen Xunit\n\n[<Fact>]\nlet ``RequestValue should parse empty"
  },
  {
    "path": "test/Falco.Tests/ResponseTests.fs",
    "chars": 22469,
    "preview": "module Falco.Tests.Response\n\nopen System.Security.Claims\nopen System.Text\nopen System.Text.Json\nopen System.Text.Json.S"
  },
  {
    "path": "test/Falco.Tests/RoutingTests.fs",
    "chars": 11586,
    "preview": "module Falco.Tests.Routing\n\nopen Xunit\nopen Falco\nopen Falco.Routing\nopen FsUnit.Xunit\nopen Microsoft.AspNetCore.Builde"
  },
  {
    "path": "test/Falco.Tests/SecurityTests.fs",
    "chars": 684,
    "preview": "module Falco.Tests.SecurityTests\n\nopen FsUnit.Xunit\nopen Xunit\nopen Falco.Security\nopen Falco.Markup\nopen Microsoft.Asp"
  },
  {
    "path": "test/Falco.Tests/StringTests.fs",
    "chars": 10940,
    "preview": "namespace Falco.Tests.String\n\nopen System\nopen System.Collections.Generic\nopen System.IO\nopen System.Text\nopen System.Te"
  },
  {
    "path": "test/Falco.Tests/WebApplicationTests.fs",
    "chars": 11355,
    "preview": "module Falco.Tests.WebApplication\n\nopen System\nopen System.Collections.Generic\nopen Xunit\nopen FsUnit.Xunit\nopen Microso"
  }
]

About this extraction

This page contains the full source code of the pimbrouwers/Falco GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 101 files (663.8 KB), approximately 184.1k tokens, and a symbol index with 12 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!