Danny Barnes, Staff Software Engineer at Coolfire, explains how Coolfire Services Foundation is built for maximally efficient data requests.
Danny Barnes: Rest API is a tried-and-true standard. It’s always the easiest thing to start with because it’s centered around standard actions applied to URLs, just like the ones used in web browsers. It requests data from a server in a simple, discrete way — you do a request of the server, and you get back a packet of data. It’s very rigid in terms of how data is returned, and the standards end when deciding how to implement a set of query string filtering and limiting mechanisms. As in, “I only want to see users whose first name starts with J.” So you can filter it in that sense, but you always get back the full record of data, with all fields included in the response.
DB: GraphQL flips that around a little bit. You can say, “Give me all users whose first name starts with J, but I’m only interested in seeing their email addresses.” GraphQL can send back just the email address rather than the whole record. You can trim out the extraneous data, which makes the data you get back much smaller and more efficient, with the only tradeoff being effectively a slightly larger request query in some cases.
GraphQL also allows you to combine objects from different collections into a single response, saving you the overhead of having to perform multiple requests to a web service and manually combining them afterward. It also saves you data by allowing you to write custom requests to the server in a multitude of ways, which can be very powerful for front-end developers to get exactly the data they need and nothing more. Even further, GraphQL supports real-time WebSocket-based retrieval of efficient data via “subscriptions.” This function allows you to “subscribe” to a query that you are interested in and automatically receive any new data returned by that query in real-time.
DB: Imagine that every time you get a user’s record from the server, it’s one kilobyte of data. Now imagine you wanted to check that user record for modifications every second. If over the course of an hour of runtime, the user’s record only changes once, that’s effectively 3600 requests and 3600 Kilobytes of data requested by the app — and all you’re really receiving is a maximum of one Kilobyte of actual new data. If you can reduce this by instructing the app to only send the new 1KB of data only when it actually changes, that’s effectively a 3600% reduction in data sent across the wire.
This scenario illustrates why we’re using Socket.IO. Let’s say I wanted to check if I’ve received any new emails. I have to ask an email server every time — essentially I manually refresh multiple times a minute. Socket.IO eliminates that by creating a real-time connection to the email server and automatically notifying me if I have a new email. New data comes in instantaneously, which is absolutely more efficient.
One of the challenges of implementing Sockets is knowing what messages to send. We’ve created a standardized messaging protocol for performing a set of create, update, and delete actions on almost any object in Coolfire. This messaging protocol is not something you get out of the box when implementing real-time WebSocket communications in your app. Socket.io merely provides the tools and connectivity to send a message, but has no opinion or suggested implementation for what those messages look like or how they are received and handled on either side. This is something that is easy to overlook when approaching the task of developing real-time communications into apps on WebSocket implementations like Socket.IO. We invented this protocol for Coolfire, and at this point, it’s standardized, general-purpose, and easy to use.
DB: Above all, we want to be able to interface with all developers. Do you only know Rest API and Sockets? Go to town. Or if you’re a cutting-edge dev shop and all your developers are excited about GraphQL like we are, we can do that too. That’s part of our strategy — to make it easier and faster across the board for developers to get in and do amazing things without having to build all of these protocols and systems. These protocols are easy to underestimate and overlook — we’ve been there and we’re using our personal experience to create this foundation for other developers to jump right in.
There are also good reasons to spread capabilities across tools. For instance, WebSockets are already in a lot of built-out tools, which makes it easy to use. There are plenty of clients who use it and really like it. On the other hand, many new clients rely more heavily on GraphQL. New developers tend to like it because it’s a client-focused development tool that makes front-end developers’ lives a lot easier. We’re actually creating some new apps for Enterprise that are almost entirely GraphQL, unlike some older apps we’ve built.
These tools do have their strengths and weaknesses, like anything else. For example, our Socket.IO protocol offers a way to subscribe to a hierarchy of “scopes” or “rooms” where you will receive all creates, updates or deletes that happen within that scope, allowing you to just receive the efficient data you need. With GraphQL subscriptions, the front-end developers’ have more control, so they can define a query based on what a user is interested in hearing rather than working within the hierarchies defined in the Coolfire scopes on the server-side. That moves control from the server to the client, although it isn’t always a good thing — the developer has to weigh the pros and cons of that for its specific application.
On the other hand, implementing Socket.IO handlers or GraphQL client libraries can be fairly complex, with some ramp-up time to learn. REST provides a straightforward way to use an API for simple use cases, and is also a standard that most developers have already worked with before. We’ve gone out of the way to implement a “bridge” between these three APIs in Coolfire so that they can all be used in the right way for the right task. If someone creates, updates, or deletes an object via the REST API in Coolfire, the subscribed Socket.IO clients and GraphQL clients will receive that object action in real-time. If someone creates, updates, or deletes an object via GraphQL mutations, the connected Socket.IO clients will receive that object action in real-time, and vice-versa.
This opens up vast possibilities for various apps to communicate with each other in a multitude of ways with Coolfire. A sensor package may be programmed to post data via REST on regular intervals without any need for real-time Socket.IO or GraphQL, but any client app connected to Coolfire with Socket.IO or GraphQL will still receive the posted data in real-time.
DB: We strategize for efficiency wherever possible. Querying large sets of data will always have the potential to be inefficient — if you’ve got a million records and you try to retrieve all of them at once, that’s obviously not going to be efficient. So you have to start tailoring it down to what you need. The same thing applies if you need real-time data.
Let’s say we have 30,000 users connected to Coolfire at one time. If every time I perform an action in Coolfire we sent out that action to all 30,000 users every time, that’s basically an amplification attack on your network. That’s how they take down servers! That won’t work. So we took the strategy of encapsulating everything into “scopes,” like networks and sessions. If I send a message to a network, only the people currently connected and interested in those messages are going to receive them. This provides a nice way to create a digital twin of your organization in Coolfire and contextualize the data to the groups or departments that already exist within your workflows.
For instance, at Enterprise Rent-a-Car, alerts would only go out to the relevant branch location depending on specific network context. The data is packaged and tiered. Of course, you could still listen at the global level if your application warrants it, but it’s probably not worthwhile with all that data. Think of this like “organizations” and “rooms” in popular chat apps like Slack — if everyone at an organization was chatting in one giant room with 30,000 users, it probably would not work very well.
DB: There’s absolutely a correlation there. As we say, “right data, right hands, right now.” Efficient data delivery speaks to that “right hands” idea. Sure, you could send buckets of data everywhere to everyone, but there’s a better way. Coolfire is all about figuring out how to encapsulate data to the point where only the relevant people are accessing or receiving it. That’s a major component of what makes situational awareness effective.
At the software level, there are certain considerations for making that happen. Anyone trying to write an app like this will have to ask themselves: How do I know who gets what? They’ve got to build some kind of structure to encapsulate the different groups of people. Let’s say it’s a first responders’ network. Which firehouse gets this message? Which users are in that firehouse? Who is getting the notifications on their devices? Developers have to build out that structure.
We found that for situational awareness tools, we were constantly building these concepts of networks and sessions that could work with users and groups of users. So we purpose-built those abstract capabilities into Coolfire Services Foundation. Basically, networks provide context for a group of users — a firehouse, a branch office, a store, or a region, for example. While networks partition off groups of users, sessions partition off moments in time. That could be a set period, a current moment, a schedule, or almost any other kind of time structure.
Based on those two factors, you can choose to send information to users within a specific network, users subscribed to a specific session or any combination of those two. This helps eliminate information overload and alert fatigue by only sending users messages and alerts that pertain to their situation, so they’re not wasting time inefficiently scrolling through mountains of data to find the one alert that pertains to them. This selective alert system helps your users be more efficient in their responses and decisions.
DB: Because we’ve been there and we’ve seen the impact situational awareness has on organizations and their people — this impact can be massive and gives us a great sense of purpose. We’ve also seen how much more effective our own developers can be at developing these types of apps with a solid services foundation to stand on. Our goal with Coolfire is to get as much of the backend overhead out of the way so developers can get busy making their impact with situational awareness.
Anyone who wants to build a situational awareness app would have to figure out many of the above features on their own, and potentially spend months doing it. We have a lot of experience in this space, so we found ourselves building the same infrastructure over and over. We’ve got the right components — Rest API, Graph QL, and Socket.IO — and we’ve worked out the system for networks, sessions, and users. Our value proposition is that now we’ve figured out that base structure that enables situational awareness, we can provide the right components, infrastructure and scalability for others to build on as well.
Essentially, we’ve built out the right backend. Now you can build your custom app on top of Coolfire, without investing time and money into that backend process, authentication schemes, messaging protocols, etc. We’ve already created the backend for you, and the expertise we’ve invested in Coolfire is all built-in. It’s a powerful tool, and there’s nothing better than seeing all the ways teams can expand on it. A lot of game-changing applications have come out of Coolfire, and we look forward to seeing many more.