Client-side services

Starting with Eliom 6.0, services can have client-side handlers. Registering client-side handlers for services allows us to perform most of the operations (e.g., building the user interface) locally, and only call the server for operations that are by necessity non-local (e.g., retrieving database data).

Client-side service implementation is required for building mobile applications with Eliom, but can also be used to change page faster within a Web application. In this manual chapter, we focus on the client-side service mechanics and do not go into the details of setting up a complete mobile application. The complete setup needed is discussed in the mobile applications chapter of this manual.

Service creation and registering

As described in the chapter on server-side services, services are first created via Eliom_service.​create and similar functions, and subsequently registered.

The first step (creation) can only happen on the server; allowing the opposite would permit "creating" on the client services that are not actually provided by the server. To allow client-side service manipulation, services can be injected, as demonstrated by the following example:

let%server s =
  Eliom_service.create
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    ~path:(Eliom_service.Path ["content"])
    ()

let%client s = ~%s

The above style makes the service available under the same identifier (here s) on both sides. Subsequently, the service can be registered on both sides with the same Eliom_registration APIs. For example:

let%shared () =
  Eliom_registration.Html.register s
    (fun () () ->
       Lwt.return
         (Eliom_tools.F.html
            ~title:"hybrid"
            Html.F.(body [
              h1 [pcdata "Salut !"];
            ])))

The types of the handlers are compatible between the two sides. For instance, Eliom_registration.​Html expects a function that produces a Html_types.html Eliom_content.Html.D.elt Lwt.t, for Eliom_registration.​Action we must return unit Lwt.t, and so on. The behavior of all services is compatible to the extent possible, e.g., actions perform a reload after performing their side effect.

For application services, the Eliom_registration.​App functor needs to be called just like on the server. The signatures are compatible between the two sides, and therefore the functor invocation can happen in a shared section.

A service registered as above can be called via links (e.g., Eliom_content.Html.D.a) and forms just like a standard server-only service. Eliom detects the existence of a client-side implementation and calls that instead of performing a request to the server. If no client-side implementation exists, a standard server request is performed, which may cause problems in the context of mobile applications.

Service routing

Service routing is the operation of choosing a service based on a URL and a collection of POST parameters. This is clearly a key operation on the server, allowing Eliom to respond on different paths. Routing has also become available on the client via the function Eliom_client.​change_page_uri. This function can be used for example in order to open a link inside a mobile application without launching the Web browser.