Help Making a Design Choice, AJAX vs. Websocket

Whatever your want, that is your creation. ^.^

Whatever your want, that is also your creation. ^.^

Also whatever your want, that is your creation. ^.^

Ditto, sensing a pattern yet? :wink:

Not really, same decisions with rest. Names of endpoints, connections, what data can be served, how to query for it, etc… etc… etc… :wink:

That template is an example, it is not a full REST endpoint, it is for interacting with only a single schema, and I near never see just single schema’s asked for or queried for.

Phoenix has default templates for those too, but again it all depends on just ‘what’ you are trying to accomplish.

GraphQL is just a query, think SQL, but for JSON, still very succinct and simple, it is not bound to any specific transport medium, only that GraphQL is a request and it returns JSON. You can use it over endpoints, channels, raw TCP, whatever. And GraphQL is quite used, there is plenty of documentation on it out there. Using it with channels all I did was just have a single message that I named “request” and I just take the string from it and call absinthe with it and return the results, it is the same thing you do if it is on an endpoint (though it has a plug that can save you that step, though piddly a step it is).

GraphQL Subscriptions are a new GraphQL thing (not in absinthe, they are new in general), it just lets you basically ‘register’ to a query and you get the response like normal, except you keep getting responses again and again as it changes. ^.^

That would be trivial to push over websockets as well.

1 Like

This is where I see the biggest danger with GraphQL - people deciding to simply pull an OData and expose the persistence schema all the way up to the front end, creating a franken-system, architectural and maintenance nightmare where the frontend is deeply coupled into every little aspect of the persistence layer.

GraphQL can be a big plus provided its schema is designed around consumer-driven contracts but I imagine quite often that is seen as just too much effort - and ultimately laziness will drive people to head for the next button that promises to generate a GraphQL application to expose the database as is.

This is what so many do with REST yeah…

It really should not be done with GraphQL, it is more of RPC, a function call to acquire data and get a response back, except of course you can state in what format you want the data back in. I just add a new absinthe schema/object when I need to call a new ‘function’ to get some data that I’ve not needed yet. Two of them do not even access the database at all. ^.^

…Always enlightening to watch the discussions unfold here.

I’m going to have to make some key decisions on an API architecture soon. This discussion has open up a lot of thought threads I didn’t have before :slight_smile:

Before this cools down, I would like to add http2 to the mix. Cowboy will soon support it, all major browsers do, and many server technologies already support it by default.

Doesn’t that make the pair SSE+AJAX a simpler option to solve this?

As usual I think “it depends”. I would think SSE + AJAX would scale better in a situation where the infrastructure implements HTTP caching and applications are designed to prefer cacheable non-client specific responses - but there are a lot of “fiddly bits” you have to pay attention to and get right and you have to have the volume of traffic to make it all worthwhile. I think many will forego the potential cacheability of HTTP responses and go straight for web sockets so they can just stay inside “one single communication concept”.

1 Like

Imagine you cannot take advantage of cache mechanisms (that may match AJAX better).

Just the case of clients sending plain JSON messages and servers responding JSON messages, just like you would do with Websockets.

If you take into account http2, AJAX requests have no connection overhead and are simple standard fetch requests, SSE is a plain oneliner with no dependencies, so I guess you get bidirectional comms plain&simple.

Then you can use this from vanilla js, from Vuejs, or from wherever you want. No further abstractions or 3rd party dependencies needed.

You can elaborate on top of that of course, but what I am asking is about the base bidirectional mechanism. On this scenario, what are the cases where we should prefer Websockets over SSE+AJAX?

There’s a good information on this thread but I think it speaks past the underlying question, “Should I learn WebSockets or AJAX.” So instead of trying to add more information to what has been said, I’m just going to share my experience based off the original question.

The TL;DR version is:

If you are just making requests or just learning then learn “AJAX”. It’s basically the difference between using a generalized tool and a specialized tool. When you need WebSockets you will know it. But I would never use WebSockets exclusively in my applications without a very good reason.

The long reason is:

