Ocsigen Start and Ocsigen Toolkit reach 1.0!
Written by The Ocsigen Team on February 09, 2017

The Ocsigen team is very happy to announce the first release of two major new projects:

  • Ocsigen Start: a Web/mobile application skeleton written with Js_of_ocaml and Eliom. You can use this skeleton as a basis for your own app, or to learn Web/mobile app development in OCaml.

  • Ocsigen Toolkit: a set of responsive widgets for your mobile and Web applications in OCaml.

Both projects are available via OPAM and released under the LGPL.

Before installing, you can try out a demo of Ocsigen Start. The demo is available

Ocsigen Start provides the basic features for user management (registration, activation links, password recovery, etc.), and some useful libraries. Remove the parts you don’t need for your own app.

Ocsigen Start also contains many examples of code: remote procedure calls, push notifications from the server, reactive pages, database interaction, session data, internationalization, and some widgets from Ocsigen Toolkit.

Ocsigen Toolkit contains common widgets for mobile and Web apps, written natively in OCaml and specifically designed for Eliom’s multi-tier and multi-platform programming style. You can also use them in client-only Js_of_ocaml programs. Many new widgets will be added in future versions.

Ocsigen Start and Ocsigen Toolkit are developed by the Ocsigen team at Be Sport, at the Paris Diderot University, and at the IRILL.

News on the Eliom language
Written by Gabriel `Drup` Radanne on February 06, 2017

The Eliom framework is the part of the ocsigen project that aims to provide high level libraries for developing client/server web applications. It contains a language extension of OCaml that allows implementing both the client and the server parts of your application as a single program. It also contains several libraries and utilities to facilitate web programming.

The various Ocsigen libraries have received a lot of care lately. Notably, we have reworked the service API, we have added support for mobile applications and, we have developed ocsigen-start.

Today, I will not talk about the ocsigen libraries. I will talk solely about the language extension.

The current language extension

The Eliom language extension extends OCaml with various annotations that allows specifying where things are to be defined and executed.

