A slightly more complex example: routing HTTP requests
Most .NET web frameworks are based on the object-oriented paradigm. This means that you have a class called something like CheesesController or CheesesModule. The methods in that class are then associated with url routes, with the most common routing methods being convention based, attribute-based (e.g. adding attributes like
[HttpGet]) or some sort of global routing table.
Suave is designed to fit in with F#’s functional programming paradigm, so routing does not use any of these routing methods. Instead routing takes place using a single function, itself composed from many smaller functions. This function has the signature
This function has a single parameter of type
HttpContext. This is an F# record type that includes the HTTP request, the HTTP response, and a few other things. This should be pretty familiar to anyone who has done any web programming before.
A WebPart function returns an asynchronous workflow which itself ultimately returns an
HttpContext option. Asynchronous workflows are hopefully already somewhat familiar. The
HttpContext option returned by the asynchronous workflow is either
Some HttpContext record or
None, and it is the option that is used to determine routing. Here is a web server with some simple routing logic. You can ignore the
>=> operator and the exact workings of
choose for now (both are explained in more detail later), just focus on the tree-like structure of the code:
choose we execute different logic depending on whether the request was a GET or a POST, and depending on whether the url was /hello or /goodbye. If a request matches a given path in the decision tree,
choose will return
Some HttpContext, if it doesn’t,
choose will return
None. The end result is that when someone makes a request the server will walk down this tree looking for the first part that returns
Some HttpContext, and then return it to the client. If no part of the tree returns
Some HttpContext then the result is an exception. You can can also add a default route which returns a 404 page.
The server won’t evaluate the entire data structure for every request, only the actual decisions, so there is no need to be concerned about performance.
How does the
userState work when there’s an error?
Even though the web part that created the state succeed earlier in the pipeline, there’s no way to get at it later. Whenever there’s an exception, Suave will terminate the currently running web part and jump into the exception handler. No, your best bet is to avoid throwing exceptions and working with types and values for control flow instead. BestPractice™