Freya

Home

Freya is a functional web programming stack for F#. Freya emphasises expressivity, safety, and correctness and is compatible with most server technologies in the .NET space.

Getting Started

The quickest way to get up and running with Freya and to get a feeling for what programming with Freya is like, is to dive straight in to the Getting Started tutorial. From zero to a Freya-based Hello World in a few minutes! Once you’re ready to move on, you can move on to the more in-depth documentation, as described below...

Hint

The Getting Started tutorial is the perfect way to take your first steps with Freya.

Sections

The documentation for Freya is organized in to sections to help you find what you’re looking for more easily:

  • Topics – contains guides specific to certain topics and may cover background information, explanations of design choices and approaches, and may cover multiple parts of Freya when they can be used in concert.
  • Tutorials – contains longer form guides, usually covering a complete process of building some web application, and which are likely to cover various elements of Freya along the way.
  • Recipes – contains guides to accomplishing specific tasks with Freya. They may range from the very simple to advanced use-cases, and may span the whole range of the Freya stack.
  • Reference – contains guides to specific libraries and components of Freya, giving a technical view of what is available from each component and how they may be used.

Meta

For more “meta” topics around the Freya project and community (such as contact information, guidance on contributing, etc.) see the following sections:

Community

The F# community is a friendly place and we hope for the same for Freya. We encourage everyone to come and talk in our Gitter channel where all are welcome. It’s a great place to ask questions!

For keeping up to date with news on Freya and the ecosystem around it, follow Freya on Twitter – any news, changes, announcements, releases, etc. will be posted there, along with new blog posts, etc.

Most of all, we encourage you all to get involved, try Freya out, and tell us what you think!

Contact

There are several ways to get in touch!

Help/Advice

Probably the quickest way to ask a question and chat it through is to ask on the Freya Gitter channel – while it’s not always going to be answered immediately, people are often available, and responses don’t usually take too long! If you’re on the FSSF Slack channels, some of the maintainers are also often available there.

Issues/Features

If you want to raise an issue relating to Freya, or suggest a new feature – or an improvement to an existing one – then the main Freya repository on GitHub should be your first stop.

Issues, feature requests, etc. for Freya are tracked and managed using the GitHub Issues process. While Freya is split in to multiple repositories, issues raised against the main repository can be moved as needed, and it is often easier to work out where they should live later!

Miscellaneous

If you just want to send an email to a human being, then that’s possible too. Email freya@xyncro.com for an open-ended channel.

Contributing

Contributions to Freya in any form are very welcome. Whether you just want to correct some grammar in the documentation (!) or you’d like to contribute a new feature, you’re involvement will be appreciated and respected. If you’re not sure how you’d like to be involved, but feel that you would in some way – get in Contact. Regardless of experience, skill level or time available, there’s probably something for you!

Hint

If you’re not comfortable with GitHub – or Git in general – or you’re not familiar with any of the processes mentioned below, don’t worry. If you contact a maintainer by Email or on Twitter, they’ll help you through anything that you need – everybody needs a helping hand sometimes and nobody knows everything!

Documentation

If you’d like to contribute to the documentation, the quickest way is to use the “Edit Page” link at the bottom of any page – that’ll allow you to edit any content and send a pull request easily via GitHub.

Although it’s very likely that your help will be accepted without any issue, if you’re planning on making major changes to the structure or content of Freya documentation it’s probably worth discussing it first. Please get in Contact and talk before expending major effort!

Code

As with documentation, the quickest way to contribute is to create a fork on GitHub and submit a pull request. You are also welcome to log issues if you’d like to suggest features, report bugs, or make sure anything else relevant gets noted.

As with documentation, if you’re planning on putting significant effort in to a feature or change, please get in Contact first, to make sure that it’s likely to be accepted in to Freya – and to make sure it’s not already being worked on!

Policies

Freya does not have a large set of policies, but some aspects of the project do require explicit affirmation of expectations. Please read the following on conduct!

Conduct

While Freya does not currently have an explicit code of conduct, any behaviour which prevents others from finding Freya and the Freya community a welcoming and friendly environment will not be tolerated. If you are unsure whether something is likely to be offensive or upsetting to others, that is usually a good indication that you probably shouldn’t do it.

Were Freya to adopt a formal code of conduct, it would probably look rather like the Rust Code of Conduct – please refer to that document for the kinds of behaviour expected of people taking part in the Freya community.

Open source software matters, but it matters less than people.

Topics

Topic guides are available covering various aspects of building with Freya. These guides deal broadly with usage, background information, history, design decisions, etc. The topic categories are available directly from the top level navigation.

Design

The design of some aspects of Freya merits particular discussion – understanding the approaches taken can help get the most out of the available components of the Freya stack.

In particular, the following sections are key to some elements of the Freya stack:

  • Machines – the design of Freya Machines merits in-depth explanation – it is a powerful and extensible approach to web programming.

Hopac

The “default” implementation of Freya uses F# async functions for most operations, and the internals are built as async. However, there is an alternative implementation available using the Hopac concurrent programming library available.

The Hopac version of Freya is effectively identical in functionality and usage, but uses a different underlying concurrency model – see Functions. This can make Freya easier to integrate with existing code where Hopac is in use, and also potentially gives some performance/resource usage gains (the Freya Benchmarks project is beginning to measure these reliably).

Packages

Packages which use the Hopac concurrency model are suffixed with .Hopac. If you are using the Freya meta-package for example, rather than taking a dependency on Freya, you would take a dependency on Freya.Hopac. This convention applies to all packages available in both variants.

Note

Not all packages are dependent on a concurrency abstraction, so not all packages come in both “default” and Hopac variants. Packages which do cannot be mixed and matched – attempting to use one package built for async and one built for Hopac together will result in errors!

Reference

For reference and more information on Hopac:

  • Hopac – the Hopac concurrency library for F#, based on ConcurrentML.
  • Hopac Documentation – reference documentation on Hopac.

Machines

Freya Machines are a powerful tool, but the programming model can be new to many, especially given the prevalence of web frameworks (particularly MVC-style frameworks) where the logic is spread throughout the whole framework. Machines can therefore look daunting at first, but they actually represent a conceptually simpler and more straightforward approach.

The sub-sections give an explanation of Machine design and implementation in Freya, using an HTTP Machine as a convenient example where relevant.

The machine Overview is the ideal place to begin to understand the underlying model of machines.

Overview
Introduction

Machines as implemented in Freya (internally using the Hephaestus library) are ways to program based on decisions.

Many problems (particularly problems like how to respond to an HTTP request) can be modelled in this way – as a series of decisions (boolean – true/false – decisions) to be made on the way to eventually arriving at a result. You can imagine the process of responding to an HTTP request as a series of suitable decisions – for example:

Is the server in a state to respond?
    true: continue
    false: return "503 Service Unavailable"

Is the version of HTTP being requested supported?
    true: continue
    false: return "505 HTTP Version Not Supported"

etc. until a suitable response is determined and returned.

As you can see, this is effectively a tree of decisions – a binary tree. The machine model requires that the logic that needs to be expressed is encoded in this form – as a tree of decisions, where the leaves represent the action that should result upon reaching the leaf.

In the case of an HTTP machine, handling an HTTP request, the endpoints would represent response handlers to be invoked, sending the chosen HTTP response back to the client.

Exemplar

The HTTP problem will continue to be used in the machine design topic as the common example case. This provides concrete examples, as well as tying the topic directly to the implementation of one of the most powerful parts of the Freya stack, a full-featured HTTP machine implementation.

The next section will cover Decisions in more detail, and begin to introduce some of the approaches taken to machines in the implementation.

Decisions

In the Overview of machine design, the concept of a tree of decisions was introduced as being the core of the machine computational model. In the implementation – Hephasestus – used by Freya, that is implemented in a very specific way.

Configuration

When defining a machine, Hephaestus does not expect to be given a ready-made decision, it expects to receive a function which will return a decision. This function takes an instance of a configuration type and returns a decision, enabling for runtime configuration of each decision. In Hephaestus terms, the decision tree initially is a prototype, and will only become a tree of actual decisions once it has been configured with appropriate data.

In effect, a decision is effectively defined as the following type (this is a simplification):

type Decision<'configuration> =
    'configuration -> DecisionValue

It may not be immediately obvious why this is useful, but it begins to become clearer when a decision value is explored.

Values

The act of configuring a decision, resulting in a decision value, allows for some significant optimisations to be made if a decision value is defined in a certain way.

Returning to the example of handling an HTTP request, consider a case with the following decision:

Is the URI too long?
    true: return "414 URI Too Long"
    false: continue

If the implementation of that decision is to compare the length of the request URI against a maximum length given in the configuration, it’s possible that the result of the decision is already known. For example, if the maximum allowed length of a URI configured was “infinite” then the result of the decision will always be false. If the maximum allowed length was zero, then the result will always be true!

This applies widely – many decisions are based on information provided as part of configuration, and a significant subset can be known ahead of running the machine.

For this reason, a decision value is effectively defined as the following type: (again, a simplification):

type DecisionValue =
    | Function of // ...function returning bool
    | Literal of bool

In this way, after configuration the decision tree is a tree of decision values, where the decision value is either a function to be evaluated at runtime to give a result, or a known result. This property will be extremely useful later in Optimisation.

State

In the Overview, you saw the example decision:

Is the version of HTTP being requested supported?
    true: continue
    false: return "505 HTTP Version Not Supported"

It’s clear that to implement that decision, the decision will need access to the request. This is accomplished in machines by passing the state to a machine to run it. So in the HTTP example, the request state might be passed to the first decision, so that it can return a result.