This is like saying, “Your options are http requests or a persistent connection.” It’s really just a way of retrieving data and the simpler solution is probably http requests. The main instance where WebSockets are better is when you need to push realtime data to the client.

This is really on you. Most of the latency will be at the processing level not the connection level.

Unless you’re going to be passing massive amounts of information at once. In that case, your underlying WebSocket implementation would have to support compression to be faster.

This is a hard one for me to answer. I don’t think either are particularly hard to learn and Phoenix will take out a lot of the pain in WebSockets. However, you will have to use the bundled Phoenix JavaScript libraries.

As long as you can abstract the data layer in your Vue.js application then it really won’t matter that much anyway.

HTTP requests, hands down. But I imagine that it doesn’t matter much actually. Since either of the methods are just about updating the underlying data. Depending on your level of expertise, once you learn how things work with one of them, then using the other is trivial.

I would begin with the fact they are not mutually exclusive. I’ve seen several applications that will use POST requests to send data while listening on a separate WebSocket for pushed real time data. One in particular, could send data across the WebSocket, but for some very good reasons decide not to. However, they could not accomplish listening to real time data the way they wanted over a polling solution.

If you’re just presenting and updating state in the Vue.js application and the Elixir application is for managing state, then there is no reason to use WebSockets besides novelty. If you wanted to learn some things about WebSockets it would be a good exercise. However, if you don’t know how to use Async Web Requests in the first place, you really need to start there.

Also, the things you may learn from using Phoenix channels would not necessarily translate to broader WebSocket knowledge. Phoenix makes using WebSockets easy, but WebSockets are not necessarily simple.

2 Likes

I’m not sure why some keep saying websockets are not necessarily simple, even with the base javascript API they are a simple ‘send this string’ or ‘we got an event of a string received’ (or a bytearray or whatever you want to read it as). Phoenix’s javascript client is a pretty thin wrapper that let’s you register ‘names’ to messages pretty easily (though you could have done that yourself easily too).

Even with HTTP/2 you are assuming the AJAX would be fast without the setup/teardown if the connection stays up, which is not always going to happen. It can be closed down for any reason, it can be closed once initial information is sent. It can be closed if the browser is throttling connections from too many open tabs. Etc… etc… SSE is interesting, but websockets already supports what it does and with a near identical API as well for receiving events/messages from the server, just no support for sending events back with SSE (hence why using ajax to make those requests).

Also that is a moot point right now anyway, cowboy (Plug’s web server) does not support HTTP2 at the version that Plug requires. ^.^;
(Hope that gets fixed soon!)

Still though, comparing API’s between ajax and phoenix sockets (even both done with basic javascript) is pretty on par, just websockets is a case where it should always be faster. Even AJAX requests over an open HTTP2 socket still sends headers and cookies and all sorts of stuff that still causes processing time and have to flow through the whole router and all.

1 Like

I don’t know enough about HTTP/2 to comment, but I don’t agree on the simplicity of WebSockets.

Ok so on simple level they can accomplish the same thing, I send a request across the socket and get a response on the same socket. On that level there is no difference.

Now, requests have a very particular send -> receive flow. I send a request I get a response back or I don’t for whatever reason. If a delete succeeds, then maybe I get a 204 response. Let’s do that on a WebSocket, I send a message over the WebSocket and then wait to receive a response. I have to keep track of the fact I made that request so I can inform the user of a success or failure. That is automatic with a regular request.

What if my deletes are expensive, so to provide a good user experience I provide a loading circle and let the user keep browsing and inform them when I’m done. Then they delete 2 more things. With web requests every request will have a response and I will have a promise or something to inform me of what action is succeeding or failing. With WebSockets, I have to keep track of those actions in the messages, then do the work of parsing and managing the messages then invoking a callback manually.

Now, those things are trivial for experienced developers. I knew exactly what I had to do, and knew how to route errors and such back correctly. A junior developer who doesn’t really understand how “AJAX” requests work would not.

