I’m developing a SPA with a phoenix backend that uses channels for real-time updates to all clients.
A client typically creates/updates/deletes some objects and the modifications are then broadcasted.
I see mainly 2 ways to do it:
Perform CRUD methods using HTTP requests and broadcast modifications to all clients using channels (maybe excluding the one that did the request if it got everything needed in the response).
Use HTTP only to load the SPA, then use websocket channels for all operations.
I guess that there is no clear answer to which one is the best. Using HTTP requests, we get a quite robust request/reply mechanism with HTTP status codes. Using channels, performance might be better, but we have to use some kind of request/reply (edit: most likely using channels ref) and we lose the HTTP status codes (which might not be precise enough anyway).
From your experience, what are the pros and cons of each method, particularly in regard to performance, race conditions and synchronization issues ?
maybe the time has come to treat WebSockets as first-class citizens and to start
introducing RESTful HTTP verbs to WebSockets (as naming conventions for
events). This is very new territory, but there are some important benefits to
using REST over WebSockets:
To be honest, I would probably broadcast only ids over websockets (for realtime stuff) and then retrieved the full data using regular HTTP API. Using HTTP has a lot of benefits that are often overlooked - extremely easy reporting through a multitude of tools, easy caching, easy rate-limitting, and more.
If the data is small, then it might make sense to send it all through websockets, but for big payloads the overhead of HTTP is easily outweight by the other things, primarily caching - even more so for public resources.
Thank you for your answers. As an HTTP API is not absolutely required in my case, I have some trouble to make up my mind and needed more input, you are very helpful in this regard.
As said, an HTTP RESTfull API is not required so far, but I would like to avoid having both an HTTP API and a websocket API with redundant features. Hence my hesitation. The clients compatibility is a good point.
json-pure is interesting as this would allow me for example to use a websocket only API at first but still being able to add support for an HTTP endpoint later if required, even if caching is mostly impossible in this case (and realtime feedback limited).
Why I No Longer Use MVC Frameworks article from Jean-Jacques Dubray raises some interesting considerations about GraphQL (that I am reluctant to use at this point). Also I may take his SAM pattern into consideration as I use elm for the frontend and it seems easy to implement using The Elm Architecture, even if it does not enforce it by default (as stated in this comment).
Thanks, you raise some strong points there. I am worried about performance as the clients have specific permissions that must not allow them to receive the same messages (and client filtering would be considered as a security issue). Using channels, this will require to use intercept on all messages or using per-client channels, and using HTTP, this will make intermediary caching mostly pointless (almost no public resources). But browser caching could still be possible and should indeed be taken into consideration, as well as tooling.
Well, at least it seems to me that his considerations about APIs being too much dedicated to frontend views and therefore unstable because of it make sense, even if at the end, practical “what works” will win for me. And I actually use the functional approach to adapt the model data for views (which is quite natural in elm).
Also again in elm, it is tempting to include view states in the model, which can become confusing. Having separated “view states” (even if it is one field of the model record) is an approach. Another one is to use “sub-models” as in the elm-spa-example from Richard Feldman, but it is not always wanted to loose a SPA “page” state when changing “page”. Anyway this might drift too much away from the intial intention of the post.
I will move to wss:// (it seems that using SSL in phoenix should make websockets also use SSL) and hopefully I won’t meet a customer using proxies with fake root certificates (I actually worked some years ago in a company using this, urgh…). Thanks for the link.
I’m (eventually) going for the same idea. I’m just not quite comfortable with my current Elixir skills at this point to get there, but I will get there.
Have a look at this Node.js project Feathers for some ideas. It uses websockets for it’s realtime updates. This is where I was before coming to Elixir and felt that something akin to Feathers could be done much better using Phoenix/Elixir/Erlang/OTP.