Dream — a simple, yet feature-complete Web framework

I am pleased to announce Dream, a very easy-to-use Web framework with high performance, secure defaults, and thorough documentation!


sample


It is available now from opam, with opam install dream.1.0.0~alpha2.


Dream offers:

…and more, yet Dream sticks to a simple programming model:

Indeed, for those who like algebra, there is a certain structure to Dream. However, that’s not the point of this post!

Dream is meant to be very easy to understand. It sticks to base types, introducing only a few types of its own, and uses existing languages, such as HTML for templates, and URLs for routes. Dream itself is one module in one opam package, which lives in a monorepo. The docs are on one page.

Dream is loosely coupled. Even though Dream offers many defaults, it is unopinionated, and you can quickly configure or replace anything. For example, it is easy to use TyXML for templates, and Dream happily supports such usage with examples.

Security-sensitive features, such as cookies, are arranged so that simple and obvious usage is automatically secure. Wherever security still depends on the Dream app, the docs highlight it. Dream has selected a modern cipher as a default, supports key rotation, and offers suggestions for other purposes, such as password hashing. It implements and abstracts away all of the OWASP security guidelines that are relevant to its level.

Dream is designed for full internationalization. It has a centralized error handler that intercepts even lower-level HTTP errors, so that you can decorate them with your app’s own error template, and leak no hardcoded strings. Dream’s URL encoders favor internationalized (UTF-8) URIs, and the router accepts them.

Finally, Dream is designed for a wide range of applications, including with or without a proxy, standalone or embedded in larger binaries, and with external static assets or assets compiled in.


Documentation

Dream is very extensively documented. See…

  • Examples, the first several of which make up a tutorial. Each example is a complete project.
  • The online playground, which features many of the examples, and is itself a Dream app!
  • The API docs.

In particular, see


Contributing

Dream has already received several very helpful contributions, and more are very welcome! See CONTRIBUTING.md. I must also acknowledge all the people working on Dream’s dependecies and prior art. In particular, Dream relies heavily on the HTTP and WebSocket servers primarily by Spiros Eliopoulos (@seliopou) and Antonio Nuno Monteiro (@anmonteiro).

Apart from accepting code, docs, and examples, Dream will happily link to:

  • Blogs and articles, as different people learn best from different presentations.
  • “Downstream” libraries to use with Dream.

For example, Thibaut Mattio (@tmattio) is working on dream-livereload, a live-reloading middleware for Dream, similar to the example, which he also contributed! Once dream-livereload is slightly more mature, Dream will link to it from its README.

There is also dream-serve, a live-reloading static site server based on Dream and libuv, which was used to develop the docs.


Roadmap

Dream is currently in an alpha state. It is thought (by me) to be internally quite stable. However, there will probably be various API tweaks before release 1.0.0.

My current, rough plan is to release several alphas of Dream over six months or so. The releases will address:

  1. Flow control for very large responses, and getting the “advanced” part of the I/O API to be as close to zero-copy and non-allocating as possible (or reasonable).
  2. Remaining (optional) security enhancements, such as a default content security policy.
  3. Remaining session improvements, such as re-keying.
  4. Friction in handling of JSON, database access, etc. This is not properly part of or due to Dream, but it should be addressed for a better Web development experience.
  5. Multicore and effects support.


That’s all. Let’s bring OCaml to the Web! Happy Web programming!



74 Likes

For readers who saw the repo during the earlier “leak,” the main updates are:

  • A large number of new examples, including deployment.
  • The playground, which runs the examples, and itself served as a test.
  • An esy-based quick start script.

There have also been very many smaller changes to the code, API, and the rest of the docs, but the above changes are the biggest “chunks.” The rest is too much to detail :slight_smile:

15 Likes

I’ve been using dream for a project since the “leak”, and it is dope! Fantastic work with the documentation and design <3

4 Likes

I was always wondering how does the source code that uses templates work with OCaml tooling, in particular with merlin, ocp-indent, ocaml-format, tuareg and other editor modes?

2 Likes

It doesn’t work well in practice with anything other than syntax highlighting. Note that you control the syntax mode with the extension. If your template is mostly HTML, you can name it foo.eml.html.

The intent is that the templates should contain mostly HTML in a large project, and most of them would be in their own template/ subdirectory. OCaml tooling wouldn’t be needed for these mostly-HTML files. For a still-small, but real example of this, see the Playground’s client.eml.html.

The one-file .ml projects with templates, where tooling is a problem, are mostly good for the very first steps of getting started, and examples.

There is also an issue about this in the repo, #55 " how to apply ocamlformat".

Note that, as in the announcement text, you can use Dream with other templaters, including TyXML, which has an HTML PPX. In addition, if you are using Reason, you can use TyXML JSX. Either of these options interacts well with tooling, as far as I know.