let%server s = 1 + 2 (* I'm executed on the server *)
let%server s2 = (* I'm declared on the server *)
  [%client 1 + 2 (* But I will be executed on the client! *) ]
let%client c =
  ~%s + ~%s2 + 1
  (* I access values on the server and execute things on the client! *)

The semantics is that the server part is executed first, then the web page is sent to the client, then the client part is executed. See the documentation for detail on the current extension.

The language extension is currently implemented using a PPX extension and a custom (and a bit sophisticated) compilation scheme. Note here that I used the word “language” extension on purpose: this is not a simple syntax extension, the Eliom language has its own type system, semantics and compilation scheme, which are extensions of the OCaml ones.

The current implementation of our language, based on PPX, started to show its limits in terms of flexibility, convenience and with respect to the safety guarantees it can provide. This is why I started, as part of my PhD thesis, to redesign and improve it.

Formalizing the Eliom language

Our first goal was to formalize the Eliom language as an extension of the OCaml language. Formalizing the language allowed us to better understand its type system and semantics, which led to various improvements and bug fixes. The formalization was published in APLAS 2016. In this paper, we present a (rather simple) type system based on two distinct type universes and the notion of converters, that allows passing values from the server to the client. We also show that the intuitive semantics of Eliom, that server code is executed immediately and client code is executed later in the exact same order it was encountered, does correspond to the compilation scheme used to slice Eliom programs into a server program and a client program.

In the the current implementation, when passing a server value of type Foo.t to the client. It also has type Foo.t, but the type is now the one available on the client. The actual object can also be transformed while passing the client/server boundary using wrappers. Unfortunately, this API is very difficult to use, not flexible and quite unsafe. Instead, we propose to use converters. Converters can be though as a pair of function: a server serialization function ty_server -> string and a client deserialization function string -> ty_client (the actual implementation will be a bit different to make (de)serializer composable). The correctness of a converter depends of course on the good behavior of these two functions, but the language guarantees that they will be used together properly and each sides will properly respect the types of the converter.

By using converters, we can provide a convenient programming model and make Eliom much easier to extend. We demonstrated this with multiple examples in another paper published in IFL 2016. Unfortunately, a proper implementation of converters is only possible with some form of ad-hoc polymorphism, which involve using modular implicits.

Implementing the Eliom language

In order to actually implement all these new things, I started to work on an extension of the OCaml compiler capable of handling the Eliom language constructs. Working directly in the compiler has several advantages:

  • We can implement the actual type system of Eliom directly.
  • Easier to extend with new features.
  • Much better error messages.
  • A simpler and faster compilation scheme.

The current work-in-progress compiler is available in the repository ocsigen/ocaml-eliom. A minimal runtime, along with various associated tools are available in ocsigen/eliomlang. A (perpetually broken) playground containing an extremely bare-bone website using eliomlang without the complete framework is available in ocsigen/eliomlang-playground.

Finally, the work on using this new compiler to compile the Eliom framework can be followed via this pull-request.

Going further

A more in-depth presentation of the Eliom language can be found here. The APLAS paper is quite formal and is mostly aimed at people that want to really understand the minute details of the language. The IFL paper, on the other hand, should be accessible to most OCaml programmers (even those who don’t know Eliom) and demonstrates how to use the new Eliom constructs to build nice, tierless and typesafe libraries for client/server web programming.

The future

The work on the Eliom language is far from done. A current area of work is to extend the OCaml module language to be aware of the Eliom annotations. A particularly delicate (but promising!) area is the ability to use Eliom annotations inside functors. A second area of work is that of stabilizing, debugging and documenting the patched compiler. Finally, a difficulty raised by this new compiler is that existing build systems, and in particular ocamlbuild, do not handle the Eliom compilation scheme very well. Some details on this can be found here.

I wish this progress report has awaken your appetite for well-typed and modular tierless programming in OCaml. I hope I will be able to share more news in a few months.

Happy Eliom programming!

Lwt 2.7.0
Written by Anton Bachin on January 06, 2017

Lwt 2.7.0 was released today. This release aims to (1) improve communication between maintainers and users, and (2) prepare for (minor) breaking changes to some APIs in Lwt 3.0.0 (planned for April).

To this end:

  • Lwt now uses deprecation warnings ([@deprecated]), especially for upcoming breaking changes. This required dropping support for OCaml 4.01.
  • There is a gradual, communicative, conservative process for deprecation and breaking. Maintainers of packages in OPAM get notified proactively. If you have code not published in OPAM, watch the Lwt repo, recompile the code at least once in three months, or subscribe to the Lwt announcements issue.
  • If a planned breaking change is a bad idea, please let the maintainers know when you see the warning.
  • Lwt now uses semantic versioning. The major version will grow slowly but steadily, but this does not mean that the whole API is being redesigned or broken.

If you are releasing a package to OPAM that depends on Lwt, it is not recommended to constrain Lwt to its current major version. A major release of Lwt will break only a few APIs, and your package is likely not to be affected – if it is, you will be notified. You may, however, wish to constrain Lwt to a major version in your private or production code.

Additional changes

  • The main OPAM package lwt is getting rid of some optional dependencies in 3.0.0, which are now installable through separate OPAM packages lwt_ssl, lwt_glib, lwt_react. This is to reduce recompilation of Lwt when installing OPAM packages ssl, lablgtk, and react.
  • Values of types 'a Lwt.t are now called promises rather than threads. This should eliminate a lot of confusion for beginners.

Lwt 2.7.0 also has a number of more ordinary changes, such as bug fixes and the addition of bindings to writev and readv. See the full changelog.

Future work

I am working on an all-new manual, including fully rewritten API documentation with examples. It should be ready towards the end of winter.

My hope is that all the above allows Lwt to be taken progressively into the future, at the same time making development more open and more humane.

Discuss on reddit!

Eliom 6.0: mobile and Web apps in OCaml
Written by The Ocsigen Team on December 12, 2016

We are very happy to announce the release of Ocsigen Eliom 6.0, which follows the recent releases of Ocsigen Server 2.8 and Ocsigen Js_of_ocaml 2.8.x.

New features include a friendlier service API that retains the expressive power of our service system. Additionally, Eliom can now be used to build cross-platform Web/mobile applications (Android, iOS, …).

What is Eliom?

Eliom is a framework for developing client/server web applications. Both the server and the client parts of the application are written in OCaml, as a single program. Communication between server and client is straightforward, e.g., one can just call a server-side function from client-side code.

Eliom makes extensive use of the OCaml language features. It provides advanced functionality like a powerful session mechanism and support for functional reactive Web pages.

Friendly service APIs

Services are a key concept in Eliom, used for building the pages that are sent to the user, for accessing server-side data, for performing various actions, and so on. Eliom 6.0 provides a friendlier API for defining and registering services, thus making Eliom more approachable.

The new API makes extensive use of OCaml’s GADTs, and provides a single entry-point that supports most kinds of services (Eliom_service.create). For more information, refer to the Eliom manual.

Mobile applications

Eliom 6.0 allows one to build applications for multiple mobile platforms (including iOS, Android, and Windows) with the same codebase as for a Web application, and following standard Eliom idioms.

To achieve this, we have made available the Eliom service APIs on the client. Thus, the user interface can be produced directly on the mobile device, with remote calls only when absolutely necessary.

To build an Eliom 6.0 mobile application easily, we recommend that you use our soon-to-be-released Ocsigen Start project, which provides a mobile-ready template application (walkthrough).

Compatibility

Eliom 6.0 supports the last 3 major versions of OCaml (4.02 up to 4.04). Additionally, Eliom is compatible with and builds on the latest Ocsigen releases, including Ocsigen Server 2.8, Js_of_ocaml 2.8.x, and TyXML 4.0.x.

Future

The Ocsigen team is busy working on new features. Notably, we are developing an OCaml compiler specifically tuned for Eliom. Additionally, we are planning a transition to the Cohttp HTTP backend.

Support

TyXML 4.0.0
Written by The Ocsigen Team on May 20, 2016

It is with great pleasure that we are announcing the release of TyXML 4.0.0. The major features of this new release are a new PPX syntax extension that allows to use the standard HTML syntax and an improved user experience for both old and new TyXML users.

What is TyXML ?

TyXML is a library for building statically correct HTML5 and SVG documents. It provides a set of combinators which use the OCaml type system to ensure the validity of the generated document. TyXML’s combinators can be used to build textual HTML and SVG, but also DOM trees or reactive interfaces, using Eliom and Js_of_ocaml.

New TyXML manual and improved documentation

A new TyXML manual is now available here. The documentation of the various TyXML modules was also improved. Do not hesitate to provide feedback via our bug tracker!

HTML syntax with the new PPX syntax extension

It is now possible to use the standard HTML syntax:

open Tyxml
let%html to_ocaml = "<a href='ocaml.org'>OCaml!</a>"

It supports insertion of OCaml code inside the HTML and can be used with all the TyXML modules (such as Js_of_ocaml and Eliom) and with SVG. A complete overview can be found in the manual.

This new PPX syntax extension leverages the (awesome) Markup.ml library and was contributed by Anton Bachin.

Others

  • Toplevel printers are now available for the base HTML and SVG implementations:
# Tyxml.Html.(div [pcdata "Oh!"]) ;;
- : [> `Div ] Tyxml.Html.elt = <div>Oh!</div>
  • The HTML and SVG combinators have received numerous improvements to make them more consistent and easier to use. This means that several modules and functions have been renamed and some types have been changed, which breaks compatibility with previous TyXML versions.

  • A healthy amount of new elements and attributes.

  • The full changelog is available here.

Compatibility

This new version breaks compatibility. Compatible versions of js_of_ocaml and Eliom are available in the respective master branches. A compatible js_of_ocaml version should be released shortly™.

TyXML 4.0.0 is only available on OCaml >= 4.02.

The future

While nothing is decided yet, some work has already started to enhance the syntax extension with type safe templating.

Happy HTML and SVG hacking!

Ocsigen: step by step tutorial for client-server Web application (2/2)
Written by Ocsigen team on March 30, 2016

This is the end of the tutorial about writing a collaborative Web drawing in OCaml. Have a look at the full tutorial if you haven’t read the first part or if you want a version with full colors and links.

In the last part, we’ve seen how to create a client-server Web application in OCaml. The server generates a Web page and sends it together with an OCaml program (compiled to JavaScript) to the browser.

We will now see how to draw on the canvas, program mouse events with Lwt, and do server to client communication on a bus.

Collaborative drawing application

Drawing on a canvas

We now want to draw something on the page using an HTML5 canvas. The drawing primitive is defined in the client-side function called draw that just draws a line between two given points in a canvas.

To start our collaborative drawing application, we define another client-side function init_client, which just draws a single line for now.

Here is the (full) new version of the program:

[%%shared
  (* Modules opened in the shared-section are available in client-
     and server-code *)
  open Eliom_content.Html5.D
  open Lwt
]

module Graffiti_app =
  Eliom_registration.App (
    struct
      let application_name = "graffiti"
    end)
    
let%shared width = 700
let%shared height = 400

let%client draw ctx ((r, g, b), size, (x1, y1), (x2, y2)) =
  let color = CSS.Color.string_of_t (CSS.Color.rgb r g b) in
  ctx##.strokeStyle := (Js.string color);
  ctx##.lineWidth := float size;
  ctx##beginPath;
  ctx##(moveTo (float x1) (float y1));
  ctx##(lineTo (float x2) (float y2));
  ctx##stroke

let canvas_elt =
  canvas ~a:[a_width width; a_height height]
    [pcdata "your browser doesn't support canvas"]

let page () =
  (html
     (head (title (pcdata "Graffiti")) [])
     (body [h1 [pcdata "Graffiti"];
            canvas_elt]))

let%client init_client () =
  let canvas = Eliom_content.Html5.To_dom.of_canvas ~%canvas_elt in
  let ctx = canvas##(getContext (Dom_html._2d_)) in
  ctx##.lineCap := Js.string "round";
  draw ctx ((0, 0, 0), 12, (10, 10), (200, 100))

let main_service =
  Graffiti_app.register_service ~path:[""] ~get_params:Eliom_parameter.unit
    (fun () () ->
       (* Cf. section "Client side side-effects on the server" *)
       let _ = [%client (init_client () : unit) ] in
       Lwt.return (page ()))

JavaScript datatypes in OCaml

Here we use the function Js.string from Js_of_ocaml’s library to convert an OCaml string into a JS string.

Client side side-effect on the server

What sounds a bit weird at first, is a very convenient practice for processing request in a client-server application: If a client value is created while processing a request, it will be evaluated on the client once it receives the response and the document is created; the corresponding side effects are then executed. For example, the line

    let _ = [%client (init_client () : unit) ] in
    ...

creates a client value for the sole purpose of performing side effects on the client. The client value can also be named (as opposed to ignored via _), thus enabling server-side manipulation of client-side values (see below).

Single user drawing application

(Lwt, Mouse events with Lwt)

We now want to catch mouse events to draw lines with the mouse like with the brush tools of any classical drawing application. One solution would be to mimic typical JavaScript code in OCaml; for example by using function Dom_events.listen that is the Js_of_ocaml’s equivalent of addEventListener. However, this solution is at least as verbose as the JavaScript equivalent, hence not satisfactory. Js_of_ocaml’s library provides a much easier way to do that with the help of Lwt.

Replace the init_client of the previous example by the following piece of code, then compile and draw!

let%client init_client () =

  let canvas = Eliom_content.Html5.To_dom.of_canvas ~%canvas_elt in
  let ctx = canvas##(getContext (Dom_html._2d_)) in
  ctx##.lineCap := Js.string "round";

  let x = ref 0 and y = ref 0 in

  let set_coord ev =
    let x0, y0 = Dom_html.elementClientPosition canvas in
    x := ev##.clientX - x0; y := ev##.clientY - y0
  in

  let compute_line ev =
    let oldx = !x and oldy = !y in
    set_coord ev;
    ((0, 0, 0), 5, (oldx, oldy), (!x, !y))
  in

  let line ev = draw ctx (compute_line ev); Lwt.return () in

  Lwt.async (fun () ->
    let open Lwt_js_events in
    mousedowns canvas
      (fun ev _ ->
         set_coord ev; line ev >>= fun () ->
           Lwt.pick
             [mousemoves Dom_html.document (fun x _ -> line x);
	      mouseup Dom_html.document >>= line]))

We use two references x and y to record the last mouse position. The function set_coord updates those references from mouse event data. The function compute_line computes the coordinates of a line from the initial (old) coordinates to the new coordinates–the event data sent as a parameter.

The last four lines of code implement the event-handling loop. They can be read as follows: for each mousedown event on the canvas, do set_coord, then line (this will draw a dot), then behave as the first of the two following lines that terminates:

  • For each mousemove event on the document, call line (never terminates)
  • If there is a mouseup event on the document, call line.

More on Lwt

Functions in Eliom and Js_of_ocaml which do not implement just a computation or direct side effect, but rather wait for user activity, or file system access, or need a unforseeable amount of time to return are defined with Lwt; instead of returning a value of type a they return an Lwt thread of type a Lwt.t.

The only way to use the result of such functions (ones that return values in the Lwt monad), is to use Lwt.bind.

Lwt.bind : 'a Lwt.t -> ('a -> 'b Lwt.t) -> 'b Lwt.t

It is convenient to define an infix operator like this:

let (>>=) = Lwt.bind

Then the code

f () >>= fun x ->

is conceptually similar to

let x = f () in

but only for functions returning a value in the Lwt monad.

For more clarity, there is a syntax extension for Lwt, defining let%lwt to be used instead of let for Lwt functions:

let%lwt x = f () in

Lwt.return creates a terminated thread from a value: Lwt.return : 'a -> 'a Lwt.t Use it when you must return something in the Lwt monad (for example in a service handler, or often after a Lwt.bind).

Why Lwt?

An Eliom application is a cooperative program, as the server must be able to handle several requests at the same time. Ocsigen is using cooperative threading instead of the more widely used preemptive threading paradigm. It means that no scheduler will interrupt your functions whenever it wants. Switching from one thread to another is done only when there is a cooperation point.

We will use the term cooperative functions to identify functions implemented in cooperative way, that is: if something takes (potentially a long) time to complete (for example reading a value from a database), they insert a cooperation point to let other threads run. Cooperative functions return a value in the Lwt monad (that is, a value of type 'a Lwt.t for some type 'a).

Lwt.bind and Lwt.return do not introduce cooperation points.

In our example, the function Lwt_js_events.mouseup may introduce a cooperation point, because it is unforseeable when this event happens. That’s why it returns a value in the Lwt monad.

Using cooperative threads has a huge advantage: given that you know precisely where the cooperation points are, you need very few mutexes and you have very low risk of deadlocks!

Using Lwt is very easy and does not cause trouble, provided you never use blocking functions (non-cooperative functions). Blocking functions can cause the entre server to hang! Remember:

  • Use the functions from module Lwt_unix instead of module Unix,
  • Use cooperative database libraries (like PG’Ocaml for Lwt),
  • If you want to use a non-cooperative function, detach it in another preemptive thread using Lwt_preemptive.detach,
  • If you want to launch a long-running computation, manually insert cooperation points using Lwt_unix.yield,
  • Lwt.bind does not introduce any cooperation point.

Handling events with Lwt

The module Lwt_js_events allows easily defining event listeners using Lwt. For example, Lwt_js_events.click takes a DOM element and returns an Lwt thread that will wait until a click occures on this element.

Functions with an ending “s” (Lwt_js_events.clicks, Lwt_js_events.mousedowns, …) start again waiting after the handler terminates.

Lwt.pick behaves as the first thread in the list to terminate, and cancels the others.

Collaborative drawing application

(Client server communication)

In order to see what other users are drawing, we now want to do the following:

  • Send the coordinates to the server when the user draw a line, then
  • Dispatch the coordinates to all connected users.

We first declare a type, shared by the server and the client, describing the color (as RGB values) and coordinates of drawn lines.

[%%shared
  type messages =
    ((int * int * int) * int * (int * int) * (int * int))
    [@@deriving json]
]

We annotate the type declaration with [@@deriving json] to allow type-safe deserialization of this type. Eliom forces you to use this in order to avoid server crashes if a client sends corrupted data. This is defined using a JSON plugin for ppx_deriving, which you need to install. You need to do that for each type of data sent by the client to the server. This annotation can only be added on types containing exclusively basic types, or other types annotated with [@@deriving json].

Then we create an Eliom bus to broadcast drawing events to all client with the function Eliom_bus.create. This function take as parameter the type of values carried by the bus.

let bus = Eliom_bus.create [%derive.json: messages]

To write draw commands into the bus, we just replace the function line in init_client by:

let line ev =
  let v = compute_line ev in
  let _ = Eliom_bus.write ~%bus v in
  draw ctx v;
  Lwt.return () in

Finally, to interpret the draw orders read on the bus, we add the following line at the end of function init_client:

  Lwt.async (fun () -> Lwt_stream.iter (draw ctx) (Eliom_bus.stream ~%bus))

Now you can try the program using two browser windows to see that the lines are drawn on both windows.

Communication channels

Eliom provides multiple ways for the server to send unsolicited data to the client:

  • Eliom_bus.t are broadcasting channels where client and server can participate (see also «a_api project=”eliom” subproject=”client” | type Eliom_bus.t » in the client API).
  • Eliom_react allows sending React events from the server to the client, and conversely.
  • Eliom_comet.Channel.t are one-way communication channels allowing finer-grained control. It allows sending Lwt_stream to the client. Eliom_react and Eliom_bus are implemented over Eliom_coment.

    It is possible to control the idle behaviour with module Eliom_comet.Configuration.

Color and size of the brush

(Widgets with Ocsigen-widgets)

In this section, we add a color picker and slider to choose the size of the brush. For the colorpicker we used a widget available in Ocsigen-widgets.

To install Ocsigen widgets, do:

opam pin add ocsigen-widgets https://github.com/ocsigen/ocsigen-widgets.git
opam install ocsigen-widgets

In Makefile.options, created by Eliom’s distillery, add ocsigen-widgets.client to the CLIENT_PACKAGES:

CLIENT_PACKAGES := ... ocsigen-widgets.client

To create the widget, we add the following code in the init_client immediately after canvas configuration:

(* Color of the brush *)
let colorpicker = Ow_color_picker.create ~width:150 () in
Ow_color_picker.append_at (Dom_html.document##.body) colorpicker;
Ow_color_picker.init_handler colorpicker;

We subsequently add a simple HTML5 slider to change the size of the brush. Near the canvas_elt definition, simply add the following code:

let slider =
  Eliom_content.Html5.D.Form.input
    ~a:[
      Html5.D.a_id "slider";
      Html5.D.a_input_min 1.;
      Html5.D.a_input_max 80.
    ]
    ~input_type:`Range
    Html5.D.Form.int

Form.int is a typing information telling that this input takes an integer value. This kind of input can only be associated to services taking an integer as parameter.

We then add the slider to the page body, as follows:

let page =
  (html
    (head (title (pcdata "Graffiti")) [])
    (body [h1 [pcdata "Graffiti"];
           canvas_elt;
           div [slider]] ))

To change the size and the color of the brush, we replace the last line of the function compute_line in init_client by:

let rgb = Ow_color_picker.get_rgb colorpicker in
let size_slider = Eliom_content.Html5.To_dom.of_input ~%slider in
let size = int_of_string (Js.to_string size_slider##.value) in
(rgb, size, (oldx, oldy), (!x, !y))

Finally, we need to add a stylesheet in the headers of our page. To easily create the head HTML element, we use the function Eliom_tools.F.head:

let page =
  html
    (Eliom_tools.F.head ~title:"Graffiti"
       ~css:[
         ["css";"graffiti.css"];]
      ~js:[] ())
    (body [h1 [pcdata "Graffiti"]; canvas_elt; div [slider]])

You need to install the corresponding stylesheets and images into your project. The stylesheet files should go to the directory static/css. graffiti.css is a custom-made CSS file.

You can then test your application (make test.byte).

Ocsigen-widgets

Ocsigen-widgets is a Js_of_ocaml library providing useful widgets for your Eliom applications. You can use it for building complex user interfaces.

Sending the initial image

(Services sending other data types)

To finish the first part of the tutorial, we want to save the current drawing on server side and send the current image when a new user arrives. To do that, we will use the Cairo binding for OCaml.

For using Cairo, first, make sure that it is installed (it is available as cairo2 via OPAM). Second, add it to the SERVER_PACKAGES in your Makefile.options: SERVER_PACKAGES := ... cairo2

The draw_server function below is the equivalent of the draw function on the server side and the image_string function outputs the PNG image in a string.

let draw_server, image_string =

  let surface = Cairo.Image.create Cairo.Image.ARGB32 ~width ~height in
  let ctx = Cairo.create surface in

  let rgb_floats_from_ints (r, g, b) =
    float r /. 255., float g /. 255., float b /. 255. in

  ((fun (rgb, size, (x1, y1), (x2, y2)) ->

    (* Set thickness of brush *)
    Cairo.set_line_width ctx (float size) ;
    Cairo.set_line_join ctx Cairo.JOIN_ROUND ;
    Cairo.set_line_cap ctx Cairo.ROUND ;
    let r, g, b =  rgb_floats_from_ints rgb in
    Cairo.set_source_rgb ctx ~r ~g ~b ;

    Cairo.move_to ctx (float x1) (float y1) ;
    Cairo.line_to ctx (float x2) (float y2) ;
    Cairo.Path.close ctx ;

    (* Apply the ink *)
    Cairo.stroke ctx ;
   ),
   (fun () ->
     let b = Buffer.create 10000 in
     (* Output a PNG in a string *)
     Cairo.PNG.write_to_stream surface (Buffer.add_string b);
     Buffer.contents b
   ))

let _ = Lwt_stream.iter draw_server (Eliom_bus.stream bus)

We also define a service that sends the picture:

let imageservice =
  Eliom_registration.String.register_service
    ~path:["image"]
    ~get_params:Eliom_parameter.unit
    (fun () () -> Lwt.return (image_string (), "image/png"))

Eliom_registration

The module Eliom_registration defines several modules with registration functions for a variety of data types. We have already seen Eliom_registration.Html5 and Eliom_registration.App. The module Eliom_registration.String sends arbitrary byte output (represented by an OCaml string). The handler function must return a pair consisting of the content and the content-type.

There are also several other output modules, for example:

  • Eliom_registration.File to send static files
  • Eliom_registration.Redirection to create a redirection towards another page
  • Eliom_registration.Any to create services that decide late what they want to send
  • Eliom_registration.Ocaml to send any OCaml data to be used in a client side program
  • Eliom_registration.Action to create service with no output (the handler function just performs a side effect on the server) and reload the current page (or not). We will see an example of actions in the next chapter.

Loading the initial image

We now want to load the initial image once the canvas is created. Add the following lines just between the creation of the canvas context and the creation of the slider:

(* The initial image: *)
let img =
  Eliom_content.Html5.To_dom.of_img
    (img ~alt:"canvas"
       ~src:(make_uri ~service:~%imageservice ())
       ())
in
img##.onload := Dom_html.handler
    (fun ev -> ctx##drawImage img 0. 0.; Js._false);

You are then ready to try your graffiti-application by make test.byte.

Note, that the Makefile from the distillery automatically adds the packages defined in SERVER_PACKAGES as an extension in your configuration file local/etc/graffiti/graffiti-test.conf:

<extension findlib-package="cairo2" />

Ocsigen: step by step tutorial for client-server Web application (1/2)
Written by Vincent Balat on March 15, 2016

This post (and the following one) is a step by step tutorial about client-server Web applications in OCaml. You can find the full tutorial here. It introduces the basics of Web programming with OCaml: type-checking HTML, defining services, using lightweight threads, writing a client-server program …

We will write a collaborative drawing application. It is a client-server Web application displaying an area where users can draw using the mouse, and see what other users are drawing at the same time and in real-time.

The final eliom code is available for download on github. Git tag eliom-5.0 has been tested against Eliom 5.0.

The application is running online here.

Basics

To get started, we recommend using Eliom’s distillery, a program which creates scaffolds for Eliom projects. The following command creates a very simple project called graffiti in the directory graffiti:

$ eliom-distillery -name graffiti -template basic.ppx -target-directory graffiti

My first page

(Services, Configuration file, Static validation of HTML)

Our web application consists of a single page for now. Let’s start by creating a very basic page. We define the service that will implement this page by the following declaration:

open Eliom_content.Html5.D (* provides functions to create HTML nodes *)

let main_service =
  Eliom_registration.Html5.register_service
    ~path:["graff"]
    ~get_params:Eliom_parameter.unit
    (fun () () ->
      Lwt.return
        (html
           (head (title (pcdata "Page title")) [])
           (body [h1 [pcdata "Graffiti"]])))

If you are using eliom-distillery just replace the content of the eliom-file by the above lines and run

$ make test.byte

This will compile your application and run ocsigenserver on it. (Refer to the manual on how to compile your project “by hand”.)

Your page is now available at URL http://localhost:8080/graff.

Services

Unlike typical web programming techniques (CGI, PHP, …), with Eliom you do not need to write one file per URL. The application can be split into multiple files as per the developer’s style. What matters is that you eventually produce a single module (*.cmo or *.cma) for the whole website.

Module Eliom_service allows to create new entry points to your web site, called services. In general, services are attached to a URL and generate a web page. Services are represented by OCaml values, through which you must register a function that will generate a page.

Parameter ~path corresponds to the URL where you want to attach your service. It is a list of strings. The value ["foo"; "bar"] corresponds to URL foo/bar. ["dir"; ""] corresponds to URL dir/ (that is: the default page of the directory dir).

Configuration file

In the directory of the project created by the Eliom-distillery, you can find the file graffiti.conf.in. This file is used in conjunction with the variables in Makefile.options to generate the ocsigenserver configuration file.

Once you start up your application via make test.byte, the configuration file becomes available at local/etc/graffiti/graffiti-test.conf. It contains various directives for Ocsigen server (port, log files, extensions to be loaded, etc.), taken from Makefile.options, and something like:

<host>
  <static dir="static" />
  <eliommodule module="/path_to/graffiti.cma" />
  <eliom />
</host>

Line <eliommodule ... /> asks the server to load Eliom module graffiti.cma, containing the Eliom application, at startup and attach it to this host (and site).

Extensions <static ... /> (staticmod) and <eliom /> are called successively:

  • If they exist, files from the directory /path_to/graffiti/static will be served,
  • Otherwise, Server will try to generate pages with Eliom (<eliom />),
  • Otherwise it will generate a 404 (Not found) error (default).

Static validation of HTML

There are several ways to create pages for Eliom. You can generate pages as strings (as in other web frameworks). However, it is preferable to generate HTML in a way that provides compile-time HTML correctness guarantees. This tutorial achieves this by using module Eliom_content.​Html5.​D, which is implemented using the TyXML library. The module defines a construction function for each HTML5 tag.

Note that it is also possible to use the usual HTML syntax directly in OCaml.

The TyXML library (and thus Eliom_content.​Html5.​D) is very strict and compels you to respect HTML5 standard (with some limitations). For example if you write:

(html
   (head (title (pcdata "")) [pcdata ""])
   (body [pcdata "Hallo"]))

You will get an error message similar to the following, referring to the end of line 2:

Error: This expression has type ([> `PCDATA ] as 'a) Html5.elt
       but an expression was expected of type
         Html5_types.head_content_fun Html5.elt
       Type 'a is not compatible with type Html5_types.head_content_fun =
           [ `Base
           | `Command
           | `Link
           | `Meta
           | `Noscript of [ `Link | `Meta | `Style ]
           | `Script
           | `Style ]
       The second variant type does not allow tag(s) `PCDATA

where Html5_types.​head_content_fun is the type of content allowed inside <head> (<base>, <command>, <link>, <meta>, etc.). Notice that &lt;PCDATA (i.e. raw text) is not included in this polymorphic variant type.

Most functions take as parameter the list representing its contents. See other examples below. Each of them take un optional ?a parameter for optional HTML attributes. Mandatory HTML attributes correspond to mandatory OCaml parameters. See below for examples.

Lwt

Important warning: All the functions you write must be written in a cooperative manner using Lwt. Lwt is a convenient way to implement concurrent programs in OCaml, and is now also widely used for applications unrelated to Ocsigen.

For now we will just use the Lwt.return function as above. We will come back to Lwt programming later. You can also have a look at the Lwt programming guide.

Execute parts of the program on the client

(Service sending an application, Client and server code, Compiling a web application with server and client parts, Calling JavaScript methods with Js_of_ocaml)

To create our first service, we used the function Eliom_registration.​Html5.​register_service, as all we wanted to do was return HTML5. But we actually want a service that corresponds to a full Eliom application with client and server parts. To do so, we need to create our own registration module by using the functor Eliom_registration.App:

module Graffiti_app =
  Eliom_registration.App (struct
      let application_name = "graffiti"
    end)

It is now possible to use My_app for registering our main service (now at URL /):

let main_service =
  Graffiti_app.register_service
    ~path:[""]
    ~get_params:Eliom_parameter.unit
    (fun () () ->
      Lwt.return
        (html
           (head (title (pcdata "Graffiti")) [])
           (body [h1 [pcdata "Graffiti"]]) ) )

We can now add some OCaml code to be executed by the browser. For this purpose, Eliom provides a syntax extension to distinguish between server and client code in the same file. We start by a very basic program, that will display a message to the user by calling the JavaScript function alert. Add the following lines to the program:

let%client _ = Eliom_lib.alert "Hello!"

After running again make test.byte, and visiting http://localhost:8080/, the browser will load the file graffiti.js, and open an alert-box.

Splitting the code into server and client parts

At the very toplevel of your source file (i.e. not inside modules or other server- /client-parts), you can use the following constructs to indicate which side the code should run on.

  • [%%client ... ] : the list of enclosed definitions is client-only code (similarly for [%%server ... ]). With [%%shared ... ], the code is used both on the server and client.
  • let%client, let%server, let%shared: same as above for a single definition.
  • [%%client.start], [%%server.start], [%%shared.start]: these set the default location for all definitions that follow, and which do not use the preceding constructs.

If no location is specified, the code is assumed to be for the server.

The above constructs are implemented by means of PPX, OCaml’s new mechanism for implementing syntax extensions. See Ppx_eliom for details.

Client parts are executed once, when the client side process is launched. The client process is not restarted after each page change.

In the Makefile created by the distillery, we automatically split the code into client and server parts, compile the server part as usual, and compile the client part to a JavaScript file using js_of_ocaml.

Client values on the server

Additionally, it is possible to create client values within the server code by the following quotation:

[%client (expr : typ) ]

where typ is the type of an expression expr on the client. Note, that such a client value is abstract on the server, but becomes concrete, once it is sent to the client with the next request.

(typ can be ommitted if it can be inferred from the usage of the client value in the server code.)

Client values are executed on the client after the service returns. You can use client values when a service wants to ask the client to run something, for example binding some event handler on some element produced by the service.

Js_of_ocaml

The client-side parts of the program are compiled to JavaScript by js_of_ocaml. (Technically, js_of_ocaml compiles OCaml bytecode to JavaScript.) It is easy to bind JavaScript libraries so that OCaml programs can call JavaScript functions. In the example, we are using the Dom_html module, which is a binding that allows the manipulation of an HTML page.

Js_of_ocaml is using a syntax extension to call JavaScript methods:

  • obj##m a b c to call the method m of object obj with parameters a, b, c,
  • obj##.m to get a property,
  • obj##.m := e to set a property, and
  • new%js constr a b c to call a JavaScript constructor.

More information can be found in the Js_of_ocaml manual, in the module Ppx_js.

Accessing server side variables on client side code

(Executing client side code after loading a page, Sharing server side values, Converting an HTML value to a portion of page (a.k.a. Dom node), Manipulating HTML node ‘by reference’)

The client side process is not strictly separated from the server side. We can access some server variables from the client code. For instance:

let count = ref 0

let main_service =
  Graffiti_app.register_service
    ~path:[""]
    ~get_params:Eliom_parameter.unit
    (fun () () ->
       let c = incr count; !count in
       ignore [%client
         (Dom_html.window##alert
            (Js.string
               (Printf.sprintf "You came %i times to this page" ~%c))
          : unit)
       ];
       Lwt.return
         (html
            (head (title (pcdata "Graffiti")) [])
            (body [h1 [pcdata "Graffiti"]])))

Here, we are increasing the reference count each time the page is accessed. When the page is loaded and the document is in-place, the client program initializes the value inside [%client ... ], and thus triggers an alert window. More specifically, the variable c, in the scope of the client value on the server is made available to the client value using the syntax extension ~%c. In doing so, the server side value c is displayed in a message box on the client.

###Injections: Using server side values in client code

Client side code can reference copies of server side values using syntax ~%variable. Values sent that way are weakly type checked: the name of the client side type must match the server side one. If you define a type and want it to be available on both sides, declare it in [%%shared ... ]. The Eliom manual provides more information on the Eliom’s syntax extension and its compilation process.

Note that the value of an injection into a [%%client ... ] section is sent only once when starting the application in the browser, and not synced automatically later. In contrast, the values of injections into client values which are created during a request are sent alongside the next response.

Next week

In next tutorial, we will turn the program into a collaborative drawing application, and learn:

  • How to draw on a canvas,
  • How to program mouse events with js_of_ocaml,
  • More about Lwt,
  • How to create communication channels with the server
  • How to create other types of services

The impatient can find the full tutorial here.

Ocsigen: client-server widgets
Written by Vincent Balat on February 22, 2016

This short tutorial is an example of client-server Eliom application. It gives an example of client-server widgets. You can find the original version of this tutorial (and many others) here.

It is probably a good starting point if you know OCaml well, and want to quickly learn how to write a client-server Eliom application with a short example and concise explanations. For more detailed explanations, see the “Graffiti” tutorial, or read the manuals.

The goal is to show that, unlike many JavaScript libraries that build their widgets programmatically (by instantiating classes or calling functions), Eliom enables server-side widget generation, before sending them to the client. Pages can thus be indexed by search engines.

This tutorial also shows that it is possible to use the same code to build the widget either on client or server side.

We choose a very simple widget, that could be the base for example for implementing a drop-down menu. It consists of several boxes with a title and a content. Clicking on the title opens or closes the content. Furthermore, it is possible to group some of the boxes together to make them behave like radio buttons: when you open one of them, the previously opened one is closed.

Screenshot

First step: define an application with a basic service

The following code defines a client-server Web application with only one service, registered at URL / (the root of the website).

The code also defines a client-side application (section [%%client ... ]) that appends a client-side generated widget to the page. Section [%%shared ... ] is compiled on both the server and client side programs. Alternatively, you can write let%client, let%server or let%shared (default) to define values on client side, on server side, or on both sides.

[%%shared
    open Eliom_content
    open Html5
    open Html5.D
]

module Ex_app =
  Eliom_registration.App (struct let application_name = "ex" end)

let _ =
  Ex_app.register_service ~path:[] ~get_params:Eliom_parameter.unit
    (fun () () ->
       Lwt.return
         (Eliom_tools.D.html ~title:"ex" ~css:[["css"; "ex.css"]]
            (body [h2 [pcdata "Welcome to Ocsigen!"]])))

[%%client
let mywidget s1 s2 =
  let button  = div ~a:[a_class ["button"]] [pcdata s1] in
  let content = div ~a:[a_class ["content"]] [pcdata s2] in
  div ~a:[a_class ["mywidget"]] [button; content]

let _ =
  let%lwt _ = Lwt_js_events.onload () in
  Dom.appendChild
    (Dom_html.document##.body)
    (To_dom.of_element (mywidget "Click me" "Hello!"));
  Lwt.return ()
]

To compile it, first create a project by calling

eliom-distillery -name ex -template basic.ppx

The name of the project must match the name given to the functor Eliom_registration.App.

After you adapt the file ex.eliom, you can compile by calling make, and run the server by calling make test.byte. Download the CSS file and place it in directory static/css. Then open a browser window and go to URL http://localhost:8080.

Screenshot:

Screenshot

More explanations

This section gives very quick explanations on the rest of the program. For more detailed explanations, see the tutorial for the graffiti app or the manual of each of the projects.

  • The client side program is sent with the first page belonging to the application (registered through module Ex_app).
  • The ## is used to call a JS method from OCaml and ##. to access a JS object field (See Js_of_ocaml’s documentation: Ppx_js).
  • If there are several services in your application, the client-side program will be sent only with the first page, and will not stop if you go to another page of the application.
  • Lwt is the concurrent library used to program threads on both client and server sides. The syntax let%lwt a = e1 in e2 allows waiting (without blocking the rest of the program) for an Lwt thread to terminate before continuing. e2 must ben a Lwt thread itself. Lwt.return enables creating an already-terminated Lwt thread.
  • Lwt_js_events defines a convenient way to program interface events (mouse, keyboard, …). For example, Lwt_js_events.onload is a Lwt thread that waits until the page is loaded. There are similar functions to wait for other events, e.g., for a click on an element of the page, or for a key press.

Second step: bind the button

To make the widget work, we must bind the click event. Replace function mywidget by the following lines:

let%client switch_visibility elt =
  let elt = To_dom.of_element elt in
  if Js.to_bool (elt##.classList##contains (Js.string "hidden")) then
    elt##.classList##remove (Js.string "hidden")
  else
    elt##.classList##add (Js.string "hidden")

let%client mywidget s1 s2 =
  let button  = div ~a:[a_class ["button"]] [pcdata s1] in
  let content = div ~a:[a_class ["content"]] [pcdata s2] in
  Lwt.async (fun () ->
    Lwt_js_events.clicks (To_dom.of_element button)
      (fun _ _ -> switch_visibility content; Lwt.return ()));
  div ~a:[a_class ["mywidget"]] [button; content]
  • Once again, we use Lwt_js_events. Function clicks is used to bind a handler to clicks on a specific element.
  • Function async runs an Lwt thread asynchronously (without waiting for its result).
  • Lwt_js_events.clicks elt f calls function f for each mouseclick on element elt.
  • To_dom.of_element, Js.string and Js.to_bool are conversion functions between OCaml values and JS values.

Third step: Generating the widget on server side

The following version of the program shows how to generate the widget on server side, before sending it to the client.

The code is exactly the same, with the following modifications:

  • We place function mywidget out of client section.
  • The portion of code that must be run on client side (binding the click event) is written as a client value, inside [%client (... : unit) ]. This code will be executed by the client-side program when it receives the page. Note that you must give the type (here unit), as the type inference for client values is currently very limited. The client section may refer to server side values, using the ~%x syntax. These values will be serialized and sent to the client automatically with the page.
  • We include the widget on the server side generated page instead of adding it to the page from client side.
[%%shared
    open Eliom_content
    open Html5
    open Html5.D
]

module Ex_app =
  Eliom_registration.App(struct let application_name = "ex" end)

let%client switch_visibility elt =
  let elt = To_dom.of_element elt in
  if Js.to_bool (elt##.classList##(contains (Js.string "hidden"))) then
    elt##.classList##remove (Js.string "hidden")
  else
    elt##.classList##add (Js.string "hidden")

let mywidget s1 s2 =
  let button  = div ~a:[a_class ["button"]] [pcdata s1] in
  let content = div ~a:[a_class ["content"]] [pcdata s2] in
  let _ = [%client
    (Lwt.async (fun () ->
       Lwt_js_events.clicks (To_dom.of_element ~%button)
         (fun _ _ -> switch_visibility ~%content; Lwt.return ()))
     : unit)
  ] in
  div ~a:[a_class ["mywidget"]] [button; content]

let _ =
  Ex_app.register_service ~path:[] ~get_params:Eliom_parameter.unit
    (fun () () ->
       Lwt.return
         (Eliom_tools.D.html ~title:"ex" ~css:[["css"; "ex.css"]]
            (body [h2 [pcdata "Welcome to Ocsigen!"];
                   mywidget "Click me" "Hello!"])))

Fourth step: widget usable either on client or server sides

If you make function mywidget shared, it will be available both on server and client sides:

let%shared mywidget s1 s2 =
  ...

Screenshot:

Screenshot

Fifth step: close last window when opening a new one

To implement this, we record a client-side reference to a function for closing the currently opened window.

[%%shared
    open Eliom_content
    open Html5
    open Html5.D
]

module Ex_app =
  Eliom_registration.App (struct let application_name = "ex" end)

let%client close_last = ref (fun () -> ())

let%client switch_visibility elt =
  let elt = To_dom.of_element elt in
  if Js.to_bool (elt##.classList##(contains (Js.string "hidden"))) then
    elt##.classList##remove (Js.string "hidden")
  else
    elt##.classList##add (Js.string "hidden")

let%shared mywidget s1 s2 =
  let button  = div ~a:[a_class ["button"]] [pcdata s1] in
  let content = div ~a:[a_class ["content"; "hidden"]] [pcdata s2] in
  let _ = [%client
    (Lwt.async (fun () ->
       Lwt_js_events.clicks (To_dom.of_element ~%button)
         (fun _ _ ->
            !close_last();
            close_last := (fun () -> switch_visibility ~%content);
            switch_visibility ~%content; Lwt.return ()))
     : unit)
  ] in
  div ~a:[a_class ["mywidget"]] [button; content]

let _ =
  Ex_app.register_service ~path:[] ~get_params:Eliom_parameter.unit
    (fun () () ->
       let _ = [%client
         (Dom.appendChild
            (Dom_html.document##.body)
            (To_dom.of_element (mywidget "Click me" "client side"))
          : unit)
       ] in
       Lwt.return
         (Eliom_tools.D.html ~title:"ex" ~css:[["css"; "ex.css"]]
            (body [
               h2 [pcdata "Welcome to Ocsigen!"];
               mywidget "Click me" "server side";
               mywidget "Click me" "server side";
               mywidget "Click me" "server side"
             ])))

Last step: several sets of widgets

Now we want to enable several sets of widgets in the same page. A single reference no longer suffices. In the following version, the server-side program asks the client-side program to generate two different references, by calling function new_set. This function returns what we call a client value. Client values are values of the client side program that can be manipulated on server side (but not evaluated). On server side, they have an abstract type.

[%%shared
    open Eliom_content
    open Html5
    open Html5.D
]

module Ex_app =
  Eliom_registration.App (struct let application_name = "ex" end)

let new_set () = [%client (ref (fun () -> ()) : (unit -> unit) ref)]

let%client switch_visibility elt =
  let elt = To_dom.of_element elt in
  if Js.to_bool (elt##.classList##(contains (Js.string "hidden"))) then
    elt##.classList##remove (Js.string "hidden")
  else
    elt##.classList##add (Js.string "hidden")

let%shared mywidget set s1 s2 =
  let button  = div ~a:[a_class ["button"]] [pcdata s1] in
  let content = div ~a:[a_class ["content"; "hidden"]] [pcdata s2] in
  let _ = [%client
    (Lwt.async (fun () ->
       Lwt_js_events.clicks (To_dom.of_element ~%button)
         (fun _ _ ->
            ! ~%set();
            ~%set := (fun () -> switch_visibility ~%content);
            switch_visibility ~%content; Lwt.return ()))
     : unit)]
  in
  div ~a:[a_class ["mywidget"]] [button; content]

let _ =
  Ex_app.register_service ~path:[] ~get_params:Eliom_parameter.unit
    (fun () () ->
       let set1 = new_set () in
       let set2 = new_set () in
       let _ = [%client
         (Dom.appendChild
            (Dom_html.document##.body)
            (To_dom.of_element (mywidget ~%set2 "Click me" "client side"))
          : unit)
       ] in
       Lwt.return
         (Eliom_tools.D.html ~title:"ex" ~css:[["css"; "ex.css"]]
            (body [
               h2 [pcdata "Welcome to Ocsigen!"];
               mywidget set1 "Click me" "server side";
               mywidget set1 "Click me" "server side";
               mywidget set2 "Click me" "server side"
             ])))

Screenshot:

Screenshot

And now?

Calling server functions

An important feature missing from this tutorial is the ability to call server functions from the client-side program (“server functions”). You can find a quick description of this in this mini HOWTO or in Eliom’s manual.

Services

For many applications, you will need several services. By default, client-side Eliom programs do not stop when you follow a link or send a form. This enables combining rich client side features (playing music, animations, stateful applications …) with traditional Web interaction (links, forms, bookmarks, back button …). Eliom proposes several ways to identify services, either by the URL (and parameters), or by a session identifier (we call this kind of service a coservice). Eliom also allows creating new (co-)services dynamically, for example coservices depending on previous interaction with a user. More information on the service identification mechanism in Eliom’s manual.

Sessions

Eliom also offers a rich session mechanism, with scopes (see Eliom’s manual).

Ocsigen, the basics
Written by Vincent Balat on February 08, 2016

Following last week release, I’m starting today a series of tutorials about the Ocsigen framework. For the impatient, most of these tutorials are already available on Ocsigen’s Web site.

In this first tutorial, we show how to use the Ocsigen framework (mainly Eliom) to write a lightweight Web site by generating pages using OCaml functions. Even though Eliom makes it possible to write complete client-server Web and mobile apps, you can still use Eliom even if you don’t need all these features (for example if you don’t want HTML type checking or client side features). Besides, this will allow you to extend your Web site in a full Web application if you need, later on. This tutorial is also a good overview of the basics of Eliom.

A service generating a page

The following code shows how to create a service that answers requests at URL http://.../aaa/bbb, by invoking an Ocaml function f of type:

f : (string * string) list -> unit -> string Lwt.t

Function f generates HTML as a string, taking as argument the list of URL parameters (GET parameters).

let f _ () =
  Lwt.return "<html><head><title>A</title></head><body>B</body></html>"

let main_service =
  Eliom_registration.Html_text.register_service
    ~path:["aaa"; "bbb"]
    ~get_params:Eliom_parameter.any
    f

Eliom_paramer.any means that the service takes any GET parameter.

We recommend to use the program eliom-distillery to generate a template for your application (a Makefile and a default configuration file for Ocsigen Server).

$ eliom-distillery -name mysite -template basic.ppx -target-directory mysite

Put the piece of code above in file mysite.eliom, compile and run the server by doing:

$ make test.byte

Your page is now available at URL http://localhost:8080/aaa/bbb.

If you dont want to use the Makefile provided by eliom-distillery, just replace mysite.eliom by a file mysite.ml, compile and run with

$ ocamlfind ocamlc -package eliom.server -thread -c mysite.ml
$ ocsigenserver -c mysite.conf

where mysite.conf is adapted from local/etc/mysite/mysite-test.conf by replacing mysite.cma by your cmo.

POST service

Services using the POST HTTP method are created using the function Eliom_service.​Http.​post_service. To create a service with POST parameters, first you must create a service without POST parameters, and then the service with POST parameters, with the first service as fallback. The fallback is used if the user comes back later without POST parameters, for example because he put a bookmark on this URL.

let g getp postp = Lwt.return "..."

let post_service =
  Eliom_registration.Html_text.register_post_service
    ~fallback:main_service
    ~post_params:Eliom_parameter.any
    g

Going further

That is probably all you need for a very basic Web site in OCaml. But Ocsigen provides many tools to write more advanced Web sites and applications:

Instead of generating HTML in OCaml strings, we highly recommend to use typed HTML. It is very easy to use, once you have learned the basics, and helps a lot to efficiently write modular and valid HTML. To do this, use module Eliom_registration.Html5 instead of Eliom_registration.Html_text. See this tutorial for more information, a comprehensive documentation here, and a more advanced manual here.

Have a look at Eliom’s API documentation to see other kinds of services, for example Eliom_registration.Redirection to create HTTP redirections.

Eliom also has a way to typecheck forms and GET or POST parameters. By giving a description of the parameters your service expects, Eliom will check their presence automatically, and convert them for you to OCaml types. See this tutorial and this manual page.

Eliom also has other ways to identify services (besides just the PATH in the URL). For example Eliom can identify a service just by a parameter (whatever the path is). This is called non-attached coservices and this makes it possible for instance to have the same feature on every page (for example a connection service). See this tutorial and this manual page.

One of the main features of Eliom is the ability to write complete Web and mobile applications in OCaml. Annotations are used to separate the code to be executed server-side from the client code. Client functions are translated into Javascript using Ocsigen Js_of_ocaml. See this tutorial for a quick introduction, or this one for a more comprehensive one. You can also have a look at this manual page.

Another interesting feature of Eliom is its session model, that uses a very simple interface to record session data server-side. It is even possible to choose the scope of this data: either a browser, or a tab, or even a group of browsers (belonging for instance to a same user). See this section and the beginning of this manual page.

We suggest to continue your reading by one of these tutorials:

January 2016 Ocsigen releases
Written by The Ocsigen team on February 01, 2016

We are excited to announce the releases of

These releases are the result of many months of work by the Ocsigen team, and bring a range of improvements.

PPX

Eliom 5.0 comes with a PPX-based language (for OCaml 4.02.x). This follows our PPX extensions for js_of_ocaml and Lwt. The new syntax is more flexible than our previous Camlp4-based one, and we recommend it for new projects. Nevertheless, the Camlp4-based syntax remains available.

Shared reactive programming

Recent versions of Eliom provided client-side support for (functional) reactive programming. Eliom 5.0 additionally supports “shared” (client-server) reactive programming, where the reactive signals have meaning both on the server and the client. This means that the initial version of the page is produced (on the server) with the same code that takes care of the dynamic updates (on the client).

Enhanced js_of_ocaml library

The js_of_ocaml library provides additional bindings for established JavaScript APIs. This includes

A new JavaScript-specific table module is also available.

ppx_deriving

js_of_ocaml provides a new JSON plugin for ppx_deriving. This can be used for serializing OCaml data structures to JSON in a type-safe way. The plugin remains compatible with its Camlp4-based predecessor with respect to the serialization format.

Under the hood

In addition to providing various fixes, we have improved the performance of various Ocsigen components. Notably:

Community

The Ocsigen team always welcomes your feedback and contributions. Stay in touch via GitHub and our mailing list!

TodoMVC: a reactive version
Written by Stéphane Legrand on October 07, 2015

TodoMVC is a project which offers the same Todo application implemented using MV* concepts in most of the popular JavaScript MV* frameworks. One of the aims of TodoMVC is to enable a fair comparison between several frameworks, by providing implementations of the same application. A js_of_ocaml (JSOO) version is now available:

Our version is powered by the React module for functional reactive programming (FRP).

In this post, we outline the architecture of our implementation, with a particular emphasis on how it applies MVC and FRP concepts.

MVC

MVC, which stands for Model-View-Controller, is a software architecture very commonly used for implementing user interfaces. MVC divides an application into three components:

  • the Model manages the data, logic and rules of the application;

  • the Controller manages events from the view, and accordingly updates the model;

  • the View generates an output presentation (a web page for instance) based on the model data.

For the Todo application, we have three corresponding OCaml modules. Model mainly contains the task list and the new task field value. It uses Deriving_Json to convert the data to JSON and vice versa, in order to be able to save and restore the application state. This module is otherwise written with basic OCaml code. Controller produces new models according to the actions it receives. Whenever a new model is built, the model becomes the new reactive signal value. We will elaborate on this point later. View builds the HTML to display the page. It receives as input the dynamic data from the model. The HTML also contains the event management code needed to emit the corresponding actions.

Besides these three MVC modules, the application uses three helpers. Storage contains the functions to read and write a string value in the browser local storage. This module is used to save and restore the application data in JSON format. Action contains all the actions available from the user interface. ReactList contains a single function to ease the creation of a reactive list via the ReactiveData library.

React

React is an OCaml module for functional reactive programming (FRP). In our TodoMVC example, React provides a way to automatically refresh the view whenever a new model is built by the controller. To achieve this goal, the application uses a reactive signal which carries the model values (which vary over time). The model value may initially be equal to the empty model. When this value is modified by the controller, i.e., after a new model has been generated, the view automatically refreshes its reactive parts.

Mixing MVC and FRP

The following figure shows what happens when the user interacts with the application, e.g., by adding a new task, or by clicking on a checkbox to select a specific task:

MVC with `React`

  1. the view sends the action to the controller;

  2. the controller gets the current model from the reactive signal, and builds a new model accordingly to the action;

  3. the controller sets this new model as the new reactive signal value;

  4. the view reacts to the newly-available model (new signal value) and updates itself with the corresponding data.

We proceed to describe our implementation of the above scheme, with an emphasis on the reactive features.

Initialization

The main function creates the reactive signal with an initial (possibly empty) model. The m value is of type Model.t:

let rp = React.S.create m in (* ... *)

React.S.create returns a tuple, the first part of which is a primitive signal; the second part is a function used by the controller to set a new model as the new signal value.

Reactive attribute

We first explain how the CSS style of a HTML node becomes reactive. In the Todo application, the task list is displayed in a <section> HTML tag. The CSS style of this HTML node must contain visibility: hidden; if the tasks list is empty, and visibility: visible; otherwise (i.e., if the number of tasks is greater than zero). The style attribute of this <section> node must therefore change according to the model content:

R.Html5.a_style (React.S.map css_visibility r)

We use the Tyxml_js module to safely build the HTML code. The first thing to note is that we use the reactive R.Html5 submodule, not the plain Html5 submodule. The a_style function implements a reactive attribute; it expects a reactive signal as its argument. Here we use React.S.map, which has the signature ('a -> 'b) -> 'a React.signal -> 'b React.signal. The first argument to map is the css_visibility function:

let css_visibility m =
  let tasks = m.Model.tasks in
  match tasks with
  | [] -> "visibility: hidden;"
  | _ -> "visibility: visible;"

As you can see, css_visibility receives a model m as its argument. When wrapped by React.S.map as above, css_visibility operates on signals. The function returns the right style, depending on whether the list of tasks is empty or not.

The second argument to React.S.map is the value named r, which is the primitive signal. r is the first value returned by the React.S.create function.

Each time the signal value gets updated by the controller, the css_visibility function is automatically called with the new signal value (a new model) as its argument, and the style attribute is automatically modified.

Reactive list

Reactive attributes alone would not suffice to build a user interface. We also need a reactive list of child nodes. Such a list is for example needed to display the task list. (The source code section is the same as for the first example.) It is a list of <li> nodes contained in a <ul> node. We accordingly have a reactive node, as follows:

R.Html5.ul ~a:[a_class ["todo-list"]] rl

As before, we use the R.Html5 module. This time we do not use R.Html5 to build an attribute, but rather a (<ul>) node. rl contains the node’s children:

let rl = ReactList.list (React.S.map visible_tasks r)

We create the reactive list via the helper module ReactList. As for the previous example, we use React.S.map to build a reactive signal, r being again the primitive signal. The visible_tasks function generates the <li> elements from the task list, filtered by the current selected visibility:

let visible_tasks m =
  let visibility = m.Model.visibility in
  let is_visible todo =
    match visibility with
    | Model.Completed -> todo.Model.completed
    | Active -> not todo.completed
    | All -> true
  in
  let tasks = List.filter is_visible m.Model.tasks in
  List.rev (List.fold_left (todo_item (r, f)) [] tasks)

Following the same principle as for the reactive attribute, each time the signal value gets updated by the controller, the <li> nodes are automatically refreshed.

Signal typing

You may have noticed that the code includes the following types:

type rs = Model.t React.signal
type rf = ?step:React.step -> Model.t -> unit
type rp = rs * rf

These types are used whenever type annotations are required, e.g., for the update function from the Controller module:

let update a ((r, f) : rp) = (* ... *)

Comparison with the Elm implementation

Elm is a functional programming language dedicated to frontend web application development. Elm was designed by Evan Czaplicki. The language should feel familiar to OCaml programmers.

Our TodoMVC example is based on the Elm implementation, which follows the structure used in all Elm programs: a model, an update function, and a view. Like Elm, our example uses the functional reactive programming style, enabled in our case by the React library and the reactive modules Tyxml_js.R and ReactiveData.

Conclusion

The combination of OCaml, js_of_ocaml, and functional reactive programming provides a killer feature combination for building rich web clients. Additionally, OCaml static typing can provide compile-time HTML validity checking (via TyXML), thus increasing reliability.

Summer Ocsigen releases
Written by Gabriel Radanne on August 17, 2015

We are happy to announce the releases of

We also welcome a new member in the ocsigen team, Vasilis Papavasileiou.

Key changes in the various releases:

  • PPX support for js_of_ocaml with OCaml >= 4.02.2. See documentation here.

    This was also the occasion to introduce a new syntax for object literals, and to improve the Camlp4 syntax (w.r.t. to locations). Both syntaxes emit the same code, and are perfectly compatible.

  • Support for dynlink in js_of_ocaml.

  • Logging improvements in Eliom and Server, in particular on the client side.

  • A healthy amount of bugfixes.

The next releases will probably see major changes. The current plan is:

  • Replace Server’s internals with cohttp, as part of our move towards Mirage-compatible libraries. See here.

  • Shared_react, which allows to build reactive pages from server side. See here.

  • PPX for Eliom.

  • Support for async/core in js_of_ocaml.

Have fun with Ocsigen!

Welcome to the Ocsigen Blog!
Written by The Ocsigen Team on July 29, 2015

The Ocsigen project finally has a blog. We are planning to publish news from the wider Ocsigen community, tutorials, and more.

Ocsigen encompasses the building blocks that you need in order to efficiently develop Web applications in OCaml. Among other libraries and tools, Ocsigen provides:

  • js_of_ocaml, which is a compiler from OCaml to JavaScript;

  • Ocsigen Server, which is a web server implemented in OCaml;

  • Lwt, which is a cooperative thread library for OCaml;

  • TyXML, which is a library for generating valid HTML and SVG content; last but not least,

  • Eliom, which puts everything together to provide a modern language for developing web applications, with tight integration between client and server.

Happy hacking, and stay tuned!