In fact, in Hephaestus, the decision actually returns a result – and a new state, which will be passed to the next decision. This allows decisions to both read relevant data, and potentially change the state for the following decisions. This is not commonly used, but can allow for more complex logic to be expressed.

This gives a slighly more realistic definition for the decision value type (again, simplified):

type DecisionValue<'state> =
    | Function of ('state -> bool * 'state)
    | Literal of bool

In this way, it is also possible to more accurately define the original decision type:

type Decision<'configuration,'state> =
    'configuration -> DecisionValue<'state>

This is now close enough to the actual implementation to understand the basic machine decision model, and the fundamental approach to configuring decisions.

In the next section on Terminals, the computational model will take shape further.

Terminals

In the Overview section, the machine model was described as being a tree of decisions, where the leaves represented the action that should result when reaching the appropriate leaf. In the Hephaestus implementation, the leaves are referred to as terminals, although different names may be used when taling about specific machines – in the HTTP example (and the Freya HTTP machine) they are referred to as handlers, in line with the traditional term “response handler”.

As with decisions, there is slightly more to them than just a simple function.

Configuration

In Decisions, the configuration process of decisions – from an unconfigured decision to a decision value once supplied with configuration data – was outlined. Terminals go through a similar process, being configured with the same configuration value before being “ready”.

As with decisions, they can be thought of as a simple type (simplified):

type Terminal<'configuration> =
    'configuration -> TerminalValue

In the case of terminals, the logic is somewhat simpler than with decisions in one sense – the terminal is only meaningful when run, so there is no consideration of a terminal being known ahead of time.

State

Also as with decisions, terminals need to act upon the input data, the state, to produce the result required. There is no need for them to produce a boolean result to determine what action to take next however – they are by definition the last part of a machine computation.

The terminal value can be seen then approximately as being (again, simplified):

type TerminalValue<'state> =
    | Terminal of 'state -> 'state

As you can see, the state is returned so that machines may fit in to broader computations, be composed, etc.

Results

There is one addition – the result of a machine computation. Although the computation as described may have modified (or returned a new instance) of the state provided, it currently has no responsibility to return a value. This is the responsibility of the terminal, and leads to this definition, expanded to encompass a result type (as ever, simplified):

type TerminalValue<'result,'state> =
    | Terminal of 'state -> 'result * 'state

This now allows for a more complete definition of the terminal type also:

type Terminal<'configuration,'result,'state> =
    'configuration -> TerminalValue<'result,'state>

This is again close enough to the meaning of the actual implementation to see the shape of a machine computation – and to note that it can be parameterized by the types of the configuration data, the result, and the state passed through the computation.

This gives a very flexible model, and in the following sections on Optimisation and Application within Freya, you will see how this model allows for an efficient execution approach, and the concrete implementation of the machine model in Freya.

Optimisation

In the Overview the basic premise of machine computation was introduced, followed by the definition of Decisions in the next section. One of the goals of the machine computation model, as expressed in Hephaestus, is to make the eventual runtime computation as efficient as possible.

In the section on decisions, the definition of a decision was declared to be approximately as follows:

type DecisionValue<'state> =
    | Function of ('state -> bool * 'state)
    | Literal of bool

This definition leads to the possibility of significant optimisation of the resulting decision tree structure.

Reachability

The simple but effective approach taken is based on the premise that where a decision is a literal, it is already possible to tell which subsequent branch of the tree is reachable, and which is not. Wherever a decision is a literal, it is possible to prune the decision tree, effectively removing the decision entirely, and creating a new tree where the execution path will go directly to the appropriate sub-tree.

Hephaestus trees are not defined to be pure trees (branches can join, so two paths can lead to the same decision). This requires a slightly more complex algorithm to safely prune the tree structure, but once it is pruned the tree becomes a tree where all remaining decisions are functions and not literals.

This can have significant impact on performance and complexity of the eventual decision tree. The Freya HTTP machine in the default pre-configured, pre-optimisation stage, has several hundred decisions, forming a large and complex tree. If given minimal configuration (which will result in many of these decisions assuming default, literal values) this number goes down to around five decisions in total!

As configuration becomes more complex, this number begins to rise, but the resulting tree is always significantly simpler than the potential maximal tree.

Implications

The implications of optimising the decision tree in this way on program design are worth noting.

First, in the overall design of the tree, wholesale duplication of logic can be permitted, as any unneeded logical paths will be removed before runtime use by the configuration and optimisation process.

Second, the expectation of what will be run becomes less important – as sections of logic may be optimised away, the expectation shifts to only running what is relevant, leading to thinking more declaratively about the overall logic. Interactions between logical elements are reduced in importance, and the importance of simple logical decisions comes to the fore, emphasising the decision based nature of the machine approach further.

The next section on Application gives some detail on the adoption of the machine model within Freya.

Application

In the previous sections on the design of Machines the principles and implementation of the general machine model were set out, as implemented in the Hephaestus machine library used by Freya. This was set out in general terms, but Freya implements a concrete machine in the form of the Freya HTTP machine.

Given the specific nature of HTTP, some of the terminology is specialised to that area (for example, terminals in the HTTP machine are referred to as handlers). The HTTP machine is also modular, with certain additions to the core HTTP standard being developed as extensions to the core machine (for example, CORS support).

Details on the Freya HTTP machine can be found in the reference section on Machines, specifically in the HTTP section, with full coverage of the machine, the configuration approach, and available extensions.

Optics

Optics (often – and in earlier versions of Freya – referred to as lenses) are a functional technique to enable you to work with complex data structures more easily. As data structures are generally immutable, modifying a data structure (or returning a new instance with the changes reflected) can be quite onerous if the data structure is large and complex, and the area you wish to change is deep within the data structure.

Optics, as their name implies, enable you to focus on a particular part of a data structure, treating it as if it were a normal top level instance of some data. You can think of doing your work through a lens (an optic), which will handle the mechanics (or optics, rather) of data structure modification for you.

Aether

Freya uses the Aether optics library. The guides to optics found there give a good introduction to the principles, along with more general information about the library itself (which is used extensively in Freya).

  • Aether Guides – guides to the principles and usage of optics, with examples and explanation.
  • Aether – the main Aether website.
Freya

Optics are a key part of Freya usage, used to work with data throughout many elements of the Freya stack. They are discussed in the reference documentation, as well as being used throughout any tutorial or recipe documentation.

  • Optics – reference for optic usage in the Freya.Core library.

Standards

Freya is an intentionally standards based stack, whether that is broad public standards (like RFCs for HTTP, etc.) or community based, like OWIN. More on standards and how Freya works with them can be found in the following sections:

OWIN

OWIN (Open Web Interface for .NET - see owin.org) is a simple, community driven, standard interface between web servers and web applications. With a simple abstraction in place, people can concentrate on writing servers or applications, confident that they will run happily with a server/application that also supports the OWIN standard.

Interface

The OWIN standard interface is not a particularly complex one, as it’s designed to be a fairly “lowest common denominator” approach, with the aim of being applicable to the broadest possible ecosystem (so no relying on .NET features only accessible from specific languages, minority versions or frameworks, etc.)

