bs-socket.io icon indicating copy to clipboard operation
bs-socket.io copied to clipboard

V2 API proposal

Open bsansouci opened this issue 4 years ago • 1 comments

Thanks @ryyppy and @peterpme for bringing this to my attention :)

This proposal should make the bindings a bit thinner, by removing the functors, while staying convenient by allowing the user to send reason data structures back and forth thanks to our serializer.

let socket = Client.create();
socket->Socket.emit("login", SharedTypes.Hi);
socket->Socket.on("message", (. x) =>
  switch (x) {
  | SharedTypes.Message(Data(s)) => Js.log("data!")
  | SharedTypes.Message(OrOthers) => Js.log("OrOthers")
  | SharedTypes.MessageOnEnter(s) => Js.log("User pressed enter")
  }
);

These bindings are now unsafe, as you can send any data with any event and nothing checks that you're going to receive the right data. I think that's pretty bad, as it effectively removes the utility of types (if you cannot trust them). I would like to fix before we ship.

One simple way would be to make the emit/on functions not have the type signature external emit: (socket, 'a, string) => unit = "emit" but something like let emit: (socket, 'a) => unit. This means the first time you call emit you restrict the type of the potential payloads to a single one, which means that type probably should take the shape:

type payload = 
  | Message(messageT)
  | Login(loginT)
  | SomeOtherThing(thingT)

It dramatically simplifies the API and brings type safety back.

An alternative would be to use GADTs, but those are no better than functors in terms of difficulty to teach.

Unrelatedly, I think writing serializers / deserializers is a huge time sink and luckily unnecessary here, as we can write a generalized one.

bsansouci avatar Apr 27 '20 21:04 bsansouci

Hey @bsansouci thanks so much for putting this together 😍

My preliminary questions:

  • What's left to cut a new release that supports socket 2.3.0?
  • I see Socket.on("message") -> does this mean that we will be forced to use message and then handle the type checking inside the callback with that generic argument?
  • If I'm not using bs-socket on the server, will this approach still work (i think its worth pointing out in the README)
  • Lastly, I know this approach is different than what @ryyppy. What makes this better?

peterpme avatar Apr 28 '20 14:04 peterpme