Legend:
Library
Module
Module type
Parameter
Class
Class type
Shuttle_http
Shuttle_http is a low level library for implementing HTTP/1.1 web services in OCaml using the Async library for lightweight concurrency. It allows defining services as simple OCaml functions, and supports streaming bodies to allow working with large bodies incrementally.
It supports error reporting using error handlers and provides a default implementation that responds with the error status code and an empty response body. Users can provide their own error handler implementation when setting up a server config. The library however only considers unhandled exceptions, and errors encountered while parsing the wire payload as use-cases that invoke the error handler. The expectation is that application specific errors will be dealt with by the user within their service definition.
Tutorial
Basics
Shuttle_http is not a framework and hence doesn't ship with any abstractions beyond service definitions needing to be a function that accept a request and return a deferred response.
A service definition in its most simple form might look like:
open Shuttle_http
let my_service (request : Request.t) =
return (Response.create ~body:(Body.string "Hello World") `Ok)
;;
Streaming response
We saw how to define services that respond with data that's entirely in memory. For some use-cases (Specially when working with really large bodies created from external sources like files), one might want to use a streaming body to serve large amounts of data without loading it all in memory:
open Shuttle_http
let my_service (context : Server.t) (request : Request.t) =
let%map reader =
(* This an example to show a stream that works with an external resource. *)
Reader.open_file "<some file path>"
in
(* Create a pipe from the reader that we will use as a streaming response body. *)
let reader_pipe = Reader.pipe reader in
(* Create a response from the reader's pipe. If the server is closed before the full
response was served, the pipe will be closed which in-turn will close the reader and
the underlying file descriptor. *)
Response.create ~body:(Body.of_pipe `Chunked reader_pipe) `Ok
;;
let main port =
Server.run_inet (Tcp.Where_to_listen.of_port port) my_service
;;