The standard, in basic form, looks like this (straying in to C# for a moment):

using AppFunc = Func<IDictionary<string, object>, Task>;

In effect it’s simply saying “I’m going to give you a dictionary containing request and response data. You muck about with that, and return me a Task when you’re done with it.” The server is then responsible for taking the eventual dictionary (called the Environment) and making sure that it gets turned in to a valid HTTP response, and sent back to the client.

Data

The obvious question now is “Where’s the request and response data?” Well, it’s in the Environment, boxed up with string keys. Some of the values are boxed strings, some boxed dictionaries, some boxed streams... It isn’t elegant, but it is workable, and making it this low level is one of the only ways to give an interface that multiple languages can actually work with.

As an example, the key owin.RequestPath in the Environment will get (or set, as it’s just a dumb dictionary) the path of the request. The key owin.ResponseBody is the stream used to write the response body, and so on.

As you’ll note – if you’ve got an F# hat on (our merchandise store is coming, we assure you) – this is all based on mutation of the Environment. That’s not a lovely thing to see in F#, and Freya does quite a lot of work to tidy this up (or at least hide it where you can pretend it doesn’t happen). You can see more about how it does so in the Core Reference section – see Core.

Servers

As you can see from the simplicity of the interface (known as the AppFunc or OwinAppFunc), there’s not much that a library needs to be able to do to work with a compatible OWIN server. Different OWIN servers, however, have different ways of asking for that AppFunc, so you may need to peruse the documentation for your specific server.

In the examples and tutorials we’ll see later, we’ll often use the Katana server, and we’ll show how simple it is to host Freya using that. If you’re using something else, it may be documented – see Servers. If not, feel free to either ask for guidance or even submit documentation – see Contributing!

Polyfills

The OWIN standard is a good base point for developing interoperable servers and frameworks, but like any standard it requires iteration and development. Sometimes it lacks features which Freya requires to work as well as possible – and in those cases Freya provides polyfills for particular server implementations which will “extend” the OWIN standard with additional features which Freya code can then test for and use where present.

This enables Freya to drive forward and improve at a fast pace.

For documentation on the polyfills currently available for Freya see the library reference.

  • Polyfills – available polyfills for Freya, providing extensions to standards such as OWIN.

Versioning

Freya follows a semantic versioning approach to versioning, with some key points, due to the multi-library nature of the Freya stack.

The overall version of Freya (and the version used to define versions of documentation, etc.) is the version of the Freya meta-package – the package which has dependencies that make up a default Freya stack. The version of this meta-package may be increased driven by changes to the dependency set.

In effect, this means that a breaking change to a dependency will likely require a major version increase of that dependency. The next release of the Freya meta-package which includes the breaking change version will therefore also likely receive a major version increment.

In this way the version of the Freya meta-package signifies the version of a Freya stack which is known and designed to work well, and it may be many versions ahead of some of the versions of the packages that it depends upon – especially when some of the core packages are very stable.

As from Freya 3.0 (including release candidate builds) the versioning of Freya packages will be less significant from a “feature announcement” perspective, but will become a simple semantic versioning tool.

Upgrading

Upgrading to newer versions of Freya may still result in breaking changes (major version changes will signify this possibility). Guidance for working through these changes can be found in the following section:

  • Upgrading – overview and version specific guidance on managing change in Freya versions.
Upgrading

Like any software project, Freya evolves over time. While backwards compatibility is maintained when possible (usually with a deprecation warning to help you to update code to newer constructs), sometimes changing scope or direction requires more significant change.

Guidance for working through specific changes is given in the following sections (this list is likely to expand over time):

2.x → 3.x

This page covers the broad scope of change from 2.x releases of the Freya stack to 3.x releases – including release candidate (RC) builds.

Packages

If you are using the Freya meta-package to manage your dependency on Freya, the new packages should be installed correctly on update, especially if you’re using Paket.

Hint

In general, Paket comes highly recommended as a reliable way of managing your Nuget – and other – dependencies. For this guide however, standard Nuget tools will work well enough.

Libraries
Arachne

In versions prior to 3.x, Freya used the Arachne family of libraries as a type system for the web. As of 3.0, the Arachne libraries have been brought under the Freya stack umbrella and renamed the Freya Types libraries. This requires a change to existing code, with Arachne.* being replaced by Freya.Types.* – for example open Arachne.Http should now be open Freya.Types.Http.

Core

Various changes to functions have taken place within the Freya Core library, all of which come with backward compatible functions with deprecation warnings. The deprecation messages give suggestions for the function to replace the obsolete function with. Most of these function changes have been about simpliying the optic-based programming model, and separating Pipeline functionality from basic Freya functionality.

Optics

The previously provided optics in the Freya Lenses libraries have been renamed and moved to the Freya Optics libraries. Namespaces have changed to reflect this, and Freya.Lenses.* has been replaced by Freya.Optics.*. For example, open Freya.Lenses.Http should now be open Freya.Optics.Http.

Routers

The router included with Freya prior to 3.x has been moved and renamed to open up the way for additional more specialist routers to become part of the Freya stack. While the basic URI Template based routing has not changed (although the core has been rewritten to be more performant and accurate), the namespace has changed from Freya.Router to Freya.Routers.Uri.Template. Usage should be unchanged.

The old Freya.Machine.Router library to add a resource extension to the router is now included in the URI Template Router by default.

Machines

As with routers, the machine included with Freya prior to 2.x has been moved and renamed to open up the way for more Machine implementations in future. The machine was previously available in the Freya.Machine namespace – this has now been changed to Freya.Machines.Http. The requirement to include HTTP functionality through the use of using http has been removed.

Machines have gone through a more extensive rewrite than other parts of Freya, and some of the configuration of the HTTP machine has now changed and been simplified. This should all be reflected in deprecated helper methods where applicable, but please do get in Contact if you find areas where this is not the case!

The extension mechanism for machines has also been revamped, as follows:

The CORS support is now available in the namespace Freya.Machines.Http.Cors. It can be enabled for a resource by including the keyword cors in your machine – using cors is no longer needed.

PATCH support is now an extension, and can be found in the namespace Freya.Machines.Http.Patch. It can be enabled by adding the patch keyword to your machine.

Full details of the new design of HTTP machines can be found in the HTTP machine reference section. Documentation work on Machines is an ongoing process. If the detail you are looking for is not there currently, please check back soon, and follow Freya on Twitter for updates on all Freya subjects, including additions/changes to documentation.

Polyfills

Polyfills have been introduced to Freya in 3.x. They allow Freya to work around deficiencies in standards (such as missing data in the OWIN standard) and move faster than current standards allow. They are currently available for Katana based servers and Kestrel. For more information see the reference section on Polyfills.

Errors/Omissions?

This document is a work in progress throughout the 3.x release candidate cycle. Please get in Contact if you find any errors or omissions, or if you have any suggestions for how this document can be more useful.

To send a pull request directly, you can use the Edit Page link at the bottom of this (or any other) page.

Tutorials

For now, see the Getting Started tutorial to create your first Freya application.

Note

More Freya tutorials are currently being developed. Please check back soon. Documentation updates are also announced on the Freya Twitter feed – follow Freya there for up to the minute information on changes to this documentation, and other Freya news.

Getting Started

You can be up and running with Freya in minutes! This quick guide will take you from zero to Hello World, using some of the high level building blocks that Freya provides out of the box – and tell you where to go to learn more about each of them.

Your Hello World will be completely self contained, and able to greet individuals by name if they provide one – reverting to a classic Hello World if not. It’s certainly possible to write this in a simpler way using Freya, but this implementation introduces some of the key Freya building blocks which will be valuable as you build more complex applications. Here’s the complete code, before the implementation is broken down:

open Freya.Core
open Freya.Machines.Http
open Freya.Routers.Uri.Template

let name =
    freya {
        let! name = Freya.Optic.get (Route.atom_ "name")

        match name with
        | Some name -> return name
        | _ -> return "World" }

let hello =
    freya {
        let! name = name

        return Represent.text (sprintf "Hello %s!" name) }

let machine =
    freyaMachine {
        handleOk hello }

let router =
    freyaRouter {
        resource "/hello{/name}" machine }

type HelloWorld () =
    member __.Configuration () =
        OwinAppFunc.ofFreya (router)

open System
open Microsoft.Owin.Hosting

[<EntryPoint>]
let main _ =

    let _ = WebApp.Start<HelloWorld> ("http://localhost:7000")
    let _ = Console.ReadLine ()

    0

Dependencies

You’ll be creating the Hello World implementation as a simple F# console application, so go ahead and create a new empty F# console application. As you can see above, you can fit the whole thing in the single file that makes up the program (easily!) so there’s no need to worry about complex application structures or any of the complexities of frameworks like ASP.NET MVC.

Hint

In general, Paket comes highly recommended as a reliable way of managing your Nuget – and other – dependencies. For this guide however, standard Nuget tools will work well enough.

The first thing you’ll need is Freya and a suitable web server. In this case, the simple server from the Katana project will be used, although other servers like Kestrel, IIS, etc. will also work.

Using your preferred method of managing Nuget dependencies, install the required packages. Make sure you’re using the latest available versions!

PM> Install-Package Freya
PM> Install-Package Microsoft.Owin.SelfHost

The Freya package is a meta-package – it brings in all of the packages you’ll need for a common Freya application.

Code

At this point you should have an empty F# program. Start off by opening some common namespaces we’ll need to write our Hello World program. In this case, you’ll need three parts of the Freya stack.

open Freya.Core
open Freya.Machines.Http
open Freya.Routers.Uri.Template
Greeting

Now you’re ready to implement the Freya part of your Hello World application. Start by creating these two functions:

let name =
    freya {
        let! name = Freya.Optic.get (Route.atom_ "name")

        match name with
        | Some name -> return name
        | _ -> return "World" }

let hello =
    freya {
        let! name = name

        return Represent.text (sprintf "Hello %s!" name) }

You now have two functions which when used together return a representation of Hello [World|{name}] depending on whether {name} was present in the route. You’ll note that these functions are computation expressions – these are very common in Freya and form the basis of the programming model (although computation expression syntax is optional). For more on functions in Freya, see the Core reference. You’ll see more about routing in a following section.

Resource

Now you need some way of handling a request and using your hello function to return the representation of your greeting as the response – you need a way to model an HTTP resource. You can use the Freya HTTP Machine to do this. Machines are a powerful and high level abstraction – see the Machines reference for more, but for now you can simply use the very simply configured machine below, which will return your representation when a normal “OK” response is valid.

let machine =
    freyaMachine {
        handleOk hello }
Router

Finally, you’ll need a way to make sure that requests to the appropriate path(s) end up at your new Machine-based resource. You can use the URI Template based Freya router to do this easily. The following function will give you a simple router which will route requests matching the given path to your machine. For more on routing in Freya, see the Routers reference.

let router =
    freyaRouter {
        resource "/hello{/name}" machine }

Server

Now that you have all the “logic” covered you’ll need a way of serving it. You can use a simple self-hosted server, and fire it up in the main method of your program. As you’re using Katana here, you’ll need to create a type of a suitable shape for Katana to use as a start-up object. Here’s the code you’ll need, along with a main method to start things up.

type HelloWorld () =
    member __.Configuration () =
        OwinAppFunc.ofFreya (router)

open System
open Microsoft.Owin.Hosting

[<EntryPoint>]
let main _ =

    let _ = WebApp.Start<HelloWorld> ("http://localhost:7000")
    let _ = Console.ReadLine ()

    0

And there you have it! Try hitting localhost:7000/hello or localhost:7000/hello/name in a browser – you should have a Hello World up and running.

Hint

The code for the simple Freya Hello World example can be found in the freya-examples GitHub repository here - if you have any problems, try cloning and running the pre-built example.

Hopefully now you’re keen to learn more about the Freya components you’ve seen and what more they can do – and what others are available. The rest of the Freya documentation should help – and if you find it doesn’t, please reach out and suggest improvements – Contact is a good place to begin.

Recipes

Recipes are availble to help with common patterns of usage, categorised by the various areas of Freya and problems solved. The recipe categories are available directly from the top level navigation.

Integration

Integrating Freya with other systems (whether servers to host Freya applications, or other software frameworks) is essential. Freya should integrate widely through the use of the OWIN open standard, but it is not always obvious how it should work in practice. Examples and information for integration are given in the following two recipe sections:

  • Frameworks – integrating Freya with other frameworks, for example the Suave web framework. Freya plays nicely with others, and further and better integration is always a goal.
  • Servers – integrating Freya with servers for hosting. While OWIN is an open standard, the approaches to integrating OWIN vary between server implementations.

Frameworks

Currently documented integrations:

Suave

Note

This documentation is in the process of being written and reviewed. Please check back soon. Documentation updates are also announced on the Freya Twitter feed – follow Freya there for up to the minute information on changes to this documentation, and other Freya news.

Servers

Note

Pull requests to Freya documentation adding or extending information on usage with any particular server are particularly welcome. Freya should be broadly compatible, and every effort will be made to solve compatibility issue if they are discovered.

Currently documented integrations:

Katana

It’s very simple to integrate Freya applications with the Katana server, especially using the Microsoft OWIN SelfHost options. A simple example is show below:

// Freya

open Freya.Core

let application =
   freya { ... }

let owinApplication =
    OwinAppFunc.ofFreya application

// Katana

open Microsoft.Hosting

type Application () =
    member __.Configuration () =
        owinApplication

// Main

[<EntryPoint>]
let main _ =

    let _ = WebApp.Start<Application> ("http://localhost:8080")
    let _ = System.Console.ReadLine ()

    0

This will give a Katana based server running Freya-delivered content in a console application.

Kestrel

Note

This documentation is in the process of being written and reviewed. Please check back soon. Documentation updates are also announced on the Freya Twitter feed – follow Freya there for up to the minute information on changes to this documentation, and other Freya news.

Routing

Routing is a potentially complex topic which also usually conforms to various patterns under normal use. Some of the more common approaches and techniques are defined here as recipes applying to various available Freya routing features.

URI Templates

The URI Template type library, combined with the Freya.Routers.Uri.Template library, gives a concise yet powerful approach to routing. URI Templates in routing can sometimes be slightly surprising in their behaviour (the specification has some interesting corner cases) but certain techniques are quite generically useful in routing. Some of those will be added here.

Note

Pull requests suggesting new techniques for routing with URI Templates are very welcome!

Important

The specification of URI Templates is broader than simple path templating and generation, and much of the specification deals with matching query strings, fragments, etc. This means that Freya expects to match a full path and query string. You can make sure this works when you may have an (optional) query string by defining a catch-all query string on the end of your route URI Templates like so: {?q*}.

Lists

Matching simple lists of values in URIs can be useful. Using simple URI Template matching, this is trivial:

// This uses simple matching and list syntax to match lists of values
// separated by commas

let listTemplate =
    UriTemplate.parse "/{values*}"

// /one,two,three ->
Freya.Optic.get (Route.list_ "values")
// -> Some [ "one"; "two"; "three" ]
Pairs

Matching key/value pairs can also be a useful technique:

// This uses simple matching and keys syntax to match lists of key/value
// pairs (x=y) separated by commas

let listTemplate =
    UriTemplate.parse "/{pairs*}"

// /one=a,two=b,three=c ->
Freya.Optic.get (Route.keys_ "pairs")
// -> Some [ ("one", "a"); ("two", "b"); ("three", "c") ]
Paths

It is often useful to want to match a whole path, regardless of what it might be – for example, a virtual file server of some kind may map a seemingly “physical” path to a different underlying abstraction.

// This uses URI Template path segment matching and list syntax to
// match paths separated by "/" characters

let pathTemplate =
    UriTemplate.parse "{/segments*}"

// /one/two/three ->
Freya.Optic.get (Route.list_ "segments")
// -> Some [ "one"; "two"; "three" ]

let prefixedPathTemplate =
    UriTemplate.parse "/one{/segments*}"

// /one/two/three ->
Freya.Optic.get (Route.list_ "segments")
// -> Some [ "two"; "three" ]

Reference

Reference documentation for Freya contains guides to specific libraries along with guides for using Freya as part of a larger system. These are technical guides and give an overview of general use, rather than a recipe-like approach. The reference documentation is designed to be referred to when you’re using Freya.

The reference documentation is divided in to the main sets of libraries that make up the Freya stack. The library references cover the complete set of Freya functionality, and given both semantic and syntactic reference to the basic usage of the libraries.

When you’re looking for more general information on how to work in Freya, and how to think about solving problems using Freya, you might want to look at some of the other documentation options, particularly:

  • Topics – for focused guides to areas of development with Freya.
  • Recipes – for Freya-based solutions to common problems.

Core

Freya.Core provides the basic abstractions on which the Freya stack is built. Most of the types and basic functionality used by the higher level parts of Freya depend on the basics defined in Freya.Core. These essential elements of Freya are defined in the following sections:

Functions

The main abstraction in Freya is an abstraction over the OWIN state – see OWIN. As this is functional programming, you need to pass the state around to functions which require it (and return it from functions which have modified it).

Doing such a common thing manually would become a chore very quickly. The solution is the Freya<'a> function, which has the following type:

type Freya<'a> =
    State -> Async<'a * State>

In the case of the Hopac variant of the Freya stack – see Hopac – the type is instead defined as:

type Freya<'a> =
    State -> Job<'a * State>

The State type is a wrapper around the OWIN Environment - it holds a few additional data structures, the relevant part is the OWIN Environment.

A function of type Freya<'a> takes the state, and asynchronously (or as a Hopac Job) returns a value of type 'a and the state. The concurrency options are made available here as one or other of these abstractions is commonly used in web programming. This makes it easy to integrate Freya with existing libraries and software.

Syntax

The Freya<'a> type would be awkward to implement manually throughout applications, and F# allows for useful syntactic extension in the form of computation expressions.

A freya computation expression is provided to make it simpler to write code using Freya, and the functions available throughout Freya are easily usable with this syntax.

Note

This syntax is not compulsory – it is possible to use a more operator-based style when writing Freya code if you prefer.

The computation expression syntax looks like this:

let double x =
    freya {
        return x * 2 }

The signature of this function is int -> Freya<int>, showing a simple way to work with functions which now have the State threaded through them. Of course, this function doesn’t do anything with the State that it has available – the next section shows how State can be used.

State

The important part of the Freya approach to programming is to make programming with state transparent and functional. The most basic way to use information contained within the state is to get the State instance and to use some element of it, as seen below:

let readPath =
    freya {
        let! state = Freya.Optic.get id_
        return state.Environment.["owin.RequestPath"] :?> string }

The first part of this function gets the State instance, and the second part extracts some data from it and returns it. Note that the first line uses a Freya<_> function – requiring the use of the let! syntax for computation expressions.

This very basic usage works, but is not a compelling approach – it can be improved significantly, as detailed in the next section:

  • Optics – using Optics in Freya for safe, typed data manipulation.
Summary

The basic abstraction of Freya has been introduced, along with the Freya computation expression.

// Freya<'a> (State is described)
type Freya<'a> =
    State -> Async<'a * State> // (or State -> Job<'a * State>)

