
# Implementing Web Interaction Using Eliom

*The code of this tutorial has been tested with Eliom 6\.0.* <br/>

This chapter of the tutorial explains how to create a small web site with several pages, users, sessions, and other elements of classical web development. Then, in `another tutorial`, we will incorporate the features of this site into our Graffiti application, to demonstrate that we can combine this kind of interaction with client-side programs.

We assume you have read at least the first section of the previous chapter, which explained how to create a service and constuct valid HTML pages.

We will create a simple web site with one main page and a page for each user (assuming we have several users already created). Then we will add a login/connection form. We will also add a registration form, in order to learn how to create *dynamically* new services, and why it is very useful.

The [full code](https://github.com/ocsigen/tutorial/tree/master/files/tutorial/chapter2) of the program can be downloaded.


## Services


### The main page

Let's start again from scratch with the following site.

```ocaml

let main_service = Eliom_content.Html.D.(
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path [""])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    (fun () () ->
      Lwt.return
        (html (head (title (txt "")) [])
           (body [h1 [txt "Hello"]])))
)
```
Note that we are using `Eliom_registration.Html`, as we are not building a client side program for now.

For the same reason, you may want to remove the `.eliom`\-file generated by the distillery and put the code into an `.ml`\-file. But don't forget to add it to the server files in the `Makefile.options`:

```makefile
SERVER_FILES := tuto.ml
```

### Adding a page for each user

<!--wodoc:aside class="concepts"-->**Concepts**

Services with parameters<br/> Using parts of the path as parameters

<!--wodoc:end-->
We will now create a page for each user. To do this, we will create a new service, taking the user name as parameter:

```ocaml
let user_service = Eliom_content.Html.D.(
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path [""])
    ~meth:(Eliom_service.Get (Eliom_parameter.string "name"))
    (fun name () ->
      Lwt.return
        (html (head (title (txt name)) [])
           (body [h1 [txt name]])))
)
```
Add these lines to the same file, compile, start the server and verify that everything is working by trying, for example: `http://localhost:8080/?name=toto`.

<!--wodoc:aside class="concept"-->**Concept: Paths**

Note that we are using the same path as the first service. Eliom will automatically call the right service according to the parameters given in the request.

<!--wodoc:end-->
<!--wodoc:aside class="concept"-->**Concept: Services with parameters**

To define a service that accepts parameters in the URL (GET parameters), just add a description of the parameters you want in the `~meth` argument of the `Eliom_service.create` function. In our example, the service is expecting a parameter called `name`, of type `string`.

The handler function (function implementing the service) always takes two parameters:

- The first one corresponds to GET parameters (in our example, a string).
- The second one corresponds to parameters that are sent in the body of the HTTP request (POST parameters). We will see soon how to make services with POST parameters.
The module `Eliom_parameter` defines the possible parameter types. For example if you write:

```
~meth:(Eliom_service.Get (Eliom_parameter.int "i"))
```
Eliom will try to find a parameter called `i` and to translate it into an `int`. In that case, the handler function will accept an `int` as the first parameter.

If you want to accept several parameters, you can do, for example:

```
~meth:(Eliom_service.Get Eliom_parameter.(int "i" ** string "s"))
```
In that case, the handler function takes a pair of type `(int * string)`.

*Warning:* The operator `**` is an infix *binary* operator. It will always create pairs, and not triples or other tuples.

The module `Eliom_parameter` also defines other parameter types: for example floats, 64 bits integers, sum types, but also more complex types, like sets or lists of values. It is also possible to define your own parameter types.

<!--wodoc:end-->
For our program, we would prefer to take one part of the URL path as the parameter describing the name of the user. To achieve this we change the definition of the previous service this way:

```ocaml
let user_service =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["users"])
    ~meth:(Eliom_service.Get (
      Eliom_parameter.(suffix (string "name"))))
    (fun name () -> ... )
```
The user pages are now available at URLs <!--wodoc:span class="code"-->http://localhost:8080/users/*username*<!--wodoc:end-->.

<!--wodoc:aside class="concept"-->**Concept: Using parts of the path as page parameters**

The module `Eliom_parameter` makes it possible to use parts of the path as service (GET) parameters.

In addition to `Eliom_parameter.suffix`, there are many other values allowing you to specify your expected parameters: for example, you may access the full suffix as a string, as a list of string, or you may want to mix suffix parameters with standard GET parameters. You can also accept, as parameters, parts of the path that are not a suffix of the path (using `Eliom_parameter.const`). See more information on suffixes in [Eliom's manual](https://ocsigen.org/eliom/latest/server-params.html#suffixes).

*Warning:* Even if it is not displayed in the URL, suffix parameters have a parameter name. This allows one to make forms that point to those kind of services. Actually each "suffix service" has an equivalent without suffix (which is by default automatically redirected towards the suffix version if it is a GET request).

<!--wodoc:end-->

### Links

<!--wodoc:aside class="concepts"-->**Concepts**

Links <br/> Database libraries <!--wodoc:end-->

We now want to add a link on each user page to go back to the main page.

Change the handler of `user_service` into:

```ocaml
(fun name () -> Lwt.return
  (html
    (head (title (txt name)) [])
    (body [h1 [txt name];
           p [a ~service:main_service [txt "Home"] ()]])))
```
<!--wodoc:aside class="concept"-->**Concept: Creating hyperlinks**

The function `val
Eliom_content.Html.D.a` accepts the following parameters:

- the service
- the content of the link
- URL parameters to be given to the service
Thus, you don't have to know the precise URL of the service you want to link to, and if the URL changes, all links will remain valid. Using this function has a wonderful consequence: *You will never have broken links\!*

<!--wodoc:end-->

#### Links towards services with parameters

In our example above, the last parameter is `()` because the service does not expect any parameter. If the service expects, for example, a pair `(int * string)`, you must provide a matching value as last parameter. OCaml checks at compile time that the type of the parameters in a link corresponds to the type expected by the service. Also parameter names are generated automatically from the service, making it impossible to erroneously create bad links.

To show an example of a link with parameters, we will display the list of user pages on the main page. Here is the new version of the full program:

```ocaml

(* Services *)
let main_service = Eliom_service.create
  ~path:(Eliom_service.Path [""])
  ~meth:(Eliom_service.Get Eliom_parameter.unit)
  ()

let user_service  = Eliom_service.create
  ~path:(Eliom_service.Path ["users"])
  ~meth:(Eliom_service.Get Eliom_parameter.(suffix (string "name")))
  ()

(* User names and passwords: *)
let users = ref [("Calvin", "123"); ("Hobbes", "456")]

let user_links = Eliom_content.Html.D.(
  let link_of_user = fun (name, _) ->
    li [a ~service:user_service [txt name] name]
  in
  fun () -> ul (List.map link_of_user !users)
)

(* Services Registration *)
let () = Eliom_content.Html.D.(

  Eliom_registration.Html.register
    ~service:main_service
    (fun () () ->
      Lwt.return
        (html (head (title (txt "")) [])
           (body [h1 [txt "Hello"];
                  user_links ()])));

  Eliom_registration.Html.register
    ~service:user_service
    (fun name () ->
      Lwt.return
        (html (head (title (txt name)) [])
           (body [h1 [txt name];
                  p [a ~service:main_service [txt "Home"] ()]])))
)
```
<!--wodoc:aside class="concept"-->**Concept: Mutually recursive services**

As our two services are mutually recursive (the first one contains links towards the second one and vice versa), we split the `create` function application in two steps:

- First we create all the services using `Eliom_service.create` or `Eliom_service.App.service` (depending on the type of services you want)
- Then we register the handlers using the `register` function from the right module.
The function `create` we previously used is just a shortcut for these two functions (we create the service, then we register the handler).

<!--wodoc:end-->
<!--wodoc:aside class="concept"-->**Concept: Database libraries**

Ultimately we'll want to use a more sophisticated database module for managing user information, which we will write later in this tutorial. You can use any OCaml database binding (for example [PGOcaml](http://pgocaml.forge.ocamlcore.org/) to program database queries). We will use our own database library called [Macaque](https://github.com/ocsigen/macaque), which implements typed requests using *comprehensions*.

*Just remember that your query functions must be cooperative with Lwt\!* For example PGOcaml is now implemented in monadic way, which makes it 100% compatible with Lwt. Macaque (the library we use later in this tutorial) is as well.

If your database module is not Lwt-cooperative but is thread-safe (for preemptive threads), you can use the `val
Lwt_preemptive.detach` function to make the blocking function be executed by a separate preemptive thread.

<!--wodoc:end-->

## Sessions


### Connection service

<!--wodoc:aside class="concepts"-->**Concepts**

Services with hidden (POST) parameters<br/> Fallback service

<!--wodoc:end-->
Now we want to add a connection form. First, we create a service for checking the name and password. Since we don't want the username and password to be shown in the URL, we use *hidden parameters* (or POST parameters). Thus, we need to create a new service taking these parameters:

```ocaml
let connection_service = Eliom_service.create_attached_post
  ~fallback:main_service
  ~post_params:Eliom_parameter.(string "name" ** string "password")
  ()
```
<!--wodoc:aside class="concept"-->**Concept: Hidden (POST) services**

Services using the POST HTTP method are created using the function `Eliom_service.create` or `Eliom_service.create_attached_post` (depending on what type of service you want to create). As you can see, there is a major difference from the way we created our previous services. Instead of providing a path for the `~path` argument, we gave a *fallback* service. This *fallback* is the service that will be used if the POST parameters are missing (for example, the user sets a bookmark on the page and returns later without POST parameters). This way, we will not get 404 errors if this occurs.

If the fallback has GET parameters, your service will have both GET and POST parameters. In that case, GET parameters will be in the URL and POST parameters will probably come from a form. In HTML, it is not possible to mix GET and POST parameters in the same form.

See also [the cheat-sheet](./basics.md) for an comprehensive overview on the different types of services.

<!--wodoc:end-->
<!--wodoc:aside class="concept"-->**Concept: POST or GET?**

POST parameters are sent in the body of the HTTP request (whereas GET parameters are sent in the URL). It is important to understand that they have very different semantics.

Remember:

- Use GET parameters when you want your page to be bookmarkable.
- Use POST parameters when you do not want the page to be bookmarkable, for example, because it performs a side effect on the server (connecting a user, add something in a database, perform a payment, etc.).
*Warning:* Even if POST parameters are not shown in the URL, they are sent as plain text. If you want to transmit private data (like a password), you must use HTTPS (see `the Ocsigen server manual`). <!--wodoc:end-->

Now we can register a handler for the new service:

```ocaml
  Eliom_registration.Html.register
    ~service:connection_service
    (fun () (name, password) ->
      let message =
        if check_pwd name password
        then "Hello " ^ name
        else "Wrong name or password"
      in
      Lwt.return
        (html (head (title (txt "")) [])
           (body [h1 [txt message];
                  user_links ()])));
```
where `check_pwd` is defined by:

```ocaml
let check_pwd name pwd =
  try List.assoc name !users = pwd with Not_found -> false
```

### Connection form

<!--wodoc:aside class="concepts"-->**Concepts**

Forms

<!--wodoc:end-->
For now, we will add the connection form only on the main page of the site.

Let's create a function for generating the form:

```ocaml
let connection_box () = Eliom_content.Html.D.(
  Form.post_form ~service:connection_service
    (fun (name1, name2) ->
      [fieldset
         [label [txt "login: "];
          Form.input
            ~input_type:`Text ~name:name1
            Form.string;
          br ();
          label [txt "password: "];
          Form.input
            ~input_type:`Password ~name:name2
            Form.string;
          br ();
          Form.input
            ~input_type:`Submit ~value:"Connect"
            Form.string
         ]]) ()
)
```
Now, add a call to this function in the handler of the main service (for example just before the user links).

<!--wodoc:aside class="concept"-->**Concept: Forms**

Form creation is very similar to link creation, using the functions `val Eliom_content.Html.D.Form.get_form` and `val Eliom_content.Html.D.Form.post_form`.

The first parameter is the service, and the last parameter (only for `post_form`) is for GET parameters you want sent in the URL, if the fallback of your POST service takes GET parameters.

The only difference is how we write form content: instead of simply giving the content as parameter to the `get_form` or `post_form` functions, you supply a function that creates the form from the names of the parameters the service is expecting. Thus, you don't need to remember the parameter names you chose while creating the service, and you can change them easily without having to update every form in your application.

In the example, note that the service is expecting a pair `(string * string)`. The function given to `post_form` takes two parameters corresponding to the names of each field.

Functions building widgets, like `val Eliom_content.Html.D.Form.input`, expect an argument of type `type Eliom_content.Html.D.Form.param` (e.g., `Eliom_content.Html.D.Form.int : int Eliom_content.Html.D.Form.param`) specifying the parameter type. OCaml checks that the name you use matches the field. For example the names above need to be used with `val Eliom_content.Html.D.Form.string`.

<!--wodoc:end-->

### Opening a session

<!--wodoc:aside class="concepts"-->**Concepts**

Session data, Eliom references

<!--wodoc:end-->
Now we want to remember that the user is successfully connected. To do that we will set a reference when the user successfully connects, and we will restrict the scope of this reference to the session (that is, to the browser).

Define your Eliom reference with a default value:

```ocaml
let username =
  Eliom_reference.eref ~scope:Eliom_common.default_session_scope None
