Header menu logo Falco.UnionRoutes

Route Module

Type-safe routing with discriminated unions.

The Route module provides functions for:

  • Generating Falco endpoints from route unions
  • Creating type-safe links from route values
  • Hydrating routes with values from HTTP context
  • Validating route structure and preconditions

Example

 type PostRoute =
     | List
     | Show of id: Guid
     | Create of PreCondition<UserId>

 let config: EndpointConfig<AppError> = {
     Preconditions = [ yield! Extractor.precondition<UserId, _> authExtractor ]
     Parsers = []
     MakeError = fun msg -> BadRequest msg
     CombineErrors = List.head
     ToErrorResponse = fun e -> Response.ofPlainText (string e)
 }

 let endpoints = Route.endpoints config handleRoute
type PostRoute = | List | Show of id: obj | Create of obj
Multiple items
module List from Microsoft.FSharp.Collections

--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T with get member IsEmpty: bool with get member Item: index: int -> 'T with get ...
val id: x: 'T -> 'T
val config: 'a
Multiple items
union case PostRoute.List: PostRoute

--------------------
module List from Microsoft.FSharp.Collections

--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T with get member IsEmpty: bool with get member Item: index: int -> 'T with get ...
val head: list: 'T list -> 'T
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
val endpoints: obj

Types

Type Description

RouteInfo

Full route metadata extracted via reflection.

Functions and values

Function or value Description

Route.allRoutes ()

Full Usage: Route.allRoutes ()

Parameters:
    () : unit

Returns: 'TRoute list A list of all possible route values, with parameterized routes using default values.

Enumerates all route cases for a route union type.

() : unit
Returns: 'TRoute list

A list of all possible route values, with parameterized routes using default values.

Example

 let allRoutes = Route.allRoutes<Route>()
 for route in allRoutes do
     let info = Route.info route
     printfn "%A %s" info.Method info.Path
val allRoutes: obj seq
val route: obj
val info: obj
val printfn: format: Printf.TextWriterFormat<'T> -> 'T

Route.endpoints config routeHandler

Full Usage: Route.endpoints config routeHandler

Parameters:
    config : EndpointConfig<'E> - Configuration for extraction (preconditions, parsers, error handling).
    routeHandler : 'TRoute -> HttpHandler - A function that takes a hydrated route value and returns an HTTP handler.

Returns: HttpEndpoint list A list of Falco HttpEndpoint values ready for use with app.UseFalco.

Generates Falco endpoints with automatic route extraction.

This is the main entry point for Falco.UnionRoutes. It:

  • Validates route structure at startup
  • Extracts route/query parameters automatically
  • Runs precondition extractors (auth, validation)
  • Hydrates nested routes recursively

config : EndpointConfig<'E>

Configuration for extraction (preconditions, parsers, error handling).

routeHandler : 'TRoute -> HttpHandler

A function that takes a hydrated route value and returns an HTTP handler.

Returns: HttpEndpoint list

A list of Falco HttpEndpoint values ready for use with app.UseFalco.

Example

 let config: EndpointConfig<AppError> = {
     Preconditions = [ yield! Extractor.precondition<UserId, _> requireAuth ]
     Parsers = []
     MakeError = fun msg -> BadRequest msg
     CombineErrors = fun errors -> errors |> List.head
     ToErrorResponse = fun e -> Response.withStatusCode 400 >> Response.ofPlainText (string e)
 }

 let handleRoute route =
     match route with
     | Home -> Response.ofPlainText "home"
     | Posts p -> handlePost p

 let endpoints = Route.endpoints config handleRoute
 app.UseFalco(endpoints) |> ignore
val config: 'a
Multiple items
module List from Microsoft.FSharp.Collections

--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T with get member IsEmpty: bool with get member Item: index: int -> 'T with get ...
val head: list: 'T list -> 'T
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
val handleRoute: route: 'a -> 'b
val route: 'a
val Home: 'a
val p: 'a
val endpoints: obj
val ignore: value: 'T -> unit

Route.info route

Full Usage: Route.info route

Parameters:
    route : 'T - The route value to inspect.

Returns: RouteInfo A RouteInfo with method and path.

Gets full route metadata for a route value using reflection.

route : 'T

The route value to inspect.

Returns: RouteInfo

A RouteInfo with method and path.

Example

 let routeInfo = Route.info (Posts (Detail (PostId Guid.Empty)))
 // routeInfo.Method = HttpMethod.Get
 // routeInfo.Path = "/posts/{id}"