// Freya computation expression
freya { ... }

Optics

In the previous section, you saw that the underlying State instance, and elements of it, could be accessed within a Freya computation expression. While this is workable, it is an untidy and weak approach from the perspective of a strongly typed language.

The solution to this in Freya is to use optics – see the Optics topic for a general introduction – to enable a safer and more functional approach.

Approach

You saw in the previous example (and it’s defined in the OWIN specification) that the data is held within dictionary structures within the state. Here are two ways to retrieve data, the first using the previous naive approach, the second using a pre-defined optic to access the data:

// The previous way, using raw access to the state
let readPathRaw =
    freya {
        let! state = Freya.Optic.get id_
        return state.Environment.["owin.RequestPath"] :?> string }

// The optics way
let readPath =
    freya {
        return! Freya.Optic.get Request.path_ }

The optic approach is clearer and simpler, and also safer – the optic gives type-safe access to the data. Here the Request.path_ optic, defined in the Freya.Optics.Http library, is used to focus on the correct part of the state, and ensure that the data contained is present and correctly mapped to an appropriate type.

The same optic can be used to set the data, or to map a function over the data – the optics are bi-directional. Here’s an example of a function which instead writes to the request path.

let writePath path =
    freya {
        do! Freya.Optic.set Request.path_ path }

The same lens can be used, the only difference is the function used – Freya.Optic.set versus Freya.Optic.get.

Lenses and Prisms

The OWIN specification makes it clear that not all data in the OWIN Environment will always be present. Some data is optional, so you might find yourself trying to read data that doesn’t exist. In a more general sense, you can construct optics that may not always be able to traverse a data structure to the data that you want. These lenses are often called prisms, as opposed to the simpler optics – lenses – you saw in the previous section. A lens is an optic to a value of 'a – a prism to a value of 'a option.

In versions of Freya prior to 3.0 (due to the way that earlier versions of Aether worked), you needed to use different functions to work with lenses and prisms (then termed lenses and partial lenses). However, from 3.0 onwards, you can use the same methods to work with lenses or prisms, giving a smaller and more consistent API.

Here’s an example using a prism:

let readStatusCode =
    freya {
        return! Freya.Optic.get Response.statusCode_ }

This function is of type Freya<int option>, as the prism returns an option of the value (the response status code is not a required data element in the OWIN specification).

Morphisms and Types

You might be wondering about the description of optics as providing typed access to the data here. In the underlying data, it is defined in the OWIN specification that this data is stored as an obj (boxed) in a dictionary. How can you work with it as a string, or an int (and in the case of more complex elements of HTTP as a full typed representation of a header, for example)?

The optics defined are composed with morphisms – functions which can convert a data structure to and from another form. In the case above, the response status code is being converted to and from an int transparently as part of the optic access.

This is an important (and powerful) feature of Freya – you can work with strongly typed, expressive representations of data, even though underneath the surface the data is the old string-based web world.