I didn’t make TyXML the default because it considerably increases the Dream learning curve for getting basic tasks done. However, Dream still supports the choice of using TyXML with examples and links.

10 Likes

A playground … incredible. Fantastic job antron.

1 Like

This is a completely random note, but you might find it interesting to try to use the node child_process module to show how to use dream as a “custom server” for nextjs, as one of the more exotic examples.

1 Like

I’ve been playing around with Dream – thank you for all your hard work!

I am absolutely astonished at the effort you’ve put into writing examples. Simply on the basis of these examples alone I would expect a lot of people will try out and hopefully adopt the Dream framework. I am not aware of many frameworks that come with some many examples out of the box!

I am also loving the emphasis you have placed on simplicity and clarity in this framework. This is so helpful because one often tends to see a lot of needless complexity in software projects.

I have some comments about the *.eml.ml though:

  • I personally place a lot of emphasis on the LSP server “understanding” everything in the ml file. I will gladly pay a small price in using a templating language that places nice with the OCaml LSP server. My guess is that a lot of beginners would prefer to have a LSP server that does not stop working in certain sections of their code – that is likely to be confusing and a net negative for them. Yes, using something like tyxml is a few extra steps but to me is a still worth the effort. The average OCaml beginner tends to be reasonably sophisticated and should be OK with tyxml. As you already would know – tyxml [%html] section allows variable interpolation and ocaml lsp server continues to work properly. Even in tyml jsx, ocaml-lsp-server works.
  • While you gain some simplicity in source code using Dream specific templating you need to have a special dune rule to convert the eml.mlml which affects some of the beginner friendliness that I guess you’re aiming for

In brief, while I see your point in using the eml.ml approach I think the gains are mixed at best. I also notice that you have painstakingly pointed out that the eml.ml approach is purely optional and never compulsory anywhere. But the point is that this pattern is everywhere on the Dream website so it seems like it is the recommended approach.

My personal suggestion would be to put the tyxml approach front and center in the Dream framework examples. It plays nice with the ecosystem and does not add a “quirk” or unnecessary customization. People value cohesiveness with the broader OCaml ecosystem. Alternatively, dream framework can add its own tyxml like ppx.

I’m sure you’ve put a lot of thought into this already… would be interesting to know your opinions on this subject.

Thanks again for Dream!

8 Likes

Thanks a lot, it seems very efficient. I am converting a PHP file and find the converted program better presented (the use of a middleware for authentification is handy).

My main issue is how to launch it as a daemon…

1 Like

On Linux, you can use systemd. On macOS, equivalently launchd. On Windows, I have only a vague understanding of its ‘services’ concept, but I would look there.

My bad… simply typing ./main.exe > main.log blocked the program. I should have written

./main.exe > main.log 2>&1

I will then have to get a systemd file (starting, stoping…) and adapt it.

I use Supervisor to manage my long running processes.

1 Like

The systemd unit file would be something like:

# dream.service

[Unit]
Description=Dream server
After=network.target

[Service]
Type=simple
Restart=on-failure
User=nobody # ensure minimal access to system
Group=nobody
ExecStart=/path/to/app
PrivateTmp=yes # hide contents of /tmp from other processes on system

[Install]
WantedBy=multi-user.target

What is Dream positioning, especially compared with the fully featured Ocsigen web framework? (a few years ago there was no other real OCaml web framework I was aware of)
What are Dream’s targeted applications? (or “Who should use Dream?”)
Thanks.

Dream is more like a micro-framework that provides the bare essentials and an emphasis on security (it has good support for CSRF tokens and secure cookies etc.). Dream gives you a simple but powerful API to put together the backend web service, that’s it. It doesn’t target doing fullstack, ORMs, authentication, JWT support, and other things that big frameworks typically include.

1 Like

The Oscigen stack isn’t “just” a web framework, as commonly understood. It is a multitier programming system that targets the web platform; specifically, this means that it provides affordances for code/modules to be written once and used on one or N different “tiers” of a system (for web apps, e.g. in the browser as well as on the server side). It’s a very sophisticated and “vertically integrated” approach to developing distributed applications that is relatively less popular IME than those that use more discrete components (e.g. a backend web framework + a persistence layer + some frontend framework, all chosen separately and integrated “by hand”, so to speak).

Dream is one such discrete component; it’s strictly a backend web framework, that makes no claim on what you can or should use for the other parts of your system. I’d describe it as somewhere between rack and rails in terms of the scope of its capabilities, if that helps. I honestly wouldn’t compare it to oscigen at all, just because they really do occupy very different spaces and have very different objectives.

3 Likes