```
Here is the new `connection_box` function:

```ocaml
let connection_box () = Eliom_content.Html.D.(
  let%lwt u = Eliom_reference.get username in
  Lwt.return
    (match u with
      | Some s -> p [txt "You are connected as "; txt s]
      | None ->
        Form.post_form ~service:connection_service
          (fun (name1, name2) ->
            [fieldset
	       [label [txt "login: "];
                Form.input
                  ~input_type:`Text ~name:name1
                  Form.string;
                br ();
                label [txt "password: "];
                Form.input
                  ~input_type:`Password ~name:name2
                  Form.string;
                br ();
                Form.input
                  ~input_type:`Submit ~value:"Connect"
                  Form.string
               ]]) ())
)
```
...~ and replace the registration of the main service and the connection service by:

```ocaml
  Eliom_registration.Html.register
    ~service:main_service
    (fun () () ->
      let%lwt cf = connection_box () in
      Lwt.return
        (html (head (title (txt "")) [])
              (body [h1 [txt "Hello"];
                     cf;
                     user_links ()])));

  Eliom_registration.Html.register
    ~service:connection_service
    (fun () (name, password) ->
      let%lwt message =
        if check_pwd name password then
	  begin
            let%lwt () = Eliom_reference.set username (Some name) in
            Lwt.return ("Hello "^name)
	  end
	else
	  Lwt.return "Wrong name or password"
      in
      Lwt.return
        (html (head (title (txt "")) [])
           (body [h1 [txt message];
                  user_links ()])));
```
<!--wodoc:aside class="concept"-->**Concept: Eliom references and extended sessions**

Session data is stored in what we call *Eliom references*. It is a type of reference whose value depend on the session the user belongs to.

Eliom is making the notion of session much more powerful by adding other *scopes* for Eliom references. Instead of limiting the scope to a session (that is: one browser), it is also possible to create Eliom references with scope

- "client-side process" (`~scope:Eliom_common.default_process_scope`),
- or "group of sessions" (see later) (`~scope:Eliom_common.default_group_scope`),
- or "current request" (`~scope:Eliom_common.request_scope`) (for example to cache the data during the request, or for *actions* to give information to subsequent service \-- see below).
Example: Say you want to implement a game, and make possible to have several instances of the game running in several tabs of the browser. Store the score on server side, as a "client side process" Eliom reference.

Example: Grouping all the sessions for one user in a group of session makes possible to share a shopping basket between several devices (your mobile phone and your laptop for example).

An Eliom reference is defined with the function `Eliom_reference.eref`, specifying the scope of this reference and the default value. The function `Eliom_reference.get` retrieves the value of this reference for the current scope. The default value is used for all sessions (or client process or group of sessions) for which it has not been changed using `Eliom_reference.set`.

By default, Eliom references are kept in memory and will disappear if you shut down the server. It is possible, however, to create *persistent Eliom references* that will survive even a server restart. To do that, add the optional parameter `persistent` to the `eref` function, with a string value corresponding to the name of the table that will contain the values on disk.

You need to rename this table every time you change the type of your Eliom reference, otherwise the server will crash (we are using OCaml's `Marshal` module).

It is not possible to create Eliom references containing functions (closures), due to limitations in OCaml's serialization mechanism.

<!--wodoc:end-->

### Display the usual page after connection

<!--wodoc:aside class="concepts"-->**Concepts**

Actions

<!--wodoc:end-->
As you can see, our connection service is displaying a welcome page which is different from the main page in connected mode. We would rather display the same page. One solution is to call the same handler after registering session data.

A cleaner solution is to use an *action*, that is: a service which will just perform a side effect. Replace the registration of the connection service by:

```ocaml
  Eliom_registration.Action.register
    ~service:connection_service
    (fun () (name, password) ->
      if check_pwd name password
      then Eliom_reference.set username (Some name)
      else Lwt.return ());
```
Now the main page is displayed after connection.

<!--wodoc:aside class="concept"-->**Concept: Actions**

An *action* is a service that performs a side effect and redisplays the current page. The handler function returns `()`.

<!--wodoc:end-->

### Putting a connection form on each page

<!--wodoc:aside class="concepts"-->**Concepts**

Non-attached coservices<br/> Redirections

<!--wodoc:end-->
<!--wodoc:aside class="concept"-->**Concept: Non-attached coservices**

With many web programming frameworks, adding a connection form on each page of a site is complicated, and is approached in one of two ways:

- A first solution is similar to what we did for the main service, but for all services (meaning that each page usually checks the presence of POST parameters). This is clumsy.
- Another solution would be to create a special page on a separate path to handle the registration, with some way to do a redirection to the page we came from after connection. (Of course we want to stay on the same page after sending the connection form!) This is ugly.
With Eliom, this is more straightforward:

- For the connection service, we use a kind of service called *non-attached coservice*, which means that it is not attached to any path in particular. Calling this kind of service will not change the *path* you see in the browser URL bar (just add parameters if you use the GET method).
- Use an action to connect the user and redisplay the page corresponding to the current URL.
By default, a random identifier will be generated automatically by Eliom for the non-attached coservice. If you want this identifier to be fixed, you can specify it yourself while creating the service using the `?name` optional parameter. This identifier is added automatically by Eliom in each form (as hidden field) and link.

<!--wodoc:end-->
We transform the connection service into a non\_attached coservice, to do so we replace the path we specified earlier for the `~path` parameter:

```ocaml
let connection_service = Eliom_service.create
  ~path:(Eliom_service.No_path)
  ~meth:(Eliom_service.Post (
    Eliom_parameter.unit,
    Eliom_parameter.(string "name" ** string "password")))
  ()
```
Now you can add the connection box on user pages.

```ocaml
  Eliom_registration.Html.register
    ~service:user_service
    (fun name () ->
      let%lwt cf = connection_box () in
      Lwt.return
        (html (head (title (txt name)) [])
              (body [h1 [txt name];
		     cf;
                     p [a ~service:main_service [txt "Home"] ()]])));
```
<!--wodoc:aside class="concept"-->**Concept: Alternative: register a redirection**

Usually, after sending a POST form, it is good practice to do a redirection. This avoids reposting the data if the user reloads the page.

Eliom provides the module `Eliom_registration.Redirection` to register services doing redirections. Such services return a service without parameter.

Example:

```ocaml

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

let service_to_redirect = Eliom_service.create_attached_post
  ~fallback:redir_service
  ~post_params:(Eliom_parameter.string "something")
  ()

let () =
  (** redir_service registration **)
  Eliom_registration.Redirection.register
    ~service:redir_service
    (fun () () ->
    	 Lwt.return
		(Eliom_registration.Redirection some_service_to_redirect_to));

  (** service_to_redirect registration **)
  Eliom_registration.Any.register
  ~service:service_to_redirect
  (fun () something -> ..... )
```
(If you want to give parameters to the service you return, use `Eliom_service.preapply` \--- more information in the [Eliom manual](https://ocsigen.org/eliom/latest/server-services.html#p3preapplied).)

If you want to do a redirection towards the current page (as in our case), use the special service `~path` parameter `Eliom_service.No_path`, which is some kind of POST non-attached coservice without parameter at all. <!--wodoc:end-->


### Disconnection

To create a logout/disconnection form, we create another non-attached coservice using POST method, and register another action. We call the function `val
Eliom_state.discard` with scope `Eliom_common.default_session_scope` to remove all session data.

```ocaml
let disconnection_service = Eliom_service.create
  ~path:(Eliom_service.No_path)
  ~meth:(Eliom_service.Post (Eliom_parameter.unit, Eliom_parameter.unit))
  ()

let disconnect_box () = Eliom_content.Html.D.(
  Form.post_form disconnection_service
    (fun _ ->
      [fieldset [Form.input ~input_type:`Submit ~value:"Log out" Form.string]]
    )
    ()
)

let () =
  Eliom_registration.Action.register
    ~service:disconnection_service
    (fun () () -> Eliom_state.discard ~scope:Eliom_common.default_session_scope ())
```
Then add this form in the connection box:

```ocaml
let connection_box () =
  let%lwt u = Eliom_reference.get username in
  Lwt.return
    (match u with
      | Some s -> div [p [txt "You are connected as "; txt s; ];
                       disconnect_box () ]
      | None -> ...
```

## Registration of users


### Basic registration form

<!--wodoc:aside class="concepts"-->**Concepts**

Attached coservice

<!--wodoc:end-->
We now add a registration form to the application. We create a new regular service, attached to the path `/registration`, that displays a registration form, and an action that will add the user to the "database":

```ocaml
let new_user_form_service = Eliom_service.create
  ~path:(Eliom_service.Path ["registration"])
  ~meth:(Eliom_service.Get Eliom_parameter.unit)
  ()

let create_account_service = Eliom_service.create_attached_post
  ~fallback:main_service
  ~post_params:(Eliom_parameter.(string "name" ** string "password"))
  ()

let account_form () = Eliom_content.Html.D.(
  Form.post_form ~service:create_account_service
    (fun (name1, name2) ->
      [fieldset
         [label [txt "login: "];
          Form.input ~input_type:`Text ~name:name1 Form.string;
          br ();
          label [txt "password: "];
          Form.input ~input_type:`Password ~name:name2 Form.string;
          br ();
          Form.input ~input_type:`Submit ~value:"Connect" Form.string
         ]]) ()
)

let _ = Eliom_content.Html.D.(
  Eliom_registration.Html.register
    ~service:new_user_form_service
    (fun () () ->
      Lwt.return
        (html (head (title (txt "")) [])
              (body [h1 [txt "Create an account"];
                     account_form ();
                    ])));

  Eliom_registration.Action.register
    ~service:create_account_service
    (fun () (name, pwd) ->
      users := (name, pwd)::!users;
      Lwt.return ())
)
```
Then add the link to this service in the connection box:

```ocaml
let connection_box () = Eliom_content.Html.D.(
  let%lwt u = Eliom_reference.get username in
  Lwt.return
    (match u with
      | Some s -> div [p [txt "You are connected as "; txt s; ];
                       disconnect_box () ]
      | None ->
        div [Form.post_form ~service:connection_service
                (fun (name1, name2) ->
...
                ) ();
             p [a new_user_form_service
                  [txt "Create an account"] ()]]
            )
)
```
<!--wodoc:aside class="concept"-->**Concept: Attached coservice**

Now we want to return to the main page after account creation. We are using an *attached coservice*, that is, a service that is identified by both the path in the URL and a special coservice number (or name). A form to such a service will change the path and send parameters together with the coservice identifier (added automatically in an hidden field).

In this particular case, We could have used a regular service, as we do not really need the coservice identifier, but in many cases, you may want to distinguish between several services registered at the same path (and with same parameters). That's what attached coservices are made for.

<!--wodoc:end-->
It looks great, but if we refresh the page after creating an account, we can see there is a problem. We are creating the same account over and over again. This is because we are calling the create\_account\_service each time we refresh the page, obviously we don't want that. To solve this issue we will implement a dynamically created and registered service with limited lifespan and number of uses.


### Registration form with confirmation

<!--wodoc:aside class="concepts"-->**Concepts**

Dynamic registration of services<br/> Session services<br/> Limited services

<!--wodoc:end-->
Now we want to add a confirmation page before actually creating the account. We *replace* the service `create_account_service` by a new POST attached coservice called `account_confirmation_service`:

```ocaml
let account_confirmation_service =
  Eliom_service.create_attached_post
    ~fallback:new_user_form_service
    ~post_params:(Eliom_parameter.(string "name" **  string "password"))
    ()
```
and we make the account creation form point at this new service.

We register an HTML handler on this service, with the confirmation page. As a side effect, this page will create the actual account creation service:

```ocaml

  Eliom_registration.Html.register
    ~service:account_confirmation_service
    (fun () (name, pwd) ->
      let create_account_service =
	Eliom_service.create_attached_get
          ~fallback:main_service
          ~get_params:Eliom_parameter.unit
          ~timeout:60.
	  ~max_use:1
	  ()
      in
      let _ = Eliom_registration.Action.register
	~service:create_account_service
        (fun () () ->
          users := (name, pwd)::!users;
          Lwt.return ())
      in
      Lwt.return
	(html
           (head (title (txt "")) [])
           (body
              [h1 [txt "Confirm account creation for "; txt name];
               p [a ~service:create_account_service [txt "Yes"] ();
                  txt " ";
                  a ~service:main_service [txt "No"] ()]
              ])));
```
Also remove the registration of the `create_account_service` service and modify the user creation form to make it points towards `account_confirmation_service`.

We created dynamically a service with a limited lifespan as specified by the `?timeout` parameter and a limited number of uses of this service defined by the `?max_use` parameter. Now if we refresh the page after creating the account, it works as intended.

<!--wodoc:aside class="concept"-->**Concept: Dynamic creation of services**

In this example, we are dynamically creating a new service (here a coservice that does an action). This is done by the same `register` function as usual.

Dynamic creation of new services allows one to create services that depend on previous interaction with the user. Here the `create_account_service` service depends on `name` and `pwd`, that were previously sent by a form.

In this simple example, an alternative would have been to send `name` and `pwd` again to the same service as in the "basic registration form" example. But this solution is not possible when you have too much data.

*Saving `name` and `pwd` as session data is a wrong solution\!* If the user duplicates his browser window and fills out the user creation form in both, then the confirmation link must create the right account\!

A working alternative would have been to generate a random key, and associate `name` and `pwd` with that key in a database table on the server. This is the way such kind of web interaction is usually implemented. However, Eliom's solution is much simpler.

The ability to register new services dynamically is implemented in few web frameworks, even though it simplifies a lot the programmating involved with that type of web interaction. This feature is a variant of what is called *continuation based web programming*. Think about it when you want to *create a page that depends on previous interaction with the user*. Dynamic registration of services will automatically record the "history" of the interaction, and make possible to use the "back button" or to have several tabs on the same site.

Examples of uses:

- displaying the results of a search
- programming a "several step form" (when a form points at another one, etc., like our registration form with confirmation).
On the other hand, if you want to implement a *shopping basket*, you want it to be shared between all tabs of your web site. To do that, you will use session data.

*Warning:* Services are kept in memory. To avoid memory leaks, you probably want to put a timeout on your dynamic coservices. Just add the optional parameter `?timeout` to the service creation function.

<!--wodoc:end-->
<!--wodoc:aside class="concept"-->**Concept: Session services**

Eliom also makes it possible to restrict the scope of services to a session, a group of sessions, or even a client side process (if you have a client side program running). It works exactly like the scope of Eliom references. To do that, just add the optional parameter `~scope` to the registration function. By default, the value is `Eliom_common.global_scope` (visible for everyone). Other possible values: `Eliom_common.default_session_scope`, `Eliom_common.default_group_scope`, or `Eliom_common.default_process_scope`.

It is possible to register again for a session, tab or group, services that have already been registered with public (site) visibility. In such cases, Eliom will try first tab services, then session services, then group services, and finally site services. This makes possible to register specialized versions of a service for one user, for example when she logs in.

<!--wodoc:end-->

## A few enhancements


### Displaying a "wrong password" message

<!--wodoc:aside class="concepts"-->**Concepts**

Scope "request" <!--wodoc:end-->

In the current version, our web site fails silently when the password is wrong. Let's improve this behavior by displaying an error message. To do that, we need to pass information to the service occurring after the action. We record this information in an Eliom reference with scope `Eliom_common.request_scope`.

Define an Eliom reference:

```ocaml
let wrong_pwd =
  Eliom_reference.eref ~scope:Eliom_common.request_scope false
```
Modify the connection box this way:

```ocaml
let connection_box () = Eliom_content.Html.D.(
  let%lwt u = Eliom_reference.get username in
  let%lwt wp = Eliom_reference.get wrong_pwd in
  Lwt.return
    (match u with
      | Some s -> div [p [txt "You are connected as "; txt s; ];
                       disconnect_box () ]
      | None ->
        let l =
          [Form.post_form ~service:connection_service
            (fun (name1, name2) ->
              [fieldset
	         [label [txt "login: "];
                  Form.input ~input_type:`Text ~name:name1 Form.string;
                  br ();
                  label [txt "password: "];
                  Form.input ~input_type:`Password ~name:name2 Form.string;
                  br ();
                  Form.input ~input_type:`Submit ~value:"Connect" Form.string
                 ]]) ();
             p [a new_user_form_service
                  [txt "Create an account"] ()]]
        in
        if wp
        then div ((p [em [txt "Wrong user or password"]])::l)
        else div l
    )
)
```
...~ and modify the `connection_service` handler:

```ocaml
  Eliom_registration.Action.register
    ~service:connection_service
    (fun () (name, password) ->
      if check_pwd name password
      then Eliom_reference.set username (Some name)
      else Eliom_reference.set wrong_pwd true);
```

### Sending 404 errors for non-existing users

<!--wodoc:aside class="concepts"-->**Concepts**

Sending 404<br/> `Eliom_registration.Any`

<!--wodoc:end-->
Our service `user_service` responds to any request parameter, even if the user does not exist in the database. We want to check that the user is in the database before displaying the page, and send a 404 error if the user is not. To do that, we will replace module `Eliom_registration.Html` by `module
Eliom_registration.Any` to register the service `user_service`:

```ocaml
  Eliom_registration.Any.register
    ~service:user_service
    (fun name () ->
      if List.mem_assoc name !users then
	begin
	  let%lwt cf = connection_box () in
	  Eliom_registration.Html.send
            (html (head (title (txt name)) [])
               (body [h1 [txt name];
                      cf;
                      p [a ~service:main_service [txt "Home"] ()]]))
	end
      else
	Eliom_registration.Html.send
          ~code:404
          (html (head (title (txt "404")) [])
             (body [h1 [txt "404"];
                    p [txt "That page does not exist"]]))
    );
```
<!--wodoc:aside class="concept"-->**Concept: Eliom\_registration.Any**

The module `module
Eliom_registration.Any` can be used to create services that are flexible to choose the kind of output they want to send.

Use the `send` function from the module you want to send the output. That function also allows, for example, to specify the HTTP response code (here, we choose to use 404\) or to set HTTP headers.

<!--wodoc:end-->
<!--wodoc:aside class="wip"-->**Work in progress**

In the future, we may add functions like `set_http_code` or `set_http_header` to personalize the answer without using `Eliom_registration.Any`.

<!--wodoc:end-->

### Wrapping the server handler to easily get the user data

When you want to assume that you have information available in sessions, for instance when a site is mainly available to connected users, it becomes tedious to check everywhere that a reference is not `None`. A simple way to distinguish authenticated and anonymous requests lies in the usage of `Eliom_tools.wrap_handler`. It allows you to provide two handler functions, one is called if a certain information is not made available by the first argument, the other is called when that information is available.

```ocaml

let authenticated_handler f = Eliom_content.Html.D.(
  let handle_anonymous _get _post =
    let connection_box =
      Form.post_form ~service:connection_service
        (fun (name1, name2) ->
	  [fieldset
              [label [txt "login: "];
               Form.input ~input_type:`Text ~name:name1 Form.string;
               br ();
               label [txt "password: "];
               Form.input ~input_type:`Password ~name:name2 Form.string;
               br ();
               Form.input ~input_type:`Submit ~value:"Connect" Form.string
              ]]) ()
    in
    Lwt.return
      (html
        (head (title (txt "")) [])
        (body [h1 [txt "Please connect"];
	       connection_box;]))
    in
    Eliom_tools.wrap_handler
      (fun () -> Eliom_reference.get username)
      handle_anonymous (* Called when [username] is [None] *)
      f (* Called [username] contains something *)
)

let () = Eliom_content.Html.D.(
  Eliom_registration.Html.register ~service:main_service
    (authenticated_handler
       (fun username _get _post ->
       	 Lwt.return
           (html
              (head (title (txt "")) [])
              (body [h1 [txt ("Hello " ^ username) ]]))))
)
```
[prev](./application.md) `next`