Here’s a quick example, retrieving a header value from the request and receiving a strongly typed representation of that header back, which can be used with all of the type-based F# techniques and tools:

let readAccept =
    freya {
        return! Freya.Optic.get Request.Headers.accept_ }

// Might return something like...

Some (Accept [
    AcceptableMedia (
        Open (Parameters (Map.empty)),
        Some (AcceptParameters (Weight 0.3, Extensions (Map.empty))))
    AcceptableMedia (
        Partial (Type "text", Parameters (Map.empty)),
        Some (AcceptParameters (Weight 0.9, Extensions (Map.empty)))) ])

Here a strongly typed representation of the “Accept” header is retrieved if it’s present – and you’ll receive a fully decomposed, typed representation of that header which you can pattern match, inspect and work with – see Types for more on the type system that Freya uses.

Summary

The Freya approach to working with stateful data has been defined, giving the common functions for working with data, and some optics that are provided with Freya.

// Get a value from the state using an optic
Freya.Optic.get : optic 'a -> Freya<'a>

// Set a value in the state using an optic
Freya.Optic.set : optic 'a -> 'a -> Freya<unit>

// Map a function over a value in the state using an optic
Freya.Optic.map : optic 'a -> ('a -> 'a) -> Freya<unit>

// Aditionally, common Freya provided optics are available in:
open Freya.Optics.Http
open Freya.Optics.Http.Cors

Pipelines

Functional programming makes much of the ability to compose functions simply – one of the joys of functional programming is being able to compose complex functionality from simpler parts with confidence.

The common Freya<'a> functions are quite simple to use together in various ways (the computation expression syntax being the most obvious – calling another Freya<'a> function within a computation expression is as simple as using the let! or do! syntax. However, it turns out to be useful to introduce another building block, which makes it easier to build systems which compose at a more coarse-grained level.

Definition

Freya introduces the concept of a Pipeline function, which is defined like this:

type Pipeline =
    Freya<PipelineChoice>

 and PipelineChoice =
    | Next
    | Halt

It’s simply a normal Freya<'a> function, where 'a is constrained to be PipelineChoice. This is used as a building block throughout various Freya libraries.

Composition

The simplest example of this is the basic composition of some Pipeline functions, composed. The Pipeline.compose function can be used to do this. This function has a basic logical model – compositions of pipeline functions will halt when the first value of Halt is returned:

let yes =
    freya {
        return Next }

let no =
    freya {
        return Halt }

// Both of these functions will be run
Pipeline.compose yes no

// Only the first of these functions will be run
Pipeline.compose no yes

This becomes a useful technique when you want to stop processing a request in a certain situation – for example, you may have written a function which should halt processing if the user making the request is not authorized.

Operators

Freya always provides named functions for every piece of functionality, but some parts of libraries lend themselves well to the use of custom operators to make definition more concise and readable. As an alternative to the Pipeline.compose function, the infix syntax >?= is also available. This has the advantage that chains of composition become significantly simpler to read and write:

open Freya.Core.Operators

let functionComposed =
   Pipeline.compose (Pipeline.compose yes no) yes

let operatorComposed =
   yes >?= no >?= yes

// or if you prefer...

       yes
   >?= no
   >?= yes

It’s a matter of taste and is definitely subjective – but if you find the operator approach clearer, Freya makes them available.

Summary

The Pipeline function concept has been defined, and a simple approach to composing them.

// Types

type Pipeline =
    Freya<PipelineChoice>

 and PipelineChoice =
    | Next
    | Halt

// Composition

Pipeline.compose : Pipeline -> Pipeline -> Pipeline

// Composition (Operator)

open Freya.Core.Operators

(>?=) : Pipeline -> Pipeline -> Pipeline

Integration

As previously detailed, Freya is built on the OWIN open standard for interoperability between .NET web servers and web frameworks (or stacks).

You should be able to use Freya with any OWIN compatible web server – if you can’t, please raise an issue and we’ll help you however we can.

Functions

For recipes for integrating with specific servers and frameworks, see the Integration documentation. In a general sense however, it is usually only needed to use one function to bridge the Freya and OWIN worlds. We need to be able to turn a Freya function in to an OWIN Application Function, or AppFunc.

let freyaSystem =
    freya {
       ... }

let freyaAppFunc =
    OwinAppFunc.ofFreya freyaSystem

The OwinAppFunc module contains functions to take a Freya<'a> function and turn it in to an OwinAppFunc. Note that the return value of the function converted will be discarded when it’s run, as there is no use for it in this case (this does mean that any Freya<'a> function can be used).

Hint

OWIN specifies signatures for middleware functions – OwinMidFunc – as well as application functions – OwinAppFunc. The OwinMidFunc module contains useful functions, but it is currently considered experimental and is not yet documented.

Summary

The basic conversion of a Freya function to an OWIN compatible function has been demonstrated.

// Convert any Freya<_> function to an OwinAppFunc
OwinAppFunc.ofFreya : Freya<_> -> OwinAppFunc

Types

Freya is driven by a strongly-typed approach to working with the web, and so includes a set of libraries (Freya.Types.*) which model many of the constructs found in web specifications, particularly those dealing with HTTP, URIs, etc. These libraries were previously known as the Arachne project, but were brought under the Freya umbrella in the 3.0 release.

HTTP

The Freya.Types.Http library implements types which represent the semantics of the following standards:

This set of RFCs covers basic types present in HTTP requests and responses, principally the data found in the headers of HTTP messages. Strongly typed representations and parsers are given.

Note

Full documentation for the individual type designs within Freya.Types.Http is not currently available, but will be added at a later stage. Inspecting the values returned however should be straightforward and logical, and all typed representations map very closely to the logical design/grammar defined within the appropriate RFC or Recommendation.

To use the types:

// Working with the types
open Freya.Types.Http

HTTP CORS

The Freya.Types.Http.Cors library implements types which represent the semantics of the following standards:

The implementation of the Recommendation consists of a set of typed headers. Additionally the Origin header is implemented as defined in RFC 6454. Strongly typed representations and parsers are given.

Note

Full documentation for the individual type designs within Freya.Types.Http.Cors is not currently available, but will be added at a later stage. Inspecting the values returned however should be straightforward and logical, and all typed representations map very closely to the logical design/grammar defined within the appropriate RFC or Recommendation.

To use the types:

// Working with the types
open Freya.Types.Http.Cors

Language

The Freya.Types.Language library implements types which represent the semantics of the following standards:

Strongly typed representations and parsers are given.

No optics are given as a corresponding Freya.Optics.* library as these types are not present directly within HTTP messages, but they are used within some types in the HTTP and HTTP CORS libraries, and may be used directly when working with some of the higher levels of abstraction in the Freya stack which expect strongly typed Language Tags/Ranges as configuration values.

Note

Full documentation for the individual type designs within Freya.Types.Language is not currently available, but will be added at a later stage. Inspecting the values returned however should be straightforward and logical, and all typed representations map very closely to the logical design/grammar defined within the appropriate RFC or Recommendation.

To use the types:

// Working with the types
open Freya.Types.Language

PATCH

The Freya.Types.Patch library implements types which represent the semantics of the following standard:

Strongly typed representations and parsers are given, along with matching and rendering logic.

Note

Full documentation for the individual type designs within Freya.Types.Patch is not currently available, but will be added at a later stage. Inspecting the values returned however should be straightforward and logical, and all typed representations map very closely to the logical design/grammar defined within the appropriate RFC or Recommendation.

To use the types:

// Working with the types
open Freya.Types.Patch

URI

The Freya.Types.Uri library implements types which represent the semantics of the following standard:

Strongly typed representations and parsers are given.

No optics are given as a corresponding Freya.Optics.* library as these types are not present directly within HTTP messages, but they are used within some types in the HTTP and HTTP CORS libraries. They are also used in higher levels of abstraction within the Freya stack.

Note

Full documentation for the individual type designs within Freya.Types.Uri is not currently available, but will be added at a later stage. Inspecting the values returned however should be straightforward and logical, and all typed representations map very closely to the logical design/grammar defined within the appropriate RFC or Recommendation.

To use the types:

// Working with the types
open Arachne.Uri

URI Template

The Freya.Types.Uri.Template library implements types which represent the semantics of the following standard:

Strongly typed representations and parsers are given, along with matching and rendering logic.

No optics are given as a corresponding Freya.Optics.* library as these types are not present directly within HTTP messages. These types are used extensively in the Uri Template Routing library, and in work on the representation of Hypermedia standards.

Note

Full documentation for the individual type designs within Freya.Types.Uri.Template is not currently available, but will be added at a later stage. Inspecting the values returned however should be straightforward and logical, and all typed representations map very closely to the logical design/grammar defined within the appropriate RFC or Recommendation.

To use the types:

// Working with the types
open Freya.Types.Uri.Template

Optics

The Freya.Optics.* libraries provide optics from the Freya State type to strongly typed properties of the request, response, etc.

HTTP

The Freya.Optics.Http library provides optics from the State to the various aspects of the request and response, modelled using the types from Freya.Types.Http (and other Freya.Types.* libraries where needed). These optics are usable directly within a freya computation expression, working with the optic functions – see Optics.

The HTTP optics are likely to be the most commonly used optics dealing with request and response data. To use the optic the following modules should be opened:

// Working with Freya optics
open Freya.Optics.Http

// Working with the Freya types (maybe required)
open Freya.Types.Http

The optics are all provided under the Request and Response modules (e.g. Request.path_), along with sub-modules for headers (e.g. Request.Headers.accept_).

HTTP CORS

The Freya.Optics.Http.Cors library provides optics from the State to the various aspects of the request and response modelled using the types from Freya.Types.Http.Cors (and other Freya.Types.* libraries where needed). These optics are usable directly within a freya computation expression, working with the optic functions detailed in Optics.

