{0 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
{{!page-"mobile-apps"}mobile applications chapter}
of this manual.

{1 Service creation and registering}

As described in the chapter {{!page-"server-services"}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:

{@ocaml[
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:

{@ocaml[
let%shared () =
  Eliom_registration.Html.register s
    (fun () () ->
       Lwt.return
         (Eliom_tools.F.html
            ~title:"hybrid"
            Html.F.(body [
              h1 [txt "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.

{1 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.
