We've seen how to define basic routing in a Suave application. In this section we'll see how we can deal with returning good looking HTML markup in a HTTP response. Templating HTML views is quite a big topic itself, that we don't want to go into much details about. Keep in mind that the concept can be approached in many different ways, and the way presented here is not the only proper way of rendering HTML views. Having said that, I hope you'll still find the following implementation concise and easy to understand. In this application we'll use server-side HTML templating with the help of a separate Suave package called Suave.Experimental.

Note: As of the time of writing, Suave.Experimental is a separate package. It's likely that next releases of the package will include breaking changes. It's also possible that the modules we're going to use from within the package will be extracted to the core Suave package.

To use the package, we need to take a dependency on the following NuGet (add to paket.dependencies):

nuget Suave.Experimental 2.2.1

Also as was the case with Suave package, make sure to add Suave.Experimental to paket.references file and invoke paket install.

Before we start defining views, let's organize our App.fs source file by adding following line at the beginning of the file:


module SuaveMusicStore.App open Suave

The line means that whatever we define in the file will be placed in SuaveMusicStore.App module. Read here for more info about organizing and structuring F# code. Now let's add a new file View.fs to the project. With Ionide you can simply create the file and then having it open in editor, trigger F#: Add Current File To Project command.

We need to move the newly created file just before the App.fs in the *.fsproj project, e.g. by invoking twice following Ionide command: F#: Move File Up

Now let's place following module definition at the very top:


module SuaveMusicStore.View open Suave.Html

We'll follow this convention throughout the tutorial to have a clear understanding of the project structure.

Note: It's very important that the View.fs file comes before App.fs in fsproj. F# compiler requires the referenced items to be defined before their usage. At first glance, that might seem like a big drawback, however after a while you start realizing that you can have much better control of your dependencies. Read the following for further benefits of lack of cyclic dependencies in F# project.

namespace Suave
module Html

from Suave
module App

from SuaveMusicStore
module Filters

from Suave
module Operators

from Suave
module RequestErrors

from Suave
module Successful

from Suave
module Web

from Suave
val browse : (HttpContext -> Async<HttpContext option>)

Full name: SuaveMusicStore.App.browse
val request : apply:(HttpRequest -> HttpContext -> 'a) -> context:HttpContext -> 'a

Full name: Suave.Http.request
val r : HttpRequest
member HttpRequest.queryParam : key:string -> Choice<string,string>
union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>
val genre : string
val OK : body:string -> WebPart

Full name: Suave.Successful.OK
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
union case Choice.Choice2Of2: 'T2 -> Choice<'T1,'T2>
val msg : string
val BAD_REQUEST : body:string -> WebPart

Full name: Suave.RequestErrors.BAD_REQUEST
val webPart : WebPart<HttpContext>

Full name: SuaveMusicStore.App.webPart
val choose : options:WebPart<'a> list -> WebPart<'a>

Full name: Suave.WebPart.choose
val path : pathAfterDomain:string -> WebPart

Full name: Suave.Filters.path
val pathScan : pf:PrintfFormat<'a,'b,'c,'d,'t> -> h:('t -> WebPart) -> WebPart

Full name: Suave.Filters.pathScan
val id : int
val startWebServer : config:SuaveConfig -> webpart:WebPart -> unit

Full name: Suave.Web.startWebServer
val defaultConfig : SuaveConfig

Full name: Suave.Web.defaultConfig

Show code from this section on GitHub

results matching ""

    No results matching ""