Warning: Reason support is experimental. We are looking for beta-tester and contributors.

Service parameters

Table of contents


Services with parameters

Service handlers take two parameters. The first one is for GET parameters (that is, parameters in the URL) and the second one for POST parameters (parameters in the body of the HTTP request).

The parameters labeled get_params or post_params of the services creation functions indicate the type of the parameters. The specification of parameters types is done using combinators defined in module Eliom_parameter. For example Eliom_parameter.unit means that the page does not take any parameter, and Eliom_parameter.int means that the page takes a parameter called foo, of type int.

Here is an example of a service with GET parameters:

open Eliom_content
open Eliom_parameter

let writeparams (i1, (i2, s1)) () =
              (head (title (pcdata "")) [])
              (body [p [pcdata "You sent: ";
                        strong [pcdata (string_of_int i1)];
                        pcdata ", ";
                        strong [pcdata (string_of_int i2)];
                        pcdata " and ";
                        strong [pcdata s1]]]))
let coucou_params = Eliom_registration.Html5.register_service
    ~get_params:(int "i" ** (int "ii" ** string "s"))

Eliom will automaticaly try to convert the parameters and call the handler with the right OCaml types (here int * (int * string)).

It is possible to register several services on the same path, if they do not have the same parameters. Eliom will try them in order of registration until one of them is able to answer (and send an error otherwise).

In the example above, if i is not an integer, the server will display an error-message (try to change the value in the URL).

Warning: The infix function ( ) is to be used to construct pairs (not tuples).

Path suffixes as parameters

The following example shows how to create a service with "suffix" service (taking the end of the URL as a parameter, as wikis do very often) and how to get server information:

open Eliom_parameter
let uasuffix =
    ~get_params:(suffix (int "year" ** int "month"))
    (fun (year, month) () ->
                  (head (title (pcdata "")) [])
                     [p [pcdata "The suffix of the url is ";
                         strong [pcdata ((string_of_int year)^"/"
                                         ^(string_of_int month))];
                         pcdata ", your user-agent is ";
                         strong [pcdata (Eliom_request_info.get_user_agent ())];
                         pcdata ", your IP is ";
                         strong [pcdata (Eliom_request_info.get_remote_ip ())]]])))

This service will answer to URLs like http://.../uasuffix/2000/11.

See uasuffix

Suffix parameters have names, because we can create forms towards these services. uasuffix/2000/11 is equivalent to uasuffix/?year=2000&month=11.
Eliom_parameter.suffix_prod allows to take both a suffix and other parameters.
Eliom_parameter.all_suffix allows to take the end of the suffix as a string list.

let isuffix =
    ~get_params:(suffix_prod (int "suff" ** all_suffix "endsuff") (int "i"))
    (fun ((suff, endsuff), i) () ->
        (head (title (pcdata "")) [])
           [p [pcdata "The suffix of the url is ";
               strong [pcdata (string_of_int suff)];
               pcdata " followed by ";
               strong [pcdata (Ocsigen_lib.string_of_url_path ~encode:false endsuff)];
               pcdata " and i is equal to ";
               strong [pcdata (string_of_int i)]]])))

See isuffix.

If you want parameters in the path but not always at the end, use the Eliom_parameter.const parameter specification. It will match for example URLs like /param1/const/param2. Example:

open Eliom_parameter

let constfix =
    ~get_params:(suffix (string "s1" ** (suffix_const "toto" ** string "s2")))
    (fun (s1, ((), s2))  () ->
                   (head (title (pcdata "")) [])
                   (body [
                     h1 [pcdata "Suffix with constants"];
                     p [pcdata ("Parameters are "^s1^" and "^s2)]])))

Page with constants in suffix.

Custom parameter types

The following example shows how to use your own types :

type mysum = A | B
let mysum_of_string = function
  | "A" -> A
  | "B" -> B
  | _ -> raise (Failure "mysum_of_string")
let string_of_mysum = function
  | A -> "A"
  | B -> "B"

let mytype =
      (Eliom_parameter.user_type mysum_of_string string_of_mysum "valeur")
    (fun x () ->
      let v = string_of_mysum x in
         (head (title (pcdata "")) [])
         (body [p [pcdata (v^" is valid. Now try with another value.")]])))

See mytype.

Untyped parameters

If you want a service that answers to requests with any parameters, use the Eliom_parameter.any value. The service will get an association list of strings. Example:

let raw_serv = Eliom_registration.Html5.register_service
  (fun l () ->
    let module Html5 = Eliom_content.Html5.D in
    let ll =
        (fun (a,s) -> << <strong>($str:a$, $str:s$)</strong> >>) l
     << <html>
            You sent:
        </html> >>)

Try raw_serv. It is possible to use Eliom_parameter.any with other parameters combinators. But any must be the last one. For example: (int "i" ** any).

Non localized parameters

Non localized parameters are GET or POST parameters that are not taken into account by Eliom for choosing the service. They have a special prefix (added automatically by Eliom). Use this if you want some information to be available or not, through parameters, for all of your services.

let my_nl_params = 
    (Eliom_parameter.int "a" ** Eliom_parameter.string "s")

let nlparams = Eliom_registration.Html5.register_service
    ~get_params:(int "i")
    (fun i () ->
            (head (title (pcdata "")) [])
            (body [p [pcdata "i = ";
                      strong [pcdata (string_of_int i)]];
                   (match Eliom_parameter.get_non_localized_get_parameters
                      | None -> 
                          p [pcdata "I do not have my non localized parameters"]
                      | Some (a, s) -> 
                          p [pcdata "I have my non localized parameters, ";
                             pcdata ("with values a = "^string_of_int a^
                                       " and s = "^s^".")]


To create a link or a form with non-localized parameters, use the optional parameter nl_params of functions Eliom_content.Html5.D.a, Eliom_content.Html5.D.get_form or Eliom_content.Html5.D.post_form. Example:

let tonlparams = Eliom_registration.Html5.register_service
    (fun i () ->
       Lwt.return Html.D.(
           (head (title (pcdata "")) [])
              [p [a ~service:nlparams [pcdata "without nl params"] 4];
               p [a ~service:nlparams 
                                  (22, "oh")
                    [pcdata "with nl params"] 
                               (22, "oh")
                 (fun iname ->
                    [p [pcdata "form with hidden nl params";
                          ~input_type:`Text ~name:iname ();
                          ~input_type:`Submit ~value:"Send" ()]]);
                 (fun iname ->
                    let (aname, sname) = 
                      Eliom_parameter.get_nl_params_names my_nl_params
                    [p [pcdata "form with nl params fiels";
                        int_input ~input_type:`Text ~name:iname ();
                        int_input ~input_type:`Text ~name:aname ();
                        string_input ~input_type:`Text ~name:sname ();
                        string_input ~input_type:`Submit ~value:"Send" ()]]);

It is also possible to create a new service by adding the non localized parameters to an existing service:

let nlparams_with_nlp =
  Eliom_service.add_non_localized_get_parameters my_nl_params nlparams

Then create your link as usual, for example: a nlparams_with_nlp [pcdata "Try it"] (22, (11, "aa")). Try it.