Remix.run Logo
porridgeraisin 4 days ago

I really like the idea. Especially the idea where you return different RpcTargets based on the "context", that's really quite nice. Not just for authentication and such, but for representing various things like "completely structurally different output for GET /thingies for admin and users".

The promise-passing lazily evaluated approach is also nice -- any debugging woes are solved by just awaiting and logging before the await -- and it solves composability at the server - client layer. The hackiness of `map()` is unfortunate, but that's just how JS is.

However, I don't see this being too useful without there also being composability at the server - database layer. This is notoriously difficult in most databases. I wonder what the authors / others here think about this.

For an example of what I mean

  const user = rpc.getUser(id)
  const friends = await rpc.getFriends(user)
Sure beats

  GET /user/id
  GET /graph?outbound=id
But, at the end, both cases are running two different SQL queries. Most of the time when we fuse operations in APIs we do it all the way down to the SQL layer (with a join).

  GET /user/id?include=friends
Which does a join and gets the data in a single query.

So while its a nice programming model for sure, I think in practice we'll end up having a `rpc.getUserAndFriends()` anyways.

I'm not that experienced, so I don't know in how many projects composability at just one layer would actually be enough to solve most composability issues. If it's a majority, then great, but if not, then I don't think this is doing much.

One situation where this actually works that comes to mind is SQLite apps, where multiple queries are more or less OK due to lack of network round trip. Or if your DB is colocated with your app in one of the new fancy datacenters where you get DB RAM to app RAM transfer through some crazy fast network interconnect fabric (RDMA) that's quicker than even local disk sometimes.