How Doshii enables real-time async communication between Apps and POS
While most webservice APIs will support a standard RESTful request/response mode of interaction, some may provide additional or alternative options via webhooks or WebSockets. These technologies enable different means of communicating with an API, with strengths and weaknesses that vary depending upon the context in which they’re used.
Regardless of platform/language, WebSockets allow for real-time communication between the connected endpoints. Either party to the connection can send data at any time, and the connection is long-lived, making WebSockets an ideal option for subscribing to server-side event feeds that may produce updates at infrequent/unknown intervals. The canonical example of a use-case that’s well-suited to using WebSockets is a web-based chat application such as Slack. There may be many users all occupying a single room/channel and sending messages at unpredictable times. Connecting each user to the server using WebSockets keeps the latency between when a user sends a new message and when the server receives it at a minimum. It also ensures that the server can then immediately distribute any new message(s) to all connected users as soon as they’re received, guaranteeing timely and consistent delivery to everyone in the conversation.
Prior to the introduction of WebSockets, this same use-case might have been addressed using interval-based polling. As its name suggests, this would involve having each client endpoint periodically (most typically on some fixed interval, though occasionally leveraging more complex algorithms such as exponential backoff) invoke (or “poll”) a webservice API to check for updates. This is a simple and easy to implement solution, however it runs into some issues when deployed at scale. In particular it leads to a constant load being exerted on the server-side even during periods of inactivity, and limits application responsiveness to whatever the polling interval happens to be. For instance, if the client polls for updates every 5 minutes, then there may be a delay of up to 5 minutes between when an event occurs and when the client learns of it. This can be mitigated somewhat by reducing the polling interval, however doing so naturally causes a corresponding increase in client and server-side load. Thus this approach tends to scale quite poorly and is extremely inefficient.
One step up from interval-based polling is HTTP long-polling. This is a technique where a client endpoint makes an HTTP request to the server, which the server then keeps open. If the server has new data to send to the client at the time it receives the request, then naturally it just sends it and the request is completed. If the server doesn’t, however, then instead of immediately completing the request with an empty response the server will hold it idle for a time, waiting to see if any new events or updates arrive. If/when they do, the server can use the idling HTTP request to immediately send the data to the client, facilitating near real-time delivery. This approach can be effective and scales more readily than interval-based polling, but can be complex to implement and remains more resource-intensive on the server-side than using WebSockets, which offer a more elegant and generally better-performing solution to the same class of problems.
While WebSockets can be quite powerful, they are not always the best solution to use. Because WebSockets are persistent over long periods of time, they require a stable, always-on network connection and active maintenance to be most effective. They are well suited to use-cases that require real-time or near real-time communication between a client and a server, particularly in cases where one or both sides need to be informed of events that may occur on the other side with little to no warning. For scenarios that lack this real-time requirement, a traditional RESTful request/response model may be more straightforward. And for cases where maintaining a long-lived, persistent connection with a server simply isn’t a workable option, webhooks may offer an alternative.
Most webservice APIs follow a standard request/response model. A client sends a request to the API server, and then the server sends back its response. These events happen on a 1:1 basis, and are always initiated by the client.
Webhooks supplement this model by turning it on its head, and essentially allow the API server to post unsolicited updates back to a client. To use a webhook the client will register a callback URL with the API provider. This step may happen well in advance of the client receiving any actual data from the API, and depending upon the API(s) you’re integrating with you may be able to configure various options such as what events you’re interested in and what data you need to receive for each one. In any case, when the API provider has new data that’s relevant to you, as the client, they will invoke the registered URL and pass new data along as part of the request payload. Your system receives the data, and can then perform whatever processing your application needs.
In essence, this is the difference between asking the driver of a bus “are we at Stop X yet?” every 5 minutes (traditional RESTful request/response model) and telling the driver when you first get on the bus to “please tell me when we get to Stop X” (webhooks). The latter approach is less overhead for both you and the driver (API provider), and also more likely to result in a timely notification that occurs very close to when the bus actually reaches ‘Stop X’. This makes webhooks ideal for situations where you want to know immediately when something happens but aren’t sure when it actually will.
Note that there are some factors that may limit or entirely prevent your ability to take advantage of webhooks. For instance, in order to receive a webhook notification, you must be able to receive an incoming request, most typically on port 80 (HTTP) or 443 (HTTPS). Network firewalls may block this ability, and NAT may frustrate it, or you may already have some other process running on these ports. You also have to know, in advance, what address the webhook needs to call. This is generally not a problem if you have your own server or a fixed deployment such as an on-premises POS system, however it can become a significant challenge if your application is running on mobile devices or otherwise in a broadly distributed fashion. At a minimum, the latter scenario requires some method of dynamically creating (and updating) webhook registrations with the API provider.
Thus, in many cases where an API offers both webhook- and WebSocket-based API’s the WebSocket option is preferable. However, webhooks can offer a viable alternative in cases where WebSockets simply are not usable, for instance due to constraints that make it impractical to maintain a persistent connection with an API provider but where real-time communication with the API is still desirable. Relying upon webhooks can also be a very low-overhead option in cases where passing data from the client to the server is seldom required or not required at all. In this scenario the client is able to consume events from the server in near real-time, without expending any resources aside from when it’s actively processing an event.
While most of the bread-and-butter work of integrating with webservice APIs will usually follow a RESTful request/response model, WebSockets and webhooks are powerful supplementary tools that can (and should) be leveraged to reduce overheads and improve performance/responsiveness within an application. They are particularly well-suited to use-cases requiring real-time or near real-time communication between a server and client. While WebSockets are generally preferred and in most scenarios come with fewer caveats than using webhooks, in certain cases webhooks can be a more appropriate choice. Which approach is best depends heavily upon the context of the application being built and the features of its runtime/deployment environment.