package twirp_ezcurl
Install
Dune Dependency
Authors
Maintainers
Sources
sha256=40a20849cadaa41d0b870a8b0f3894ab560a27a7dda821cf14e1c67bfa81b08b
sha512=1fd0a0851da62c24f3c64b487dd7e877c5da0edb19a1234cd822d997067e6b7afbe6764e790f32a850e0cc7a860f9d5787e3766bfafe756c46fc062db96dad43
README.md.html
Twirp
This is an OCaml implementation of Twirp that relies on ocaml-protoc (version 3 or above) to compile protobuf IDL files.
License
MIT license
Usage
In the following examples we use a basic "calculator" service as an example:
syntax = "proto3";
// single int
message I32 {
int32 value = 0;
}
// add two numbers
message AddReq {
int32 a = 1;
int32 b = 2;
}
// add an array of numbers
message AddAllReq {
repeated int32 ints = 1;
}
service Calculator {
rpc add(AddReq) returns (I32);
rpc add_all(AddAllReq) returns (I32);
}
We assume there's a dune rule to extract it into a pair of .ml and .mli files:
(rule
(targets calculator.ml calculator.mli)
(deps calculator.proto)
(action
(run ocaml-protoc --binary --pp --yojson --services --ml_out ./ %{deps})))
Using Tiny_httpd as a server
The library twirp_tiny_httpd
uses Tiny_httpd as a HTTP server to host services over HTTP 1.1.
Tiny_httpd is a convenient little HTTP server with no dependencies that uses direct style control flow and system threads, rather than an event loop. Realistically, it is sufficient for low traffic services (say, less than 100 req/s), and is best used coupled with a thread pool such as Moonpool to improve efficiency.
detailed example
See 'examples/twirp_tiny_httpd/' for an example:
module H = Tiny_httpd
open Calculator
(* here we give concrete implementations for each of the
methods of the service. *)
module Service_impl = struct
let add (a : add_req) : i32 = default_i32 ~value:Int32.(add a.a a.b) ()
let add_all (a : add_all_req) : i32 =
let l = ref 0l in
List.iter (fun x -> l := Int32.add !l x) a.ints;
default_i32 ~value:!l ()
end
(* instantiate the code-generated [Calculator] service
to turn it into a [Pbrt_services.Server.t] abstract service. *)
let calc_service : Twirp_tiny_httpd.handler Pbrt_services.Server.t =
Calculator.Server.make
~add:(fun rpc -> Twirp_tiny_httpd.mk_handler rpc Service_impl.add)
~add_all:(fun rpc -> Twirp_tiny_httpd.mk_handler rpc Service_impl.add_all)
()
let () =
let port = try int_of_string (Sys.getenv "PORT") with _ -> 8080 in
Printf.printf "listen on http://localhost:%d/\n%!" port;
(* create the httpd on the given port *)
let server = H.create ~port () in
(* register the service in the httpd (adds routes) *)
Twirp_tiny_httpd.add_service ~prefix:(Some "twirp") server calc_service;
H.run_exn server
We implement the concrete service Calculator
, then turn it into a Pbrt_services.Server.t
(which is an abtract representation of any service: a set of endpoints). We can then create a [Tiny_httpd.Server.t] (a web server) and register the service (or multiple services) in it. This will add new routes (e.g. "/twirp/foo.bar.Calculator/add") and call the functions we defined above to serve these routes.
Using ezcurl as a client
The library twirp_ezcurl
uses Ezcurl as a Curl wrapper to provide Twirp clients.
Curl is very widely available and is a robust HTTP client; ezcurl adds a simple OCaml API on top. Twirp_ezcurl is best used for low-traffic querying of services.
full example
Example (as in 'examples/twirp_ezcurl/') that computes `31 + 100` remotely:let spf = Printf.sprintf
let () =
let port = try int_of_string (Sys.getenv "PORT") with _ -> 8080 in
Printf.printf "query on http://localhost:%d/\n%!" port;
let r =
match
(* call [Calculator.add] with arguments [{a=31; b=100}] *)
Twirp_ezcurl.call ~use_tls:false ~host:"localhost" ~port
Calculator.Calculator.Client.add
@@ Calculator.default_add_req ~a:31l ~b:100l ()
with
| Ok x -> x.value |> Int32.to_int
| Error err ->
failwith (spf "call to add failed: %s" @@ Twirp_ezcurl.show_error err)
in
Printf.printf "add call: returned %d\n%!" r;
()
The main function is Twirp_ezcurl.call
, which takes a remote host, port, service endpoint (code-generated from a .proto
file), and an argument, and performs a HTTP query. The user can provide an already existing Curl client to reuse, turn TLS off or on, and pick the wire format (JSON or binary protobuf).