The Eio-native web framework for modern OCaml.
Documentation: hyphatech.github.io/spindle
- RFC-strict: its own HTTP/1.1 engine, every requirement it meets a test: RFC 9112 and 9110 for HTTP, 6455 for WebSockets, 7578 for forms, and RFC 9651's published suite for Structured Fields.
- Eio-native: straight-line handlers on OCaml 5, multicore by design.
- Typed end to end: JSON derived from your types, every input validated.
- Interactive docs: OpenAPI docs via Scalar at
/docs, generated from your routes. - Front end in sync: Zod or Melange schemas, derived from your OCaml types.
- Batteries included: SQLite and Postgres, WebSockets, SSE, sessions, logging, traces and metrics.
opam repo add hypha https://github.com/hyphatech/opam-repository.git
opam install spindleAdd to your bin/dune:
(executable
(name main)
(libraries spindle eio_main)
(preprocess (pps ppx_wiretype)))A whole project: your first app.
open Spindle.Syntax
type bill = {
total : float; [@min 0.]
tip : int; [@min 0] [@max 100] (** percent *)
people : int; [@min 1] [@max 50]
}
[@@deriving wiretype]
type share = { each : float } [@@deriving wiretype]
let split b =
let total = b.total *. float (100 + b.tip) /. 100. in
Ok { each = total /. float b.people }
let routes =
[
Spindle.post
Spindle.Path.(s "split")
(Spindle.Returns.json share_json)
(let+ b = Spindle.json bill_json in
split b);
]
let () =
Spindle.Log.setup ();
Eio_main.run @@ fun env ->
Spindle.serve env (routes @ Spindle.Openapi.routes routes)$ curl localhost:8080/split --json '{"total": 90, "tip": 10, "people": 3}'
{"each":33}Open localhost:8080/docs for interactive API docs, with nothing to
write: an OpenAPI 3.2 document generated from your routes, served by
Scalar. Every route, its schema with the bounds from
your types, every error it may answer, and a button to try it.
See AGENTS.md.
MIT, copyright Hypha Technologies Ltd. See LICENSE.
