ocaml-multicore / eio

Effects-based direct-style IO for multicore OCaml
Other
560 stars 72 forks source link

Api sdk design questions: Should an http api eio sdk delegate Eio_main.run to the caller? #354

Closed dangdennis closed 2 years ago

dangdennis commented 2 years ago

I'm rewriting https://github.com/lessp/fetch into an ocaml5 cohttp-eio client. But I require design help around eio_main calls.

  1. Is it reasonable to have each http request call Eio_main.run itself? Or should each fetch call expect an env object? piaf passes both env and eio switch to each request. It makes sense to pass these two as args to maximize the flexibility.
  2. If our implementation requires env and sw, how should I best update this fetch signature: link?

One option is make env and sw optional and generic, such that functor implementations (lwt, async) that don't use eio can ignore it.

  val fetch :
    ?env:'a ->
    ?sw:'b ->
    ?body:string ->
    ?headers:Headers.t list ->
    ?meth:Method.t ->
    string ->
    (Response.t, string) result promise
dangdennis commented 2 years ago

Saw recommendation for switch. Okay I can at least remove the switch as an argument

talex5 commented 2 years ago

Is it reasonable to have each http request call Eio_main.run itself?

No, that would prevent two requests from running at once. It would also force the use of Eio_main, which prevents using the library on other platforms such as MirageOS, or testing it with Eio_mock.Backend.

For (2), I'm not familiar with the API, but I would expect there to be some kind of t parameter with general configuration for the library (e.g. how to validate certificates, how to pool connections, etc), and things you need from env would normally go there. e.g.

  type t

  val create : #Eio.Net.t -> t

  val fetch :
    ?body:string ->
    ?headers:Headers.t list ->
    ?meth:Method.t ->
    t -> string ->
    (Response.t, string) result promise

It you don't want to change the module API, you could perhaps use a 1st-class module. e.g.

module type ENV = sig
  val net : Eio.Net.t
  ...
end

module Make(Env : ENV) : sig
  ...
end

That can be awkward to use though if you want to use it in several places, as you have to pass the module around as a parameter.

dangdennis commented 2 years ago

I had forgotten the most common design pattern in ocaml. Thanks @talex5!