{0 Service parameters}



{1:parameters Parameters}

{2 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 of a service are provided via the arguments of the
{!Eliom_service_sigs.TYPES.meth}
constructors. The specification of parameter types is done using
combinators defined in the module
{!Eliom_parameter}.
For example, [Eliom_parameter.unit] means that the service does
not take any parameter, and [Eliom_parameter.int "foo"] means that
the service takes a parameter called [foo], which is of type
[int]. See
{!Eliom_parameter_sigs.S}
for documentation on the combinators.

Here is an example of a service with GET parameters:

{@ocaml[
let writeparams (i1, (i2, s1)) () = Lwt.return @@
  let open Eliom_content.Html.D in
  html
    (head (title (txt "")) [])
    (body
       [p [txt "You sent: ";
           strong [txt (string_of_int i1)];
           txt ", ";
           strong [txt (string_of_int i2)];
           txt " and ";
           strong [txt s1]]])
]}

{@ocaml[
let service_with_params =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["thepath"])
    ~meth:
      (Eliom_service.Get
         Eliom_parameter.(int "i" ** (int "ii" ** string "s")))
    writeparams
]}

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.
We 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).{%html:<br/>%}

{e Warning:} The infix function [( ** )] can only be used to
construct pairs (not tuples).{%html:<br/>%}

{2:suffix Path suffixes as parameters}

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


{@ocaml[
let uasuffix =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["uasuffix"])
    ~meth:
      (Eliom_service.Get
         Eliom_parameter.(suffix (int "year" ** int "month")))
    (fun (year, month) () -> Lwt.return @@
      let open Eliom_content.Html.D in
      html
        (head (title (txt "")) [])
        (body
           [p [txt "The suffix of the url is ";
               strong [txt (string_of_int year ^ "/" ^
                               string_of_int month)];
               txt ", your user-agent is ";
               strong [txt (Eliom_request_info.get_user_agent ())];
               txt ", your IP is ";
               strong [txt (Eliom_request_info.get_remote_ip ())]]]))
]}

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

Suffix parameters have names, because we can create forms towards
these services. [uasuffix/2000/11] is equivalent to
[uasuffix/?year=2000&month=11].{%html:<br/>%}
[suffix_prod] allows both a suffix and other parameters.{%html:<br/>%}
[all_suffix] allows the end of the suffix to be taken as a
[string list].{%html:<br/>%}

{@ocaml[
let isuffix =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["isuffix"])
    ~meth:
      (Eliom_service.Get
         Eliom_parameter.
           (suffix_prod (int "suff" ** all_suffix "endsuff") (int "i")))
    (fun ((suff, endsuff), i_param) () -> Lwt.return @@
      let open Eliom_content.Html.D in
      html
        (head (title (txt "")) [])
        (body
           [p [txt "The suffix of the url is ";
               strong [txt (string_of_int suff)];
               txt " followed by ";
               strong [txt
                         (Ocsigen_lib.Url.string_of_url_path
                            ~encode:false
                            endsuff)];
               txt " and i is equal to ";
               strong [txt (string_of_int i_param)]]]))
]}

If you want parameters in the path but not always at the end,
use the [const] parameter specification.
It will match for example URLs like [/param1/const/param2].
Example:
{@ocaml[
let constfix =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["constfix"])
    ~meth:
      (Eliom_service.Get
         Eliom_parameter.
           (suffix (string "s1" ** (suffix_const "toto" ** string "s2"))))
    (fun (s1, ((), s2)) () -> Lwt.return @@
      let open Eliom_content.Html.D in
      html
        (head (title (txt "")) [])
        (body [
           h1 [txt "Suffix with constants"];
           p [txt ("Parameters are "^s1^" and "^s2)]]))
]}

{2 Custom parameter types}

The following example shows how to use your own types :