These optics are probably not likely to be commonly used, especially when relying on some of the higher level abstractions available in the Freya stack, but they can be useful for writing new low-level code.

// Working with Freya optics
open Freya.Optics.Http.Cors

// Working directly with the types if required
open Freya.Types.Http.Cors

The optics are all provided under the Request.Headers and Response.Headers modules (e.g. Request.Headers.accessControlAllowOrigin_).

HTTP PATCH

The Freya.Optics.Http.Patch library provides optics from the State to the various aspects of the request and response modelled using the types from Freya.Types.Http.Patch (and other Freya.Types.* libraries where needed). These optics are usable directly within a freya computation expression, working with the optic functions detailed in Optics.

These optics are probably not likely to be commonly used, especially when relying on some of the higher level abstractions available in the Freya stack, but they can be useful for writing new low-level code.

// Working with Freya optics
open Freya.Optics.Http.Patch

// Working directly with the types if required
open Freya.Types.Http.Patch

The optics are all provided under the Request.Headers and Response.Headers modules (e.g. Response.Headers.acceptPatch_).

Routers

The Core library, along with the Types and Optics libraries, allow for the creation of powerful handlers for HTTP requests, but they don’t provide support for routing requests to specific handlers.

Routers are used to solve this problem, and allow for the aggregation of multiple handlers in to a more complex application. Freya allows for the possibility of multiple different implementations of routing, to support differing requirements. Currently Freya includes one router, based on URI Templates.

  • URI Template – a router which efficiently uses URI Templates to dispatch HTTP requests to handlers, and exposing the matched data as strongly typed URI Template data types.

URI Template

The URI Template router uses URI Templates – supported by the URI Template library – to define and match routes. This is both powerful and useful – the same templates can be used to generate URIs when needed.

Routes

The URI Template router is based on mapping requests to Pipeline functions – see Pipelines if you’re not familiar with the Freya pipeline concept. It maps the request by matching the method and the path and query against a URI Template.

Syntax

The URI Template Router defines a custom computation expression (simpler and more limited than the freya computation expression. The computation expression uses a custom operation to let you define routes in a simple, expressive and typed way. The computation expression is named freyaUriTemplateRouter but is also aliased to freyaRouter for convenience!

Definitions

Routes are defined by specifying a requirement for the HTTP method (or verb), a requirement for the path, and the Pipeline function to call if the route is matched. Route matching effectively happens in definition order precedence, although the router internally converts the route definitions to an optimised trie for performance reasons.

Strongly typed values are used for the requirements, using types taken from the Types libraries, in this case Freya.Types.Http and Freya.Types.Uri.Template, as well as types from Freya.Routers.Uri.Template. Here’s an annotated example of setting up a router, including opening appropriate modules/namespace:

open Freya.Core
open Freya.Routers.Uri.Template
open Freya.Types.Http
open Freya.Types.Uri.Template

// Handlers

let handlerA =
    freya {
        return Next }

let handlerB =
    freya {
        return Next }

// Routing

let routeA =
    UriTemplate.parse "/a/{id}"

let routeB =
    UriTemplate.parse "/b/{name}"

let routes =
    freyaRouter {
        route Any routeA handlerA
        route (Methods [ GET; OPTIONS ]) routeB handlerB }

Breaking this down, the first thing you will notice is the definition of two handlers, which are simple Pipeline functions:

let handlerA : Pipeline =
    freya {
        return Next }

let handlerB : Pipeline =
    freya {
        return Next }

Next in the code you will see two simple URI Templates defined. URI Templates can be used to generate URIs given a template and suitable data – Freya also allows to match on URI Templates, extracting the data to then be used. There are some caveats to matching URI Templates, but in general it is a good fit for many applications.

Two URI Templates are defined which will match the paths shown. The syntax for a match in this case is likely familiar – a simple match, capturing the braced terms (e.g. {id}).

let routeA : UriTemplate =
    UriTemplate.parse "/a/{id}"

let routeB : UriTemplate =
    UriTemplate.parse "/b/{name}"

Finally the router itself with the routes defined. The routes are defined using the route keyword in the computation expression. This takes three arguments:

  • A UriTemplateRouteMethod, which may be All – matching any method, or Methods which takes a list of Method values which are allowed. In the example, the first route will match any method, the second only GET or OPTIONS requests.
  • A UriTemplate which will be matched against the request path and query.
  • A Pipeline which will be called if the method, and the path and query are matched.
let routes =
    freyaRouter {
        route Any routeA handlerA
        route (Methods [ GET; OPTIONS ]) routeB handlerB }

The router will call the Pipeline function of the first matched route. If no route matches, no pipeline will be called.

Type Inference

Freya 3.0 introduced a more extensive use of statically resolved type parameters (don’t worry if these are not familiar) to give more concise and flexible APIs. One of the places where this is used is in this computation expression. Rather than only taking a literal UriTemplateRouteMethod as the first parameter, the route function can actually take any value which has a static UriTemplateRouteMethod member. By default, this is defined for a few different types, all of which can be used interchangeably. That means that the folloing are all valid routes:

let routes =
    freyaRouter {
        route Any routeA handlerA // Any
        route (Methods [ GET; POST ]) routeA handlerA // Methods
        route [ GET; POST ] routeA handlerA // Method list, inferred
        route GET routeA handlerA } // Method, inferred

You will see that this potentially makes things clearer and more readable, allowing for simpler expressions of the same concepts. In addition to the Methods, both the template and the handler are also inferred - anything which has UriTemplate and anything which has Pipeline can be used. By default, this means that you can just use strings and they will be statically inferred as templates, and any Freya<_> function can be inferred as a Pipeline. This can mean that a previously more complex configuration can be made much simpler:

let routes1 =
    freyaRouter {
        route (Methods [ GET ]) (UriTemplate.parse "/hello") handlerA }

// is the same as...

let routes2 =
    freyaRouter {
        route GET "/hello" handlerA }
Pipeline

In earlier versions of Freya, it was neccessary to call an explicit toPipeline function to use a router as a pipeline. This is no longer needed in 3.0+ – the router implements Pipeline and thus anything which expects to be able to infer a pipeline can accept a router.

URI Templates

in this example the URI Templates have been defined separately from the router. This could be done inline, saving space. However, it is often useful for multiple parts of a program to be able to refer to the URI Template as a first class item, so they are commonly defined outside of the router itself.

This becomes especially useful when you wish to return the URI of a resource as part of a response. You can use the same URI Template for routing and generating linking URIs, which prevents the two ever becoming unsynchronised, using the typed approach to prevent a class of error.

Values

As seen in Routes, it’s quite simple to map routes (the combination of method and path specification) to Pipeline functions. Once a route is matched however, you will likely need the handler to have access to the data that was matched as part of the URI Template.

Here is one of the URI Templates from the previous section:

let routeA =
    UriTemplate.parse "/a/{id}"

You can see that if this route has been matched, a value for {id} should now exist. Freya aims for a consistent model of programming throughout, and so the approach to accessing this data is aligned to accessing any other data – it is considered to be part of the state.

Optics

As with accessing data from the request or response, accessing data from the route requires the use of a suitable set of optics. These are provided under the Route module. Here’s a function which will return the {id} value from the example:

let readId =
    freya {
        return! Freya.Optic.get (Route.atom_ "id") }

There are several things to note here. The first is that route optics are prisms. You can’t statically be sure that a value will be present (even though intuitively you can know that it will be in certain contexts), so the optics must be prisms. Additionally, route optics are parameterised – as shown, it is passed the name of the value sought, in this case “id”).

Another key point to note is that there are three prisms available (all within the Route module). In this case, Route.atom_ is used, but Route.list_ and Route.keys_ are also available. Briefly, this is due to the nature of data within the URI Template specification. It is possible to render and match more complex data structures with URI Templates (see the URI Template RFC for a sense of how URI Templates can be used in more advanced ways). Simple values will only usually require the use of the Route.atom_ optic, but much more is possible – see the relevant recipes for more information.

Summary

Techniques for accessing matched values using optics have been shown.

open Freya.Routers.Uri.Template

// Optic for extracting string values from a matched route
Route.atom_ : string -> Prism<State, string>

// Optic for extracting string list values from a matched route
Route.list_ : string -> Prism<State, string list>

// Optic for extracting string pair values from a matched route
Route.keys_ : string -> Prism<State, (string * string) list>
Recipes

See also:

  • Routing – as well as the library reference, a growing collection of routing recipes covering various techniques is maintained.

See also:

  • Routing – as well as the library reference, a growing collection of routing recipes covering various techniques is maintained.

Machines

Freya provides powerful ways to interact with the web which are safe, expressive, and relatively low-level. However, Freya also provides some higher level abstractions to enable more effective and concise programming when interacting with complex standards.

Machines are one way of approaching this, and provide a different model of web programming, based around decision trees and declarative programming (don’t worry – this sounds complex and scary, but it isn’t!)

Understanding the way that machines are built and used helps make the most of this powerful Freya feature, and the underlying approach and computational model is covered in some depth in the topic on Machines covering the basic design and implementation of a machine.

Freya currently includes one machine (with extensions) for working with HTTP – additions may be made in future for complementary protocols, etc.

  • HTTP – a Freya Machine for working with HTTP in a safe and semantically correct way, based on a purely functional declarative approach.

In addition to the documentation on specific Machines, all Freya machines follow a defined set of Conventions which are useful to note.

HTTP

Freya lets you work with HTTP implicitly, using the typed but low-level tools found in Core combined with types and optics, such as the provided Optics. These are expressive and effective, but do not impose a particular structure or semantic form.

Hint