There are like 5 other things that Phoenix provides around WebSockets that I can think of off the top of my head that aren’t easy. So I think calling it a thin wrapper is a little misleading, but that’s also a subjective assessment. :smile:

3 Likes

Just pass a tag back and forth, that is what I’ve seen done on every websocket interface to date, and is in fact what phoenix’s library wraps for you anyway. :slight_smile:

The tag format handles that too, nothing special there.[quote=“Azolo, post:30, topic:5145”]
Now, those things are trivial for experienced developers. I knew exactly what I had to do, and knew how to route errors and such back correctly. A junior developer who doesn’t really understand how “AJAX” requests work would not.
[/quote]

Eh not really, about every RPC system that I’ve ever seen in any language on any system follows the tag style as well, it is quite ubiquitous.

Actually for websocket related stuff it handles the tagging (a unique integer per request is its format), it handles reconnecting if the connection dies (with a heartbeat even, where-as if that happened in AJAX your javascript would not be called until the TCP timeout of 30 minutes or a browser internal timeout is hit, which can be very very very long regardless), and it handles abstracting out topics (basically just a namespace for the messaging, which is easy to do yourself by, oh, adding a single extra tag, which consequently is how phoenix does it too). :slight_smile:

I agree those things are simple and easy for us. But are those things as intuitive for a junior developer? Also those things are decisions from past knowledge. Ask @Emily, decisions are hard.

If my friend, who has come right out of school, were to ask me the same question. I would tell him to use regular requests unless he needs to push real-time data to the client or he gets a better grasp on the Vue.js data situation.

My friend who has been in banking for years and is learning web development, I would tell them to use as little JavaScript as possible or let me create the backend.

From what I could see, this wasn’t @Emily’s only problem nor was it a problem that really should be stressed over. In any, I would never recommend learning WebSockets over AJAX requests.

2 Likes

Which is great that Phoenix already wrote the interface for us, now you just do myTopic.send and all such simple things instead, more simple than AJAX even then, you get JSON back immediately with no parsing needed. :slight_smile:

This thread has been a good read. Will mention 2 things I don’t think I saw here yet.

  1. there are things you get on the connection object with a full http request (through AJAX) you don’t in the websocket. So if you want the requesters IP on the server side for example you’ll find it there already waiting for you with ajax.

  2. phoenix does indeed make websockets very easy and I’ve chosen to use them 99% of the time. But I don’t like to underestimate that designing for channels is completely different and depending on application complexity could be hard to get used to. For example I once designed something that when I added features you’d have to join dozens of channels to keep the data feed consistent… with a simple design change it went down to 1, but it still involved a refactor. Or bugs like accidentally pushing a client update to everyone on a certain page. Again for someone experienced in this, less of an issue.

I’m basing this completely on developer comfort, not speed/scale/etc

Without knowing either I think AJAX is a good choice. Then again if you start with websockets maybe you end up with a pretty cool untarnished perspective… hrm :slight_smile: what’s your risk tolerance…

1 Like

In what cases, it is recommended to use GraphQL over websockets, and vice versa?

It is not an exclusive over… It means using GraphQL with websocket as the transport layer :slight_smile:

And vice versa is not possible in that case.

1 Like

GraphQL is transport-layer-generic, it doesn’t care what it goes over, so websockets are good when you need more real-time communication, and things like absinthe can set up subscriptions over websockets to get live updates to singular queries. :slight_smile:

1 Like

I had a similar question so I thought I just asked it here.

In my app I have a form which has two select inputs, one for “Units” and one for “Subjects”, and Units have many Subjects.

So what I want is when you select a Unit, only Subjects belonging to that Unit will appear on the select box for Subjects. Simple enough.

Is this “feature” too simple to justify using Channels? After reading this thread it seems a simple AJAX request should be more appropriate, but I have zero experience with AJAX and little with Channels.

Eh for autocomplete a simple ajax tends to be fine, unpoly even makes it very simple, or you can server-drive it over phoenix channels by using the Drab library, which lets you drive it from phoenix over a websocket rather transparently.

2 Likes