{@ocaml[
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_registration.Html.create
    ~path:(Eliom_service.Path ["mytype"])
    ~meth:
      (Eliom_service.Get
         (Eliom_parameter.user_type
            mysum_of_string
            string_of_mysum
            "value"))
    (fun x () -> Lwt.return @@
      let open Eliom_content.Html.D in
      html
        (head (title (txt "")) [])
        (body [p [txt
                    (string_of_mysum x ^
                     " is valid. Now try with another value.")]]))
]}

See also {{!page-"clientserver-communication".client_sending_data}Client sending data} in the chapter
about client-server communication, which shows how to use a [user_type]
from the client-side.

{2:any Untyped parameters}

If you want a service that answers to requests with any parameters,
use the [any] combinator. The service will get an association list
of strings. For example:

{@ocaml[
let raw_serv =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["any"])
    ~meth:(Eliom_service.Get Eliom_parameter.any)
  (fun l () ->
    let module Html = Eliom_content.Html.D in
    let ll =
      List.map
        (fun (a,s) -> strong [txt a; txt ", "; txt s]) l
    in
    Lwt.return
      [%html "<html>
          <head><title>Example</title></head>
          <body>
          <p>
            You sent:"
            ll
          "</p>
          </body>
        </html>"])
]}

It is possible to use [Eliom_parameter.any] with other parameter
combinators, but [any] must be the last one. For example:
[(int "i" ** any)].

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

{@ocaml[
let my_nl_params =
  Eliom_parameter.make_non_localized_parameters
    ~prefix:"tutoeliom"
    ~name:"mynlparams"
    Eliom_parameter.(int "a" ** string "s")

let nlparams =
  let open Eliom_content.Html.D in
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["nlparams"])
    ~meth:(Eliom_service.Get (Eliom_parameter.int "i"))
    (fun i () -> Lwt.return @@
      html
        (head (title (txt "")) [])
        (body [
           p [txt "i = "; strong [txt (string_of_int i)]];
           match Eliom_parameter.get_non_localized_get_parameters
                   my_nl_params
           with
           | None ->
             p [txt "I do not have my non localized parameters"]
           | Some (a, s) ->
             p [txt "I have my non localized parameters, ";
                txt (Printf.sprintf "with values a = %d and s = %s." a s)]
         ]))
]}


To create a link or a form with non-localized parameters, use the
optional parameter {%wodoc:span class="code"%}nl_params{%wodoc:end%} of functions
[Eliom_content.Html.D.a], [Eliom_content.Html.D.Form.get_form], or
[Eliom_content.Html.D.Form.post_form]. Example:

{@ocaml[
let tonlparams =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["nlparams"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    (fun i () -> Lwt.return @@
      let open Eliom_content.Html.D in
      html
        (head (title (txt "")) [])
        (body
           [p [a ~service:nlparams [txt "without nl params"] 4];
            p [a ~service:nlparams
                 ~nl_params:
                   (Eliom_parameter.add_nl_parameter
                      Eliom_parameter.empty_nl_params_set
                      my_nl_params
                      (22, "oh"))
                 [txt "with nl params"]
                 5];
            Form.get_form
              ~service:nlparams
              ~nl_params:
                (Eliom_parameter.add_nl_parameter
                   Eliom_parameter.empty_nl_params_set
                   my_nl_params
                   (22, "oh"))
              (fun iname ->
                 [p [txt "form with hidden nl params";
                     Form.input
                       ~input_type:`Text ~name:iname
                       Form.int;
                     Form.input
                       ~input_type:`Submit ~value:"Send"
                       Form.string]]);
            Form.get_form ~service:nlparams (fun iname ->
              let (aname, sname) =
                Eliom_parameter.get_nl_params_names my_nl_params
              in
              [p [
                 txt "form with nl params fields";
                 Form.input ~input_type:`Text ~name:iname Form.int;
                 Form.input ~input_type:`Text ~name:aname Form.int;
                 Form.input ~input_type:`Text ~name:sname Form.string;
                 Form.input ~input_type:`Submit ~value:"Send" Form.string]]);
           ]))
]}

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

{@ocaml[let nlparams_with_nlp =
  Eliom_service.add_non_localized_get_parameters my_nl_params nlparams
]}

Then create your link as usual.