If you are already familiar with the HTTP machine, you may be looking to jump straight to the Reference Diagrams, or to the configuration reference for Properties, Decisions or Handlers.

HTTP is a fairly involved set of standards, and properly implementing the correct semantics of HTTP is not a trivial matter. Dealing with the correct logical approach to negotiating content types, working out the right approach to cache control and correctly expressing the state of the underlying resources, can be quite a lot to design when taken holistically.

The Freya HTTP macine (Freya.Machines.Http) is designed to solve this. The Machine lets you define just the properties of a resource you care about, and the Machine library handles the rest. You can specify as much or as little as you wish, all in a type safe manner, and be confident that HTTP semantics will remain consistent and correct.

To begin working with the Freya HTTP machine, it is suggested that reading the topic around the design of Machines makes a good entry point. Once you have an initial sense of the machine model, the following sections will should be easier to dive in to.

  • Overview – the basic design and syntax of the Freya HTTP machine.
  • Model – the diagram and implementation of the HTTP machine.
  • Configuration – the available configuration options as part of the Freya HTTP machine, as introduced in the machine overview and model.
Overview

To make the most of the HTTP machine, you should have a basic view of the model of a machine, ideally having read the topic on Machines design. That section finished by hinting at the application of the machine model to the Freya HTTP machine – this is covered in this and the following sections.

Syntax

The first thing to note is that as with the Freya URI Template Router, the configuration of the HTTP machine is done using a moderately declarative computation expression syntax. This allows for configuration to be readable while also taking advantage of some features of the F# type system to allow for concision where possible.

To create a simple HTTP machine, which models and HTTP resource, you can use the computation expression, freyaHttpMachine – also aliased as freyaMachine for convenience:

open Freya.Machine.Http

let resource =
    freyaMachine {
       handleOk handler }

Here you can see a very simple resource with almost minimal configuration.

The computation expression makes extensive use of custom operations, giving a declarative syntax which allows for a very clean description of the functionality of the machine as defined by configuration.

Terminology

In the topic on Machines, the application of the general machine model to specific problems, in this case HTTP was discussed, stating that general machine terminology is sometimes overridden for specific problem domains. The HTTP machine is one such example.

Decisions

Decisions remain the same, as they are universally applicable, and you will see decisions referred to throughout the HTTP machine documentation.

Terminals/Handlers

As you can infer from the section title, the more general term Terminal is replaced by the HTTP-implying term Handler. This ties the approach back towards styles of web development which people are likely to be more familiar with, and anchors the concept in common terminology. In essence, you can think of an HTTP machine as making a series of Decisions to decide which Handler should handle an HTTP request, and return a suitable response.

Model

The HTTP model is built using a modular approach using a pattern implemented in the underlying Hephaestus machine library. The Hephaestus library allows for powerful approaches to composing machines, which is out of scope for Freya documentation, but drives a useful modularity in terms of the HTTP model.

This modularity will be immediately visible in the diagrams of the HTTP machine, and reflected in the documentation around configuration of Decisions.

Diagrams

Clickable diagrams are available (these are generated from the Omnigraffle design documents for the HTTP machine and extensions, maintained as part of the Freya Machines repository):

Visualisation

In the Overview, the terminology of Decisions and Handlers was defined, and these are visualised in the clickable diagram of the HTTP model. The composition elements are informative in terms of grouping and structure, but the decisions and handlers are the key elements of the model. The naming of these elements is identical to the configuration syntax that may be used in the computation expression, allowing the diagrams to be used as a direct reference along with the detailed reference on each configuration option.

Decisions

Decisions are represented as diamonds, with one true outcome and one false outcome. The true outcome is represented by a solid line, and the false outcome by a dashed line.

  • Decisions which may be configured directly as part of the HTTP machine are coloured strong blue.
  • Decisions which may be influenced through configuration but not configured directly are coloured light blue.
  • Decisions which may not be configured are coloured grey.

There is a full reference for the HTTP machine Decisions, as well as a full reference for the Properties which may be configured to influence decisions which are not configured directly.

Handlers

Handlers are represented by boxes, showing the HTTP Staus Code associated with the handler by default. Colour is used to represent the semantic meaning of the HTTP results returned – green for 2xx, yellow for 3xx, orange for 4xx and dark orange for 5xx.

There is a full reference for the HTTP machine Handlers.

Configuration

There is extensive configuration available as part of the Freya HTTP machine, and the following sections deal with the different aspects, explained in the overview.

  • Properties – properties of the HTTP resource which may be used by decisions to configure behaviour.
  • Decisions – decisions influence the overall execution of the HTTP Machine, and enable you to define the behaviour of key aspects of your resource by answering true/false questions about the resource.
  • Handlers – handlers enable the response to return representations of the resource when appropriate, as well as providing a potential point in the execution of the Machine to set additional headers, etc.
Properties

Note

This documentation is currently being written and reviewed. Please check back soon. Documentation updates are also announced on the Freya Twitter feed – follow Freya there for up to the minute information on changes to this documentation, and other Freya news.

Decisions
Definition

Defining decisions to configure the HTTP machine is simple. All decisions are optional (defaults for all decisions, whether simple default values or a default function) are built in to the HTTP machine, so you only need to implement decisions which are relevant for your resource.

Types

Decisions can be implemented as one of two types due the static type inference used as part of the HTTP machine computation expression. This is a useful feature, as it enables the optimisation of machines (see the topic on the design of machines, particularly Decisions and Optimisation for relevant details).

You can configure decisions in the HTTP machine as either static or dynamic (i.e. as either bool or Freya<bool> in this case). No special syntax is needed, type inference will allow them to be used interchangeably. However, it should be noted that decisions defined statically – as bool – will be optimised and removed from the decision tree underlying the machine.

// A simple HTTP machine with a static decision

let staticHttp =
    freyaMachine {
        serviceAvailable true }

// A dynamic (Freya<'a>) function and a machine with a
// dynamic decision

let available =
    freya {
        <some health check logic>
        return [true|false] }

let dynamicHttp =
    freyaMachine {
        serviceAvailable available }

As you can see from the above example, the computation expression will accept decision values of either type transparently.

Reference

As shown in the clickable HTTP Model Diagrams the decisions are defined within re-usable functional blocks. A full reference for any block which contains decisions follows, giving the decision name, default values where applicable, and an explanation of the purpose and/or implementation of logic associated with each block and individual decision.

Assertions

Assertions decisions handle basic decisions about the state of the system as a whole, and basic properties of the HTTP request being handled.

Decision Default Description
serviceAvailable true Is the service available?
httpVersionSupported n/a Is the HTTP version (1.0, 1.1, etc.) supported? The default implementation will allow any HTTP versions of 1.1 or higher.
methodImplemented n/a Is the request method implemented/known about? The default implementation will compare the method with the basic sets of core HTTP methods, and any custom methods included in the method property.
Conflict

Conflict decisions handle decisions about the resource supplied by the client and whether it conflicts with the state of the resource known by the server.

Decision Default Description
conflict false Does the resource supplied conflict with the server resource?
Content

Content decisions handle decisions about the resource (and the representation of the resource) supplied by the client, such as whether the resource is of an acceptable media type (if a media type is specified).

Decision Default Description
lengthDefined n/a Is the length of the content defined?
hasMediaType n/a Is the media type of the included representation defined?
mediaTypeSupported n/a Is the media type of the included representation an acceptable media type? The implementation will refer to the acceptableMediaTypes property if it is defined. If the acceptableMediaTypes property is not configured, any media type will be accepted.
Existence

Existence decisions handle decisions about the resource and whether it currently exists on the server.

Decision Default Description
exists true Does the resource currently exist on the server?
Method

Method decisions handle decisions about whether the request method matches a specified method (used to route request handling to a set of method specific decisions).

Decision Default Description
methodMatches n/a Does the request method match the method configured? The decision will always return false (and thus be pruned from the final decision tree) if the method is not configured to be allowed via the methods property if configured or the default methods allowed if not.
Negotiations

Negotiations decisions handle decisions about the requested representation (if any) requested by the client, and whether such a representation can be negotiated.

Decision Default Description
hasAccept n/a Does the request define acceptable media types?
acceptMatches n/a Is at least one acceptable media type available? The implementation will refer to the availableMediaTypes property if configured, otherwise it is assumed that the server will decide on an appropriately typed representation via a different process.
hasAcceptLanguage n/a Does the request define acceptable languages?
acceptLanguageMatches n/a Is at least one acceptable language available? The implementation will refer to the availableLanguages property if configured, otherwise it is assumed that the server will decide on an appropriate language via a different process.
hasAcceptCharset n/a Does the request define acceptable character sets?
acceptCharsetMatches n/a Is at least one acceptable character set available? The implementation will refer to the availableCharsets property if configured, otherwise it is assumed that the server will decide on an appropriate character set via a different process.
hasAcceptEncoding n/a Does the request define acceptable encodings?
acceptEncodingMatches n/a Is at least one acceptable encoding available? The implementation will refer to the availableEncodings property if configured, otherwise it is assumed that the server will decide on an appropriate encoding via a different process.
Operation

Operation decisions are slightly different to ordinary decision, as the operation decision (named do<Method>, e.g. doPost) is expected to have side effects. This is the right place to implement your behavioural logic, to take the action that the request was intended to trigger.

Decision Default Description
do<Method> true Has the action succeeded without error?
completed true Has the action completed?
Permissions

Permissions decisions handle basic decisions about the client and whether they are authorized and allowed to make the request.

Decision Default Description
authorized true Is the request authorized? This might involve validating credentials, etc.
allowed true Is the request allowed? This might involve checking permissions, etc.
Preconditions
Common

Common precondition decisions handle basic decisions about the resource and the knowledge that the client has of that resource, to determine whether an action should proceed, for any action.

