SAFE part 1 – Data generation and table

The application works well but it is quite ugly and there is only one person in the list.

Data generation with Bogus


Bogus is a data generation library for .net and works really well with .net core.

To install a dependency via Paket, open the Server.fsproj, then type Ctrl+Shift+P to open the command prompt, select Paket: add NuGet package (to current project) and then type Bogus. Wait a little bit aaaaaand… done!

There is another way to install a dependency.

In paket.dependencies, add the following in the group Server part:

nuget Bogus

In paket.references of the Server folder, add the following in the group Server part:


Then, in a terminal, launch:

.paket/paket.exe update

If you use Linux, write this command:

mono .paket/paket.exe update

Generate persons

To use Bogus, replace personRepository in Server.fs with:

open Bogus

let personRepository =
    let generator =
            .CustomInstantiator(fun f ->
                { id = f.Random.Number()
                  firstName = f.Name.FirstName()
                  lastName = f.Name.LastName()
                  address = 
                    { number = f.Random.Number(0, 100)
                      street = f.Address.StreetName()
                      postalCode = f.Address.ZipCode()
                      city = f.Address.City()

    let persons =
        |> List.ofSeq

        getAll = fun () -> async {
            do! Async.Sleep 2000
            return persons

There are 2 parts in data generation with Bogus.

You have to define a generation rule for each field. There are many ways to add these rules, but Person is a record type, so it’s better to use the following signature:

Faker<Person>("fr").CustomInstantiator((* Faker -> T *))

The function in CustomInstantiator is trivial, it generates a Person with random values depending on the type of data you want to generate.

You can set the locale to generate data of a specific language. I choose "fr" because French is a very cool language.

Once you have defined the Faker generator, you can call the generate function with the number of values you want to generate. The return type is a System.Collections.Generic.List which is different than the F# list type. That’s why the result is piped to List.ofSeq.

You can test the web service with Postman to see the generated data (see the previous article).

GitHub of this step here.

A beautiful table in Client

If you launch the application in this step, I’ll be awful because there is a mistake in Views.fs:

The issue is that content returns a string like "Jean Smisse\nNathan Durand\nJeannine Omelette", but to have linebreaks in HTML, a &lt;br /&gt; must be used.

Instead of fixing this bug, a table will be used.

First of all, a function for the header:

open Fable.Helpers.React

let personHeader =
    tr  []
        [ th [] [ str "Id" ]
          th [] [ str "First name" ]
          th [] [ str "Last name" ]
          th [] [ str "Address" ]

Then, one for a line in the table:

open Shared

let personLine p =
    tr  []
        [ td [] [ |> string |> str ]
          td [] [ str p.firstName ]
          td [] [ str p.lastName ]
          td [] [ str (Address.toString p.address) ] ]

id is an int, so it has to be converted to a string to be used in the str function.

Address.toString doesn’t exist yet, so add it in Shared/Models.fs:

module Address =
    let toString address =
        string address.number
        + " " + address.street
        + " " + address.postalCode
        + " " +

The last function to add is the table function:

let personsTable persons =
    let lines =
        |> personLine

    Table.table [ Table.IsHoverable ]
        [ thead [] [ personHeader ]
          tbody [] lines

lines is not surrounded by [] because it is already a ReactElement list, so you can pass it directly as a parameter of the tbody function.

And finally, the containerBox is replaced by:

let containerBox (model : Model) (dispatch : Msg -> unit) =
    let content =
        if System.String.IsNullOrEmpty(model.message) |> not then
            str model.message
            personsTable model.persons' [ ]
        [ Field.div
            [ Field.IsGrouped ]
            [ content ] ]

The main difference with the previous version here is that the content value no longer returns a string, but a ReactElement instead.

Your application now shows a shiny table:

GitHub of this step here.


So far, nothing is really complex, the application is very simple because it fetches some data and shows it.

You have seen the main mechanisms of SAFE like the remoting part, the philosophy of Fable and almost every important concepts you’ll use for this application.

Next time, person deletion.


3 thoughts on “SAFE part 1 – Data generation and table”

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.