dream/example/r-template-stream

r-template-stream


When a client connects to this Web app, it sends back one paragraph per second in a response stream:

let render = response => {
  %% response
  <html>
  <body>

%   let rec paragraphs = index => {
      <p><%i index %></p>
%     let%lwt () = Dream.flush(response);
%     let%lwt () = Lwt_unix.sleep(1.);
%     paragraphs(index + 1);
%   };
%   let%lwt () = paragraphs(0);

  </body>
  </html>
};

let () =
  Dream.run
  @@ Dream.logger
  @@ _ => Dream.stream(~headers=[("Content-Type", Dream.text_html)], render);
$ cd example/r-template-stream
$ npm install esy && npx esy
$ npx esy start

Visit http://localhost:8080 [playground] to see it in action.

The important differences with regular usage of templates are:

  • We create the response with Dream.stream, which is a convenience wrapper around some lower-level functions that would prepare a response for streaming.
  • We use the opening line %% response to tell the templater that we don't want to build a string, but to stream the template to a response in scope under the name response.
  • We use the promise library Lwt inside the template for asynchronous control flow. See example 5-promise for an introduction to Lwt.

The call to Dream.flush isn't necessary in most real-world cases — Dream's HTTP layer automatically schedules the writing of data. However, this example is trying to appear interactive, so we force writing of all output after generating each <p> tag.


See also:

  • r-template for the simpler way to do templates, building up entire bodies as strings.
  • 7-template section Security for XSS prevention considerations.
  • w-template-stream is the OCaml version of this example.

Up to the example index