I’d like to discuss @jasim 's post a bit. It’s a great conversation starter but it got me thinking that we need to actually look at how such a framework would look and feel from the user’s (i.e. the web dev’s) perspective. And whenever I think of web dev, the pattern I keep coming back to is the tried-and-true MVC. And I really like how Phoenix has done it, so I keep wanting to borrow some ideas from there. So to me, here’s what a nice project layout might look like (this is native so all module names are disambiguated by dune):
dune-project
README.md
src/
dune
model/
dune
User.re
service/
dune
User.re
web/
controller/
dune
User.re
dune
middleware/
...
Server.re
template/
not-found.mustache.html
not-found.mustache.json
And here are a couple of example usages from this imaginary project: https://gist.github.com/yawaramin/f0a24f1b01b193dd6d251e5e43be65e9
So in the above snippet, the main app is set up in src/web/Server.re
. What I wanted here was a really minimalistic but also extensible way to set up routes and middlewares. And to me the way that makes the most sense to handle routing in OCaml is pattern-matching (kudos to the ReasonReact team for coming up with that simple and elegant design). So the Server
module is the heart of the app, but this being OCaml, there’s no magic involved–the route handlers are just functions from routes and requests to (promises of) responses.
Requests should contain things like the headers, query params, cookies, session, flash, body, etc.
Responses should be constructed programmatically (using ReWeb.Response.{make,makeAsync}
) or from ocaml-mustache templates (see template/
subdirectory). The response constructor function should take optional arguments for status, headers, cookies, etc. with appropriate defaults.
Middleware should be functions that take a response and return a promise of request (which might be a cancelled request); in this way they are composeable (much like Elixir’s plugs).
I haven’t touched on data access here; to be honest I’m not very familiar with the OCaml database libraries at the moment, but I am leaning towards Caqti since it seems to be active, and supports the popular OSS DBs as well as Lwt.
Scaffolding would be great to have and it would be great if dune or opam would let us do that (e.g. opam new my-app --scaffold reweb
), but in the meantime we can probably get away with maintaining example starter projects which people can copy to start with.
Lots of this is off the top of my head but what I’m trying to do here is uncover an ergonomic design for a web framework, based on learnings from recent successful frameworks. I think a large part of it would be just giving users a ‘blessed stack’ of libraries to start with, so they don’t have to go hunting throughout the ecosystem and don’t have to figure out and set up a project structure from scratch (where does the router go? where do the controllers go? where do I put the tests?). And so on.
P.S. the pattern-matching routers look really nice in OCaml syntax.