Decision Default Description
hasIfMatch n/a Does the request define an if-match value?
ifMatchMatches n/a Does the if-match value supplied match an Entity Tag given for the resource? The implementation will refer to the entityTag property if configured, otherwise it will assume a successful match.
hasIfUnmodifiedSince n/a Does the request define an if-unmodified-since value?
ifUnmodifiedSinceMatches n/a Does the if-unmodified-since value supplied match an last modified time given for the resource? The implementation will refer to the lastModified property if configured, otherwise it will assume a successful match.
Safe

Safe precondition decisions handle basic decisions about the resource and the knowledge that the client has of that resource, to determine whether an action should proceed, for a safe action.

Decision Default Description
hasIfNoneMatch n/a Does the request define an if-none-match value?
ifNoneMatchMatches n/a Does the if-none-match value supplied (not) match any Entity Tags given for the resource? The implementation will refer to the entityTag property if configured, otherwise it will assume a successful (non-)match.
hasIfModifiedSince n/a Does the request define an if-modified-since value?
ifModifiedSinceMatches n/a Does the if-modified-since value supplied match an last modified time given for the resource? The implementation will refer to the lastModified property if configured, otherwise it will assume a successful match.
Unsafe

Unsafe precondition decisions handle basic decisions about the resource and the knowledge that the client has of that resource, to determine whether an action should proceed, for an unsafe action.

Decision Default Description
hasIfNoneMatch n/a Does the request define an if-none-match value?
ifNoneMatchMatches n/a Does the if-none-match value supplied (not) match any Entity Tags given for the resource? The implementation will refer to the entityTag property if configured, otherwise it will assume a successful (non-)match.
Responses
Created

Created decisions handle decisions about the resource and whether it was created as part of the request processing.

Decision Default Description
created false Was the resource created in response to this request?
Common

Commons decisions handle basic decisions about the resource and the representation (if any) that should be returned to the client.

Decision Default Description
noContent false Should (no) representation be returned to the client?
Moved

Moved decisions handle basic decisions about the resource in situations where it is no longer present at the current URI.

Decision Default Description
gone false Has the resource gone from this URI?
movedTemporarily false Has the resource been moved temporarily from this URI?
movedPermanently false Has the resource been moved permanently from this URI?
Other

Other decisions handle basic decisions about the resource where the resource should not be represented directly, but should refer to another resource or location for this resource.

Decision Default Description
seeOther false Should another resource be used instead of this one?
found false Has this resource been found?
multipleChoices false Are there multiple forms of this resource which may be relevant to the client?
Validations

Validations decisions handle basic decisions about the request and whether it is of an appropriate form to be handled by the server.

Decision Default Description
expectationMet true Have implied HTTP expectations been met?
methodAllowed true Is the request method allowed for this resource? The implementation will refer to the methods property if configured, or the default set of methods if not.
uriTooLong false Is the URI too long?
badRequest false Is the request bad or malformed in some way?
Handlers
Definition

Defining handlers to provide responses is slightly more complex than defining Decisions, but is still a well-typed and straightforward process. The definition of handlers gains some extra complexity due to support for (optional) content-negotiation, and this leads to more potential types for a handler.

Types

As with Decisions, the handler can be defined as multiple types due to the use of static type inference in the HTTP machine computation expression. This allows for different types to be provided transparently, based on your goal for the handler.

Static

The simplest handler implementation is to provide nothing but a Representation. A Representation defines the data to be returned as the response, both the payload itself (Data, as a byte array) and any information on media type, language, etc. which is relevant (as the type Description). Here is an example of a handler of this type which will always return a very simple Hello World representation.

// Static handler (Representation)

let hello =
   { Description =
       { Charset = Some Charset.Utf8
         Encodings = None
         MediaType = Some MediaType.Text
         Languages = None }
     Data = Encoding.UTF8.GetBytes "Hello World" }

// A simple HTTP machine with a static handler

let staticHttp =
    freyaMachine {
        handleOk hello }

This will return the Hello World content with a text media type and a defined UTF-8 character set, but no definition for encodings or languages.

Dynamic

The static handler is only of use for very simple content requirements, and does not allow you to change any additional properties of the response other than through the representation returned. A dynamic handler allows you to work with request and response (and other) data as you normally would with Freya functions – a dynamic handler is simply a Freya<Representation>.

As the handler is the last function to be executed, you can also set properties on the response inside the handler – for example, adding or overriding response headers, status codes, etc. In this way you can easily customise the response where your requirements are outside of the HTTP implementation of the HTTP machine.

Here is an example of a machine with a dynamic handler, which also overrides the response reason phrase:

// Dynamic handler

let hello =
    freya {
        do! Freya.Optic.set Response.reasonPhrase_ (Some "Custom Phrase!")

        return {
            Description =
              { Charset = Some Charset.Utf8
                Encodings = None
                MediaType = Some MediaType.Text
                Languages = None }
            Data = Encoding.UTF8.GetBytes "Hello World" } }

// A simple HTTP machine with a dynamic handler

let dynamicHttp =
    freyaMachine {
        handleOk hello }

As you can see, there are no syntax changes required within the HTTP machine configuration when working with different handler types.

Negotiated Dynamic

The third, and most powerful handler type allows for a more controlled approach to negotiation. In the previous handler types, you’ve seen that the Representation returned defines the media type, encoding, etc. all of which could be the result of content negotiation during the execution of the machine. For this reason, the third handler type is Acceptable -> Freya<Representation>, a function which takes an Acceptable type, which is the result of any content negotiation which may have occurred during the execution of the machine.

The Acceptable type gives enough information to determine an appropriate representation:

type Acceptable =
    { Charsets: Acceptance<Charset>
      Encodings: Acceptance<ContentCoding>
      MediaTypes: Acceptance<MediaType>
      Languages: Acceptance<LanguageTag> }

 and Acceptance<'a> =
     | Acceptable of 'a list
     | Free

Using the information contained within the Acceptable type, and the individual Acceptance<_> value for each negotiable aspect, the handler can determine the representation to send, and construct it approrpriately. The Acceptable case of the Acceptance<_> type is an ordered list of matched values, with the most preferred first.

Usage of the the negotiated dynamic handler is similar to the dynamic handler, but with the opportunity to determine the most appropriate representation after content negotiation.

// Negotiated Dynamic handler

let hello acceptable =
    freya {
        do! Freya.Optic.set Response.reasonPhrase_ (Some "Custom Phrase!")

        // Logic to determine and construct appropriate representation ...

        return { ... } }

// A simple HTTP machine with a dynamic handler

let dynamicHttp =
    freyaMachine {
        handleOk hello }
Reference

The basic response properties will be set by default, but may be overridden by supplying any of the following handlers, which will also return an appropriate representation. Where no representation is to be returned, a supplied handler can return Representation.empty.

2xx
Handler Status Notes
handleOk 200
handleOptions 200
handleFallback 200 The fallback handler is not HTTP semantic, but provides a handler to deal with cases not covered by the HTTP machine in normal operation.
handleCreated 201
handleAccepted 202
handleNoContent 204
5xx
Handler Status Notes
handleInternalServerError 500 The internal server error handler will be invoked when an operation decision returns false.
handleNotImplemented 501
handleServiceUnavailable 503
handleHttpVersionNotSupported 505

Conventions

Freya machines follow a package naming convention to make it clear what is available and how it should be used. The convention for naming is as follows:

  • Freya.Machines.<Machine>[.<Extension>]

Using the example of the Freya HTTP machine, this gives:

  • Freya.Machines.Http

as the name of the core HTTP machine library. The HTTP machine also has extensions available to implement further web standards, or to integrate with other technologies/frameworks. Following the convention, this gives (for example):

  • Freya.Machines.Http.Cors
  • Freya.Machines.Http.Patch

Polyfills

Polyfills provide functionality which is not (and may never be) part of an open standard. Existing polyfills add existing data to the OWIN standard, enabling such things as more accurate routing. Polyfills are available for the following servers:

  • Katana – polyfills for Katana-based implementations, including self-hosted and IIS hosted approaches.
  • Kestrel – polyfills for Kestrel-based servers.

Katana

The Katana framework is the basis of self-host OWIN applications and also IIS applications. The Freya.Polyfills.Katana polyfill should be used whenever you are taking one of these hosting approaches. The polyfill should be used by inserting it in front of your Freya application in a pipeline composition:

open Freya.Core
open Freya.Core.Operators
open Freya.Polyfills.Katana

// Some pre-existing Freya pipeline (could be a router, function, etc.)
let myApp =
    freya {
        ...
        return Next }

// Compose a polyfill with the pre-existing pipeline
let composedApp =
        Polyfill.katana
    >?= myApp

// Use as normal...
let owinApp =
    OwinAppFunc.ofFreya composedApp

...

The polyfill currently adds additional data to the OWIN environment which enables routing to work more accurately (giving routers access to the raw, encoded form of the path and query).

Kestrel

The Kestrel server is the newer HTTP server built by Microsoft. The Freya.Polyfills.Kestrel polyfill should be used whenever you are taking one of these hosting approaches. The polyfill should be used by inserting it in front of your Freya application in a pipeline composition:

open Freya.Core
open Freya.Core.Operators
open Freya.Polyfills.Kestrel

// Some pre-existing Freya pipeline (could be a router, function, etc.)
let myApp =
    freya {
        ...
        return Next }

// Compose a polyfill with the pre-existing pipeline
let composedApp =
        Polyfill.kestrel
    >?= myApp

// Use as normal...
let owinApp =
    OwinAppFunc.ofFreya composedApp

...

The polyfill currently adds additional data to the OWIN environment which enables routing to work more accurately (giving routers access to the raw, encoded form of the path and query).