ReasonML - Http Server in Node.js

Since the JavaScript interop in ReasonML is really powerful nothing stops us from writing some ReasonML for Node.js.

Here's a very simple Node.js server:

module Http = {
  type lib;
  type server;
  type request;
  type response = {. [@bs.meth] "_end": string => unit};
};
[@bs.module]
external http : Http.lib = "http";

[@bs.send.pipe: Http.lib]
external createServer : ((Http.request, Http.response) => unit) => Http.server = "";

[@bs.send.pipe: Http.server]
external listen : int => Http.server = "";
http
  |> createServer((_, res) => res##_end("hello world"))
  |> listen(3333);

The above produces the following JavaScript code:

var Http = require("http");

Http.createServer((function (_, res) {
  return res.end("hello world");
})).listen(3333);

Type Safety

Because we assigned types to each of the external calls, the following code would not compile:

http |> listen(3333);

(* same as listen(3333, http) *)

The compiler will warn us the listen method cannot accept http as a parameter because the type of http is Http.lib whereas listen expects a parameter of type Http.server and the only way to produce a value of this type is to use createServer:

  This has type:
    (Http.server) => Http.server
  But somewhere wanted:
    (Http.lib) => 'a

  The incompatible parts:
    Http.server
    vs
    Http.lib