
Version 1.0.0
This is a preliminary version of the documentation. Help us to improve it by filling tickets. We are looking for native english speakers to proof read the documentation. Contact us!
Unlike many other Web programming techniques (CGI, PHP, ...), with Eliom, you don't write one file for each URL, but a caml module (cmo or cma) for the whole Web site.
The Eliom_services module allows to create new entry points to
your Web site, called services. In general, services are
attached to an URL and generate a Web page.
They are represented by OCaml values, on which
you must register a function that will generate a page.
There are several ways to create pages for Eliom. This tutorial
is mainly using Eliom_predefmod.Xhtml, a module allowing
to register xhtml pages statically typed using OCaml's
polymorphic variants.
The XHTML.M module defines functions to construct
xhtml pages using that type system.
As the Eliom_predefmod.Xhtml redefines some functions
of XHTML.M, open the modules in this order:
open Lwt open XHTML.M open Eliom_services open Eliom_parameters open Eliom_sessions open Eliom_predefmod.Xhtml
Lwt
(lightweight threads) is the cooperative thread library used by Ocsigen
(see later).
Here is an example showing how to create a new service and
register a page created with XHTML.M. Use the function
Eliom_predefmod.Xhtml.register_new_service:
let coucou = register_new_service ~path:["coucou"] ~get_params:unit (fun _ () () -> return (html (head (title (pcdata "")) []) (body [h1 [pcdata "Hallo!"]])))
The same, written with fully qualified values:
let coucou = Eliom_predefmod.Xhtml.register_new_service ~path:["coucou"] ~get_params:Eliom_parameters.unit (fun _ () () -> Lwt.return (XHTML.M.html (XHTML.M.head (XHTML.M.title (XHTML.M.pcdata "")) []) (XHTML.M.body [XHTML.M.h1 [XHTML.M.pcdata "Hallo!"]])))
As you can see,
return is a function from Lwt.
Use it like this for instants, and
see later for more advanced use.
Now you can compile your file (here tutorial.ml) by typing :
ocamlc -I /path_to/ocsigen/ -I /path_to/lwt/ -c tutorial.ml
If you use findlib, you can also use the following command line:
ocamlfind ocamlc -thread -package ocsigen -c tutorial.ml
Replace /path_to/ocsigen/ by the directory where Ocsigen libraries are installed (that contains eliom.cma, staticmod.cmo, etc.), usually something like /usr/lib/ocaml/3.09.3/ocsigen or /usr/local/lib/ocaml/3.09.3/ocsigen or /opt/godi/lib/ocaml/site-lib/ocsigen.
Add the following lines to Ocsigen's config file (/etc/ocsigen/ocsigen.conf most of the time):
<host> <site path="examples"> <eliom module="/path_to/tutoeliom.cmo" /> </site> </host>
Note that if your module has a findlib META file, it is also possible to do:
<host> <site path="examples"> <eliom findlib-package="package-name" /> </site> </host>
Then run ocsigen. You should see your page at url http://your_server/examples/coucou. See this example here.
NB: See the default config file to see how to set the port on which your server is running, the user who runs it, the path of the log files, etc.
Here is a sample Makefile for your modules.
Typing of xhtml with XHTML.M and Eliom_predefmod.Xhtml
is very strict and compels you to respect
xhtml 1.1 standard (with some limitations).
For example if you write:
(html (head (title (pcdata "")) []) (body [pcdata "Hallo"]))
You will get the following error message:
This expression has type ([> `PCDATA ] as 'a) XHTML.M.elt but is here used with type ([< XHTML.M.block ] as 'b) XHTML.M.elt Type 'a is not compatible with type 'b = [< `Address | `Blockquote | `Del | `Div | `Dl | `Fieldset | `Form | `H1 | `H2 | `H3 | `H4 | `H5 | `H6 | `Hr | `Ins | `Noscript | `Ol | `P | `Pre | `Script | `Table | `Ul ]
'b is the type of block tags (only tags allowed inside <body>), but PCDATA (i.e. raw text) is not a block tag.
In XHTML, some tags cannot be empty. For example
<table> must contain at least one row.
To enforce this, the XHTML.M.table function takes two parameters:
the first one is the first row, the second one is a list
containing all the other rows.
(same thing for <tr> <form>
<dl> <ol> <ul>
<dd> <select> ...)
This forces the user to handle the empty list case specially and thus make
the output conform to the DTD.
A more detailed introduction to XHTML.M is available
here.
Take a quick look at it before continuing this tutorial.
If you prefer using a syntax closer to html, you can write:
let coucou1 = Eliom_predefmod.Xhtml.register_new_service ~path:["coucou1"] ~get_params:Eliom_parameters.unit (fun _ () () -> return << <html> <head><title></title></head> <body><h1>Coucou</h1></body> </html> >>)
To compile this syntax, you need a camlp4 syntax extension:
ocamlc -I /path_to/ocsigen/ -pp "camlp4o /path_to/ocsigen/xhtmlsyntax.cma -loc loc" -c tutorial.ml
(Replace /path_to/ocsigen/ by the directory where ocsigen is installed). See this example here.
As the syntax extension is using the same typing system as XHTML.M, You can mix the two syntaxes (see later).
Warning: The two syntaxes are not equivalent for typing. Using the syntax extension will do less checking. For example the following code is accepted but not valid regarding xhtml's dtd (because <head> must contain a title):
<< <html> <head></head> <body><h1>plop</h1></body> </html> >>
We recommend you to use
the functions from XHTML.M, as you will (almost)
always get valid xhtml.
Use the syntax extension for example to enclose already created pieces
of html, and check your pages validity with the
W3C validator.
More info
on XHTML.M.
More info on the syntax extension.
If OCamlDuce is installed on your system, it is now possible to use it instead of XHTML.M and Eliom_parameters.Xhtml to typecheck your pages. You will get a stronger type checking and more flexibility (easier to use other XML types, to parse incoming XML data, etc.).
To use it, make sure that you have Eliom compiled with OCamlDuce
support. Then dynlink ocamlduce.cma and
eliomduce.cma from the configuration file
(after eliom.cma).
Then use Eliom_duce.Xhtml instead of
Eliom_predefmod.Xhtml to register your pages.
Here is an example:
open Lwt let s = Eliom_duce.Xhtml.register_new_service ~path:[""] ~get_params:unit (fun sp () () -> return {{ <html> [<head> [<title> ""] <body> [<h1> "This page has been type checked by OCamlDuce"]] }})
If you want to register untyped (text) pages, use the
functions from Eliom_predefmod.HtmlText, for example
Eliom_predefmod.Text.register_new_service :
let coucoutext = Eliom_predefmod.HtmlText.register_new_service ~path:["coucoutext"] ~get_params:Eliom_parameters.unit (fun sp () () -> return ("<html>n'importe quoi "^ (Eliom_predefmod.HtmlText.a coucou sp "clic" ())^ "</html>"))
Services registered with register_new_service are available for all users. We call them public services.
Page generation may have side-effects:
let count = let next = let c = ref 0 in (fun () -> c := !c + 1; !c) in register_new_service ~path:["count"] ~get_params:unit (fun _ () () -> return (html (head (title (pcdata "counter")) []) (body [p [pcdata (string_of_int (next ()))]])))
See this example here.
As usual in OCaml, you can forget labels when the application is total:
let hello = register_new_service ["dir";"hello"] (* the url dir/hello *) unit (fun _ () () -> return (html (head (title (pcdata "Hello")) []) (body [h1 [pcdata "Hello"]])))
See this example here.
The last example shows how to define the default page for a directory. (Note that ["rep";""] means the default page of the directory rep/)
let default = register_new_service ["rep";""] unit (fun _ () () -> return (html (head (title (pcdata "")) []) (body [p [pcdata "default page. rep is redirected to rep/"]])))
See default.
["foo";"bar"] corresponds to the URL
foo/bar.
["dir";""] corresponds to the URL dir/
(that is: the default page of the directory dir).
The empty list [] is equivalent to [""].
Warning: You cannot create a service on path ["foo"] (URL foo, without slash at the end) and another on path ["foo";"bar"] (URL foo/bar) because foo can not be both a directory and a file. Be also careful not to use a string as a directory with Eliom, if it is a file for Staticmod (and vice versa).
Warning: ["foo";"bar"] is not equivalent to ["foo/bar"]. In the latter, the "/" will be encoded in the URL.
The parameter labeled
get_params
indicates the type of GET parameters for the page (that is, parameters
present in the URL).
unit means that the page does not take any GET parameter.
Functions implementing services are called service handlers.
They take three parameters. The first
one has type
Eliom_sessions.server_params
and
corresponds to server parameters (user-agent, ip, current-url, etc.
- see later in that section for examples of use),
the second one is for GET parameters
(that is, parameters in the URL) and the third one
for POST parameters (parameters in the body of the HTTP request).
Here is an example of a service with GET parameters:
let writeparams _ (i1, (i2, s1)) () = return (html (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 = register_new_service ~path:["coucou"] ~get_params:(int "i" ** (int "ii" ** string "s")) writeparams
Note that the URLs of coucou
and coucou_params
differ only by parameters. Url
http://your_server/examples/coucou
will run the first one,
http://your_server/examples/coucou?i=42&ii=17&s=krokodile
will run the second one.
If i is not an integer,
the server will display an error-message
(try to change the value in the URL).
Here, int, string and
are functions defined in the Eliom_parameters module.
Warning:
The infix function ( ) is to be used to
construct pairs (not tuples).
The following examples 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:
let uasuffix = register_new_service ~path:["uasuffix"] ~get_params:(suffix (int "year" ** int "month")) (fun sp (year, month) () -> return (html (head (title (pcdata "")) []) (body [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_sessions.get_user_agent sp)]; pcdata ", your IP is "; strong [pcdata (Eliom_sessions.get_remote_ip sp)]]])))
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.
suffix_prod allows to take both a suffix and
other parameters.
all_suffix allows to take the end of the suffix as a
string list.
let isuffix = register_new_service ~path:["isuffix"] ~get_params:(suffix_prod (int "suff" ** all_suffix "endsuff") (int "i")) (fun sp ((suff, endsuff), i) () -> return (html (head (title (pcdata "")) []) (body [p [pcdata "The suffix of the url is "; strong [pcdata (string_of_int suff)]; pcdata " followed by "; strong [pcdata (Ocsigen_extensions.string_of_url_path endsuff)]; pcdata " and i is equal to "; strong [pcdata (string_of_int i)]]])))
See isuffix.
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_predefmod.Xhtml.register_new_service ~path:["mytype"] ~get_params: (Eliom_parameters.user_type mysum_of_string string_of_mysum "valeur") (fun _ x () -> let v = string_of_mysum x in return (html (head (title (pcdata "")) []) (body [p [pcdata (v^" is valid. Now try with another value.")]])))
See mytype.
If you want a service that answers to requests with any parameters,
use the Eliom_parameters.any value. The service will get an
association list of strings. Example:
let raw_serv = register_new_service ~path:["any"] ~get_params:Eliom_parameters.any (fun _ l () -> let ll = List.map (fun (a,s) -> << <strong>($str:a$, $str:s$)</strong> >>) l in return << <html> <head><title></title></head> <body> <p> You sent: $list:ll$ </p> </body> </html> >>)
Try raw_serv.
You can catch parameters typing errors and write your own error messages using the optional parameter error_handler. Example:
let catch = register_new_service ~path:["catch"] ~get_params:(int "i") ~error_handler:(fun sp l -> return (html (head (title (pcdata "")) []) (body [p [pcdata ("i is not an integer.")]]))) (fun _ i () -> let v = string_of_int i in return (html (head (title (pcdata "")) []) (body [p [pcdata ("i is an integer: "^v)]])))
error_handler takes as parameters the usual sp, and a list of pairs (n,ex), where n is the name of the wrong parameter, and ex is the exception that has been raised while parsing its value.
See catch (change the value of the parameter).
To create a link (<a>), use the
Eliom_predefmod.Xhtml.a function (or Eliom_duce.Xhtml.a, etc),
as in these examples:
let links = register_new_service ["rep";"links"] unit (fun sp () () -> return (html (head (title (pcdata "Links")) []) (body [p [Eliom_predefmod.Xhtml.a coucou sp [pcdata "coucou"] (); br (); Eliom_predefmod.Xhtml.a hello sp [pcdata "hello"] (); br (); Eliom_predefmod.Xhtml.a default sp [pcdata "default page of the dir"] (); br (); Eliom_predefmod.Xhtml.a uasuffix sp [pcdata "uasuffix"] (2007,06); br (); Eliom_predefmod.Xhtml.a coucou_params sp [pcdata "coucou_params"] (42,(22,"ciao")); br (); Eliom_predefmod.Xhtml.a raw_serv sp [pcdata "raw_serv"] [("sun","yellow");("sea","blue and pink")]; br (); Eliom_predefmod.Xhtml.a (new_external_service ~prefix:"http://fr.wikipedia.org" ~path:["wiki";""] ~get_params:(suffix (all_suffix "suff")) ~post_params:unit ()) sp [pcdata "OCaml on wikipedia"] ["OCaml"]; br (); XHTML.M.a ~a:[a_href (uri_of_string "http://en.wikipedia.org/wiki/OCaml")] [pcdata "OCaml on wikipedia"] ]])))
See links.
If you open Eliom_predefmod.Xhtml after XHTML.M,
Eliom_predefmod.Xhtml.a
will mask XHTML.M.a.
Thus you can avoid to write fully qualified values most of the time.
Eliom_predefmod.Xhtml.a takes as first parameter
the service you want to link to.
Note that to create a (relative) link we need to know the current URL.
That's why the function a
takes sp as second parameter.
The third parameter is the text of the link. The last parameter is for GET parameters you want to put in the link. The type of this parameter and the name of GET parameters depend on the service you link to.
The links to Wikipedia shows how to define an external service (here it
uses a suffix URL).
For an external service without parameters, you can use the low level
function XHTML.M.a, if you don't want to create an
external service explicitely.
Note that the path must be a list of strings.
Do not write ["foo/bar"],
but ["foo";"bar"], otherwise, the "/" will be encoded in
the URL.
If you want to create (mutually or not) recursive pages,
create the service using Eliom_services.new_service first,
then register it in the table using (for example)
Eliom_predefmod.Xhtml.register:
let linkrec = Eliom_services.new_service ["linkrec"] unit () let _ = Eliom_predefmod.Xhtml.register linkrec (fun sp () () -> return (html (head (title (pcdata "")) []) (body [p [a linkrec sp [pcdata "click"] ()]])))
The server will fail on startup if there are any unregistered
services.
The function Eliom_predefmod.Xhtml.get_form allows to create a form
that uses the GET method (parameters in the URL).
It works like Eliom_predefmod.Xhtml.a but takes a function that creates the form from the parameters names as parameter.
let create_form = (fun (number_name, (number2_name, string_name)) -> [p [pcdata "Write an int: "; Eliom_predefmod.Xhtml.int_input ~input_type:`Text ~name:number_name (); pcdata "Write another int: "; Eliom_predefmod.Xhtml.int_input ~input_type:`Text ~name:number2_name (); pcdata "Write a string: "; Eliom_predefmod.Xhtml.string_input ~input_type:`Text ~name:string_name (); Eliom_predefmod.Xhtml.string_input ~input_type:`Submit ~value:"Click" ()]]) let form = register_new_service ["form"] unit (fun sp () () -> let f = Eliom_predefmod.Xhtml.get_form coucou_params sp create_form in return (html (head (title (pcdata "")) []) (body [f])))
See the function form in action.
Note that if you want to use typed parameters,
you cannot use functions like XHTML.M.input to
create your forms (if you want to use parameters defined with
Eliom_parameters.any, see later). Indeed, parameter names are typed to force them
be used properly. In our example, number_name has type
int param_name and must be used with
int_input (or other widgets), whereas
string_name has type
string param_name and must be used with
string_input (or other widgets).
All functions for creating form widgets are detailed
here.
For untyped forms, you may use functions from XHTML.M (or OCamlDuce's syntax, or whatever syntax you are using) or functions which name is prefixed by "raw_". Here is a form linking to our (untyped) service raw_serv.
let raw_form = register_new_service ~path:["anyform"] ~get_params:unit (fun sp () () -> return (html (head (title (pcdata "")) []) (body [h1 [pcdata "Any Form"]; Eliom_predefmod.Xhtml.get_form raw_serv sp (fun () -> [p [pcdata "Form to raw_serv: "; Eliom_predefmod.Xhtml.raw_input ~input_type:`Text ~name:"plop" (); Eliom_predefmod.Xhtml.raw_input ~input_type:`Text ~name:"plip" (); Eliom_predefmod.Xhtml.raw_input ~input_type:`Text ~name:"plap" (); Eliom_predefmod.Xhtml.string_input ~input_type:`Submit ~value:"Click" ()]]) ])))
Try this form.
By default Web page parameters are transferred in the URL (GET parameters). A web page may also expect POST parameters (that is, parameters that are not in the URL but in the body of the HTTP request). Use this if you don't want the user to be able to bookmark the URL with parameters, for example if you want to post some data that will change the state of the server (payment, database changes, etc). When designing a Web site, think carefully about the choice between GET or POST method for each service!
When you register a service with POST parameters, you must first register a service (fallback) without these parameters (for example that will answer if the page is reloaded without the hidden parameters, or if it is bookmarked).
let no_post_param_service = register_new_service ~path:["post"] ~get_params:unit (fun _ () () -> return (html (head (title (pcdata "")) []) (body [h1 [pcdata "Version of the page without POST parameters"]]))) let my_service_with_post_params = register_new_post_service ~fallback:no_post_param_service ~post_params:(string "value") (fun _ () value -> return (html (head (title (pcdata "")) []) (body [h1 [pcdata value]])))
Services may take both GET and POST parameters:
let get_no_post_param_service = register_new_service ~path:["post2"] ~get_params:(int "i") (fun _ i () -> return (html (head (title (pcdata "")) []) (body [p [pcdata "No POST parameter, i:"; em [pcdata (string_of_int i)]]]))) let my_service_with_get_and_post = register_new_post_service ~fallback:get_no_post_param_service ~post_params:(string "value") (fun _ i value -> return (html (head (title (pcdata "")) []) (body [p [pcdata "Value: "; em [pcdata value]; pcdata ", i: "; em [pcdata (string_of_int i)]]])))
To create a POST form, use the
Eliom_predefmod.Xhtml.post_form function.
It is similar to Eliom_predefmod.Xhtml.get_form
with an additional parameter
for the GET parameters you want to put in the URL (if any).
Here, form2 is a page containing a form
to the service post (using XHTML.M's functions)
and form3 (defined using the syntax extension)
contains a form to post2, with a GET parameter.
form4 is a form to an external page.
let form2 = register_new_service ["form2"] unit (fun sp () () -> let f = (Eliom_predefmod.Xhtml.post_form my_service_with_post_params sp (fun chaine -> [p [pcdata "Write a string: "; string_input ~input_type:`Text ~name:chaine ()]]) ()) in return (html (head (title (pcdata "form")) []) (body [f]))) let form3 = register_new_service ["form3"] unit (fun sp () () -> let f = (Eliom_predefmod.Xhtml.post_form my_service_with_get_and_post sp (fun chaine -> <:xmllist< <p> Write a string: $string_input ~input_type:`Text ~name:chaine ()$ </p> >>) 222) in return << <html> <head><title></title></head> <body>$f$</body></html> >>) let form4 = register_new_service ["form4"] unit (fun sp () () -> let f = (Eliom_predefmod.Xhtml.post_form (new_external_service ~prefix:"http://www.petizomverts.com" ~path:["zebulon"] ~get_params:(int "i") ~post_params:(string "chaine") ()) sp (fun chaine -> <:xmllist< <p> Write a string: $string_input ~input_type:`Text ~name:chaine ()$ </p> >>) 222) in return (html (head (title (pcdata "form")) []) (body [f])))
See the urls: post without parameter, post2 without POST parameter, form2, form3, form4.
Remember that a Web site written with Eliom is an OCaml application.
This application must be able to handle several requests at the same
time, in order to prevent a single request from slowing down the whole server. To make this possible, Ocsigen
is using cooperative threads
(implemented in monadic style
by Jérôme Vouillon) which make them really easy
to use (see Lwt module).
Take time to read the documentation about Lwt right now if you want to understand the following of this tutorial.
As it doesn't cooperate, the following page will stop the server for 5 seconds. No one will be able to query the server during this period:
let looong = register_new_service ~path:["looong"] ~get_params:unit (fun sp () () -> Unix.sleep 5; return (html (head (title (pcdata "")) []) (body [h1 [pcdata "Ok now, you can read the page."]])))
To solve this problem, use a cooperative version of
sleep:
let looong = register_new_service ~path:["looong"] ~get_params:unit (fun sp () () -> Lwt_unix.sleep 5.0 >>= fun () -> return (html (head (title (pcdata "")) []) (body [h1 [pcdata "Ok now, you can read the page."]])))
If you want to use, say, a database library that is not written in cooperative way, but is thread safe for preemptive threads, use the Lwt_preemptive module to detach the computation. In the following example, we simulate the request by a call to Unix.sleep:
let looong2 = register_new_service ~path:["looong2"] ~get_params:unit (fun sp () () -> Lwt_preemptive.detach Unix.sleep 5 >>= fun () -> return (html (head (title (pcdata "")) []) (body [h1 [pcdata "Ok now, you can read the page."]])))
You now have the minimum knowledge to write basic Web sites with
Eliom: page typing, service creation, parameters, forms
and database acces using Lwt
(and possibly Lwt_preemptive.detach).
Here is a summary of all other concepts introduced by Eliom.
They will allow you to easily program more complex behaviours and will be developped in the following sections of this tutorial.
Before beginning the implementation, think about the URLs you want to create as entry points to your Web site, and the services you want to provide.
Services we used, so far, are called main services. For instants, Eliom uses four kinds of services:
POST and GET parameters are not equivalent, and you must be very careful
if you want to use one or the other.
GET parameters are the parameters you see in the URL (for
example http://your_server/examples/coucou?i=42&ii=17&s=krokodile). They are created by browsers if you use forms with the GET method, or written directly in the URL.
POST parameters are sent by browsers in the body of the HTTP request. That's the only solution
if you want to send files with your request.
Remember that only pages without POST parameters are bookmarkable.
Use GET parameters if you want the user to be able to come back to the URL
later or to write the URL manually.
Use POST parameters when you want a different behaviour
between the first click and a reload of the page. Usually sending
POST parameters triggers an action on server side
(like a payment, or adding something in a database), and you don't want
it to succeed several times if the page is reloaded or bookmarked.
Services can send several types of data, using these different modules:
| Services | Coservices | |||
|---|---|---|---|---|
| attached | non-attached | attached | non-attached | |
Eliom_predefmod.Xhtml | Allows to register functions that
generate xhtml pages
statically checked using polymorphic variant types. You may use
constructor functions from XHTML.M or a syntax
extension close to the standard xhtml syntax. | |||
Eliom_predefmod.Xhtmlcompact | Same, but without pretty printing (does not add spaces or line breaks). | |||
Eliom_predefmod.Blocks | Allows to register functions that
generate a portion of page (content of the body tag) using
XHTML.M or the syntax extension.
(useful for XMLHttpRequest requests for example). | |||
Eliom_duce.Xhtml | Allows to register functions that generate xhtml pages statically checked using OCamlduce. Typing is stricter, and you need a modified version of the OCaml compiler (OCamlduce). | |||
Eliom_predefmod.HtmlText | Allows to register functions that generate text html pages, without any typechecking of the content. The content type sent by the server is "text/html". | |||
Eliom_predefmod.CssText | Allows to register functions that generate CSS pages, without any typechecking of the content. The content type sent by the server is "text/css". | |||
Eliom_predefmod.Text | Allows to register functions that generate text pages, without any typechecking of the content. The services return a pair of strings. The first one is the content of the page, the second one is the content type. | |||
Eliom_predefmod.Actions | Allows to register actions ( functions that do not generate any page). The URL is reloaded after the action. | |||
Eliom_predefmod.Unit | is like Eliom_predefmod.Actions but the
URL is not reloaded after the action. | |||
Eliom_predefmod.Redirection | [New in 1.1.0] Allows to register HTTP permanent redirections.
You register the URL of the page you want to redirect to.
Warning: According to the RFC of the HTTP protocol,
the URL must be absolute! The browser will get a 301 or 307 code in answer and redo the request to the new URL. To specify whether you want temporary (307) or permanent (301) redirections, use the ?options parameter of registration functions. For example: register options:`Permanent ... or register options:`Temporary .... | |||
Eliom_predefmod.Files | Allows to register services that send files | |||
Eliom_predefmod.Any | Allows to register services that can choose what they send, for example an xhtml page or a file, depending on some situation (parameter, user logged or not, page present in a cache ...).It is also possible to create your own modules for other types of pages. | |||
Each of these registrations may be done in the public service table, or in a session service table, accessible only to a single user of the Web site. This allows to generate custom services for a specific user.
Eliom will try to find the page, in that order:
It is also possible to create a session data table, where you can save information about the session. Each service can look in that table to see if a session is opened or not and get the data.
The most commonly used services are:
Here is a list of frequent issues and the solution Eliom provides to to solve them. Most of them will be developped in the following parts of the tutorial.
.