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

MatchError

Error details when a URL fails to match any route.

RouteInfo

Full route metadata extracted via reflection.

RouteMatcher<'TRoute>

A pre-compiled URL matcher that efficiently matches URL strings against route patterns. Create one with Route.createMatcher and reuse it for multiple matches.

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.createMatcher ()

Full Usage: Route.createMatcher ()

Parameters:
    () : unit

Returns: RouteMatcher<'TRoute> A RouteMatcher that can match URLs to route values.

Create a pre-compiled URL matcher for a route type. The matcher enumerates all route cases and their patterns once, then matches URLs efficiently.

() : unit
Returns: RouteMatcher<'TRoute>

A RouteMatcher that can match URLs to route values.

Example

 let matcher = Route.createMatcher<MyRoute>()
 match matcher.Match(HttpMethod.Get, "/posts/550e8400-e29b-41d4-a716-446655440000") with
 | Ok route -> printfn "Matched: %A" route
 | Error Route.NoMatchingRoute -> printfn "No match"
 | Error (Route.ParameterError(path, name, value, expected)) ->
     printfn "Parameter '%s' value '%s' is not a valid %s (route: %s)" name value expected path
val matcher: obj
union case Result.Ok: ResultValue: 'T -> Result<'T,'TError>
val route: obj
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
union case Result.Error: ErrorValue: 'TError -> Result<'T,'TError>

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.matchUrl method url

Full Usage: Route.matchUrl method url

Parameters:
    method : HttpMethod - The HTTP method.
    url : string - The URL path to match.

Returns: Result<'TRoute, MatchError> Ok with the matched route value, or Error with match failure details.

Match a URL against all route patterns for a route type. This creates a new matcher on each call. For matching many URLs, prefer Route.createMatcher which pre-compiles patterns and can be reused.

method : HttpMethod

The HTTP method.

url : string

The URL path to match.

Returns: Result<'TRoute, MatchError>

Ok with the matched route value, or Error with match failure details.

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.