val routeInfo: obj

Route.link route

Full Usage: Route.link route

Parameters:
    route : 'T - The route value with actual parameter values.

Returns: string A URL path with parameters substituted.

Generates a concrete URL path from a route value by substituting actual field values.

route : 'T

The route value with actual parameter values.

Returns: string

A URL path with parameters substituted.

Example

 let postId = PostId (Guid.Parse "abc-123")
 let url = Route.link (Posts (Detail postId))
 // returns "/posts/abc-123"
val postId: obj
val url: obj

Route.respond _returns value

Full Usage: Route.respond _returns value

Parameters:
    _returns : Returns<'T> - The Returns<'T> phantom value from the route match — binds the response type.
    value : 'T - The value to serialize as JSON.

Returns: HttpHandler An HTTP handler that writes the JSON response.
Modifiers: inline
Type parameters: 'T

Sends a JSON response with the type guaranteed by Returns<'T>.

_returns : Returns<'T>

The Returns<'T> phantom value from the route match — binds the response type.

value : 'T

The value to serialize as JSON.

Returns: HttpHandler

An HTTP handler that writes the JSON response.

Example

 let handle route : HttpHandler =
     match route with
     | List returns -> Route.respond returns (Fortune.all ())
     | Show (id, returns) -> Route.respond returns (Fortune.find id)
val handle: route: 'a -> 'b
val route: 'a
Multiple items
module List from Microsoft.FSharp.Collections

--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T with get member IsEmpty: bool with get member Item: index: int -> 'T with get ...
val returns: obj
val id: obj

Route.validate preconditions

Full Usage: Route.validate preconditions

Parameters:
Returns: Result<unit, string list> Ok () if valid, Error with list of all issues if invalid.

Full validation: route structure + precondition coverage.

preconditions : PreconditionExtractor<'E> list

The list of registered precondition extractors.

Returns: Result<unit, string list>

Ok () if valid, Error with list of all issues if invalid.

Example

 [<Fact>]
 let ``all routes are valid`` () =
     let preconditions = [ yield! Extractor.precondition authExtractor ]
     let result = Route.validate<Route, AppError> preconditions
     Assert.Equal(Ok (), result)
val preconditions: obj list
val result: obj
union case Result.Ok: ResultValue: 'T -> Result<'T,'TError>

Route.validatePreconditions preconditions

Full Usage: Route.validatePreconditions preconditions

Parameters:
Returns: Result<unit, string list> Ok () if all types are covered, Error with list of missing types if invalid.

Validates that all PreCondition<T> and OverridablePreCondition<T> fields have registered extractors.

preconditions : PreconditionExtractor<'E> list

The list of registered precondition extractors.

Returns: Result<unit, string list>

Ok () if all types are covered, Error with list of missing types if invalid.

Example

 let preconditions = [ yield! Extractor.precondition authExtractor; yield! Extractor.precondition adminExtractor ]
 match Route.validatePreconditions<Route, AppError> preconditions with
 | Ok () -> ()
 | Error errors -> failwith (String.concat "\n" errors)
val preconditions: obj list
union case Result.Ok: ResultValue: 'T -> Result<'T,'TError>
union case Result.Error: ErrorValue: 'TError -> Result<'T,'TError>
val errors: string seq
val failwith: message: string -> 'T
module String from Microsoft.FSharp.Core
val concat: sep: string -> strings: string seq -> string

Route.validateStructure ()

Full Usage: Route.validateStructure ()

Parameters:
    () : unit

Returns: Result<unit, string list> Ok () if valid, Error with list of issues if invalid.

Validates route structure including paths and field-to-parameter consistency.

() : unit
Returns: Result<unit, string list>

Ok () if valid, Error with list of issues if invalid.

Example

 match Route.validateStructure<Route>() with
 | Ok () -> printfn "Routes are valid"
 | Error errors -> errors |> List.iter (printfn "Error: %s")
union case Result.Ok: ResultValue: 'T -> Result<'T,'TError>
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
union case Result.Error: ErrorValue: 'TError -> Result<'T,'TError>
val errors: string list
Multiple items
module List from Microsoft.FSharp.Collections

--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T with get member IsEmpty: bool with get member Item: index: int -> 'T with get ...
val iter: action: ('T -> unit) -> list: 'T list -> unit

Type something to start searching.