Ocsigen

Ocsigen
Quickstart
guide

Vincent Balat

FUN-OCaml - Berlin
Sep 16-17 2024

Use arrow keys to navigate

Step 1: Install

$ opam install ocsigen-start ocsipersist-sqlite-config

You can find these slides on ocsigen.org
and the source code of the sides with the solution of exercices on Github.

Refer to the main one page user manual to get more explanations.

Ocsigen
Ocsigen

Ocsigen Server

Eliom

Js_of_ocaml

Tyxml

Lwt

Ocsigen Start

Ocsigen Toolkit

Ocsigen i18n

Jérôme Vouillon, Vincent Balat
Pierre Chambart, Grégoire Henry, Benedikt Becker,
Vasilis Papavasileiou, Gabriel Radanne, Hugo Heuzard,
Benjamin Canou, Boris Yakobowski, Jan Rochel, Idir Lankri,
Jérémie Dimino, Romain Calascibetta, Raphaël Proust, Anton Bachin, Baptiste Strazzulla,
Julien Sagot, Stéphane Glondu, Gabriel Kerneis, Denis Berthod, Thorsten Ohl,
Danny Willems, Kate Deplaix, Enguerrand Decorne, Grégoire Lionnet,
Jaap Boender, Gabriel Scherer, Gabriel Cardoso, Yuta Sato, Sora Morimoto,
Christophe Lecointe, Arnaud Parant, Jérôme Maloberti, Charly Chevalier,
Jean-Henri Granarolo, Simon Castellan, Barbara Lepage, Séverine Maingaud,
Mauricio Fernandez, Michael Laporte, Nataliya Guts, Archibald Pontier,
Jérôme Velleine, Charles Oran, Pierre Clairambault, Cécile Herbelin

Example app: Be Sport

The sports social network https://besport.com/news

Ocsigen Ocsigen

Ocsigen

First part: Server-side programming

Write your website in OCaml

Step 2: Ocsigen Server

As an executable

$ ocsigenserver -c config

Where config is something like:

<ocsigen>
  <server>
    <port>8080</port>
    <commandpipe>local/var/run/mysite-cmd</commandpipe>
    <logdir>local/var/log/mysite</logdir>
    <datadir>local/var/data/mysite</datadir>
    <charset>utf-8</charset>
    <debugmode/>
    <extension findlib-package="ocsigenserver.ext.staticmod"/>
    <host hostfilter="mydomain.com">
      <static dir="local/var/www/staticdir"/>
    </host>
  </server>
</ocsigen>

As an OCaml library

let () =
  Ocsigen_server.start 
       [ Ocsigen_server.host [Staticmod.run ~dir:"static" ()]]

Example of Dune file for this program:

(executable
 (public_name myproject)
 (name main)
 (libraries
  ocsigenserver
  ocsigenserver.ext.staticmod))

Compile with:

dune build

Find more complex configuration examples in the manual

Step 3: Generating pages with Eliom

Create a new project:

$ dune init project --kind=executable mysite
$ cd mysite

Define a service in bin/main.ml:

let myservice =
  Eliom_service.create
    ~path:(Eliom_service.Path ["foo"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    ()

Register a handler:

let () =
  Eliom_registration.Html.register ~service:myservice
    (fun () () ->
      Lwt.return
         Eliom_content.Html.F.(html (head (title (txt "The title")) [])
                                    (body [h1 [txt "Hello"]])))

Start the server with static files and Eliom:

let () = 
  Ocsigen_server.start 
    ~command_pipe:"local/var/run/mysite-cmd"
    ~logdir:"local/var/log/mysite"
    ~datadir:"local/var/data/mysite"
    ~default_charset:(Some "utf-8")
    [
      Ocsigen_server.host
       [ Staticmod.run ~dir:"local/var/www/mysite" ()
       ; Eliom.run () ]
    ]

Add packages ocsipersist-sqlite, ocsigenserver.ext.staticmod and eliom.server to file bin/dune, in the "libraries" section and create the directories used in the configuration just above.

Compile and run:

$ dune exec mysite

Go to http://localhost:8080/foo to test your program.

Sessions: scoped references

Server-side session data is stored in Eliom references:

let r = 
  Eliom_reference.eref
     ~scope:Eliom_common.default_session_scope 0


let f () =
  let%lwt v = Eliom_reference.get r in
  Eliom_reference.set r (v + 1);

Eliom references have a scope!

Request request_scope
Tab default_process_scope
Session default_session_scope
Session group default_group_scope
Site site_scope
Global global_scope

Step 4: Implement a basic login mechanism

  1. On your main page, add a form with a single text input field for a user name.

Submiting this form sends the user name to a POST service, that will register your user name.

When the user name is already known, your main page displays this name, and a logout button.

  1. Implement a second page, and add HTML links from one page to the other

Hints:

  • See an example of form and POST service here
  • Use an action (service with no output, that will just redisplay the page after perfoming a side-effect) to set a scoped reference with the user name
  • To close the session use function Eliom_state.discard_all

Test your app with several browsers to check that you can have several users simultaneously.

See the solution here.

Advanced version: instead of using a reference with scope session, create a session group whose name is the user name. Check that you can share session data across multiple browsers.

Ocsigen

Service, reinvented

Services have many other features:

  • Services can be identified by a path
    and/or by a name added automatically by Eliom as (GET or POST) parameter
  • Secure services (csrf-safe, secure sessions, https only …)
  • Dynamic creation of services Continuation based Web Programming
    • Scoped services (?scope)
    • Temporary services (?max_use, ?timeout …)

Example:

  1. A user submit a form with some data
  2. You ask Eliom to create dynamically a new temporary service, identified by an auto-generated name,

The form data will be saved in the closure!

Functional Web Programming!