mirror of
https://github.com/twirl/The-API-Book.git
synced 2025-05-19 21:33:04 +02:00
corrections & clarifications
This commit is contained in:
parent
4fef3e3575
commit
03de69fc0d
@ -1,6 +1,6 @@
|
|||||||
### [Bidirectional Data Flows. Push and Poll Models][api-patterns-push-vs-poll]
|
### [Bidirectional Data Flows. Push and Poll Models][api-patterns-push-vs-poll]
|
||||||
|
|
||||||
In the previous chapter, we discussed the following case: a partner receives information about new events that occurred in the system by periodically requesting an endpoint that supports retrieving ordered lists.
|
In the previous chapter, we discussed the following scenario: a partner receives information about new events occuring in the system by periodically requesting an endpoint that supports retrieving ordered lists.
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /v1/orders/created-history⮠
|
GET /v1/orders/created-history⮠
|
||||||
@ -15,63 +15,64 @@ GET /v1/orders/created-history⮠
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This pattern (known as [*polling*](https://en.wikipedia.org/wiki/Polling_(computer_science))) is the most common approach to organizing two-way communication in an API when a partner needs not only to send some data to the server but also to receive notifications from the server about changes in some state.
|
This pattern (known as [*polling*](https://en.wikipedia.org/wiki/Polling_(computer_science))) is the most common approach to organizing two-way communication in an API when a partner needs not only to send data to the server but also to receive notifications from the server about changes in some state.
|
||||||
|
|
||||||
Although this approach is quite easy to implement, polling always requires a compromise between responsiveness, performance, and system throughput:
|
Although this approach is quite easy to implement, polling always requires a compromise between responsiveness, performance, and system throughput:
|
||||||
|
|
||||||
* The longer the interval between consecutive requests, the greater the delay between the change of state on the server and receiving the information about it on the client, and the potentially larger the traffic volume that needs to be transmitted in one iteration.
|
* The longer the interval between consecutive requests, the greater the delay between the change of state on the server and receiving the information about it on the client, and the potentially larger the traffic volume that needs to be transmitted in one iteration.
|
||||||
* On the other hand, the shorter this interval, the more requests will be made in vain, as no changes in the system have occurred during the elapsed time.
|
* On the other hand, the shorter this interval, the more requests will be made in vain, as no changes in the system have occurred during the elapsed time.
|
||||||
|
|
||||||
In other words, polling always creates some background traffic in the system but never guarantees maximum responsiveness. Sometimes this problem is solved using so-called [“long polling”](https://en.wikipedia.org/wiki/Push_technology#Long_polling), i.e., by intentionally delaying the server's response for a long time (seconds, tens of seconds) until some state change occurs. However, we do not recommend using this approach in modern systems due to the associated technical problems (in particular, in unreliable network conditions, the client has no way of knowing that the connection is actually lost and a new request needs to be sent).
|
In other words, polling always generates some background traffic in the system but never guarantees maximum responsiveness. Sometimes, this problem is solved by using the so-called “[long polling](https://en.wikipedia.org/wiki/Push_technology#Long_polling),” which intentionally delays the server's response for a prolonged period (seconds, tens of seconds) until some state change occurs. However, we do not recommend using this approach in modern systems due to associated technical problems, particularly in unreliable network conditions where the client has no way of knowing that the connection is lost, and a new request needs to be sent.
|
||||||
|
|
||||||
If it turns out that regular polling is not enough to solve user problem, you can switch to a reverse model (*push*): the server itself informs the client that changes have occurred in the system.
|
If regular polling is insufficient to solve the user's problem, you can switch to a reverse model (push) in which the server itself informs the client that changes have occurred in the system.
|
||||||
|
|
||||||
Although the problem and ways to solve it look similar, completely different technologies are currently used to deliver messages from the backend to the backend and from the backend to the client device.
|
Although the problem and the ways to solve it may appear similar, completely different technologies are currently used to deliver messages from the backend to the backend and from the backend to the client device.
|
||||||
|
|
||||||
#### Delivering Notifications to Client Devices
|
#### Delivering Notifications to Client Devices
|
||||||
|
|
||||||
Since various mobile platforms currently constitute a major share of all client devices, this implies significant limitations in terms of battery (and partly traffic) saving on the technologies for data exchange between the server and the end user. Many platform and device manufacturers monitor the resources consumed by the application and can send it to the background or close open connections. In such a situation, frequent polling should only be used in active phases of the application work cycle (i.e., when the user is directly interacting with the UI) or in controlled environments (for example, if employees of a partner company use the application in their work and can add it to system exceptions).
|
As various mobile platforms currently constitute a major share of all client devices, this implies significant limitations in terms of battery and partly traffic savings on the technologies for data exchange between the server and the end user. Many platform and device manufacturers monitor the resources consumed by the application and can send it to the background or close open connections. In such a situation, frequent polling should only be used in active phases of the application work cycle (i.e., when the user is directly interacting with the UI) or in controlled environments (for example, if employees of a partner company use the application in their work and can add it to system exceptions).
|
||||||
|
|
||||||
Three alternatives to polling might be proposed:
|
Three alternatives to polling might be proposed:
|
||||||
|
|
||||||
##### Duplex Connections
|
##### Duplex Connections
|
||||||
|
|
||||||
The most obvious option is using technologies that can transmit messages in both directions over a single connection. The best-known example of such technology is [WebSocket](https://websockets.spec.whatwg.org/). Sometimes, [the Server Push functionality of the HTTP/2 protocol](https://datatracker.ietf.org/doc/html/rfc7540#section-8.2) is used for this purpose; however, we must note that the specification formally does not allow such usage. There is also the [WebRTC](https://www.w3.org/TR/webrtc/) protocol; its main purpose is a peer-to-peer exchange of media data, and it's rarely used in client-server interaction.
|
The most obvious option is to use technologies that can transmit messages in both directions over a single connection. The best-known example of such technology is [WebSocket](https://websockets.spec.whatwg.org/). Sometimes, [the Server Push functionality of the HTTP/2 protocol](https://datatracker.ietf.org/doc/html/rfc7540#section-8.2) is used for this purpose; however, we must note that the specification formally does not allow such usage. There is also the [WebRTC](https://www.w3.org/TR/webrtc/) protocol; its main purpose is a peer-to-peer exchange of media data, and it's rarely used in client-server interaction.
|
||||||
|
|
||||||
Although the idea looks simple and attractive, its applicability to real-world use cases is limited. Popular server software and frameworks do not support server-initiated message sending (gRPC does support it, but the client should initiate the exchange; using gRPC server streams to send server-initiated events is essentially employing HTTP/2 server pushes for this purpose, and it's the same technique as in long polling approach, just a bit more modern), and the existing specification definition standards do not support it — as WebSocket is a low-level protocol, and you will need to design the interaction format on your own.
|
Although the idea looks simple and attractive, its applicability to real-world use cases is limited. Popular server software and frameworks do not support server-initiated message sending (gRPC does support it, but the client should initiate the exchange; using gRPC server streams to send server-initiated events is essentially employing HTTP/2 server pushes for this purpose, and it's the same technique as in the long polling approach, just a bit more modern), and the existing specification definition standards do not support it — as WebSocket is a low-level protocol, and you will need to design the interaction format on your own.
|
||||||
|
|
||||||
Duplex connections are still suffering from the unreliability of the network and require implementing additional tricks to tell the difference between a network problem and the absence of new messages. All these issues result in limited applicability of the technology; it's mostly used in web applications.
|
Duplex connections still suffer from the unreliability of the network and require implementing additional tricks to tell the difference between a network problem and the absence of new messages. All these issues result in limited applicability of the technology; it's mostly used in web applications.
|
||||||
|
|
||||||
##### Separate Callback Channel
|
##### Separate Callback Channels
|
||||||
|
|
||||||
Instead of a duplex connection, two separate connections might be used: one for sending requests to server and one to receive notifications from server. The most popular technology of this kind is [MQTT](https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html). Although it's considered very effective because of using low-level protocols, its disadvantages follow from its advantages:
|
Instead of a duplex connection, two separate connections might be used: one for sending requests to the server and one to receive notifications from the server. The most popular technology of this kind is [MQTT](https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html). Although it is considered very effective because of utilizing low-level protocols, its disadvantages follow from its advantages:
|
||||||
* The technology is meant to implement the pub/sub pattern, and its main value is that the server software (MQTT Broker) is provider alongside the protocol itself. Applying to to different tasks, especially bidirectional communication, might be challenging.
|
* The technology is meant to implement the pub/sub pattern, and its main value is that the server software (MQTT Broker) is provided alongside the protocol itself. Applying it to other tasks, especially bidirectional communication, might be challenging.
|
||||||
* The low-level protocols force you to develop your own data formats.
|
* The low-level protocols force you to develop your own data formats.
|
||||||
|
|
||||||
There is also a Web standard for sending server notifications called [Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html) (SSE). However, it's less functional than WebSocket (only text data and unidirectional flow are allowed) and rarely used.
|
There is also a Web standard for sending server notifications called [Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html) (SSE). However, it's less functional than WebSocket (only text data and unidirectional flow are allowed) and rarely used.
|
||||||
|
|
||||||
##### Third-Party Push Notifications
|
##### Third-Party Push Notifications
|
||||||
|
|
||||||
One of the notorious problems with the long polling / WebSocket / SSE / MQTT technologies is the necessity to maintain an open network connection between the client and the server, which might be a problem for mobile applications and IoT devices from the performance and battery-saving point of view. One of the options that allow to mitigate the issue is delegating sending push notifications to a third-party service (the most popular choice today is Google's Firebase Cloud Messaging) that deliver notifications through the built-in mechanisms of the platform. Using such integrated services takes off the most of the load from the developer's shoulders related to maintaining open connections and checking their status. The disadvantages of using third-party services is the necessity to pay for them and strict limits on message sizes.
|
One of the notorious problems with the long polling / WebSocket / SSE / MQTT technologies is the necessity to maintain an open network connection between the client and the server, which might be a problem for mobile applications and IoT devices from in terms of performance and battery life. One option that allows for mitigating the issue is delegating sending push notifications to a third-party service (the most popular choice today is Google's Firebase Cloud Messaging) that delivers notifications through the built-in mechanisms of the platform. Using such integrated services takes most of the load of maintaining open connections and checking their status off the developer's shoulders. The disadvantages of using third-party services are the necessity to pay for them and strict limits on message sizes.
|
||||||
|
|
||||||
Also, sending push notifications to end-user devices suffers from one important issue: the percentage of successfully delivered message never reaches 100%; message drop rate might be tens of per cent. Taking into account the message size limitations, it's actually better to implement mixed model than pure push model: the client continues polling the server, just less frequently, and push notifications just trigger ahead-of-time polling. (This problem is actually applicable to any notification delivery technology. Low-level protocols offer more options to set delivery guarantees; however, given the situation with forceful closing open connections by OSes, having in an application low-frequency polling as a precaution is almost never a bad thing.)
|
Also, sending push notifications to end-user devices suffers from one important issue: the percentage of successfully delivered messages never reaches 100%; the message drop rate might be tens of percent. Taking into account the message size limitations, it's actually better to implement a mixed model than a pure push model: the client continues polling the server, just less frequently, and push notifications just trigger ahead-of-time polling. (This problem is actually applicable to any notification delivery technology. Low-level protocols offer more options to set delivery guarantees; however, given the situation with forceful closing of open connections by OSes, having low-frequency polling as a precaution in an application is almost never a bad thing.)
|
||||||
|
|
||||||
#### Using Push Technologies in Public APIs
|
#### Using Push Technologies in Public APIs
|
||||||
|
|
||||||
As a consequence of the fragmentation of client technologies described above, it's virtually impossible to use any of them but polling in public APIs. Requiring partners implement receiving notifications through WebSocket, MQTT, or SSE channels raises the bar of adopting the API as working with low-level protocols, poorly covered by existing IDLs and code-generation tools into the bargain, requires significant amount of effort and is prone to implementation errors. If you decide to provide ready-to-use SKDs to ease working with the API, you will need to develop it for every applicable platform (which is, let us reiterate, quite labor-consuming). Given that HTTP-polling is *much* easier to implement and its disadvantages play their role only in the situations when one *really* needs to think about saving traffic and computational resources, we would rather recommend exposing additional channels of receiving server-sent notifications *as an addition* to polling, not instead of it.
|
As a consequence of the fragmentation of client technologies described above, it's virtually impossible to use any of them but polling in public APIs. Requiring partners to implement receiving notifications through WebSocket, MQTT, or SSE channels raises the bar for adopting the API as working with low-level protocols, which are poorly covered by existing IDLs and code-generation tools, requires a significant amount of effort and is prone to implementation errors. If you decide to provide ready-to-use SDKs to ease working with the API, you will need to develop them for every applicable platform (which is, let us reiterate, quite labor-consuming). Given that HTTP polling is *much* easier to implement and its disadvantages play their role only in situations when one *really* needs to think about saving traffic and computational resources, we would rather recommend exposing additional channels for receiving server-sent notifications *as an addition* to polling, not instead of it.
|
||||||
|
|
||||||
Using platform pushes might be a fine solution for public APIs, but there another problem arises: application developers are not eager to allow other third-party services send push notifications, and that's for a list of reasons, starting with the costs of sending pushes and ending with security considerations.
|
Using platform pushes might be a fine solution for public APIs, but there another problem arises: application developers are not eager to allow other third-party services send push notifications, and that's for a list of reasons, starting with the costs of sending pushes and ending with security considerations.
|
||||||
|
|
||||||
In fact, the most convenient way of organizing message delivery from the public API backend to a partner service's user is delivering message backend-to-backend, so the partner service might relay it further using push notification or any other technology that partner selected for developing their applications.
|
In fact, the most convenient way of organizing message delivery from the public API backend to a partner service's user is by delivering messages backend-to-backend. This way, the partner service can relay it further using push notifications or any other technology that the partner selected for developing their applications.
|
||||||
|
|
||||||
#### Delivering Backend-to-Backend Notifications
|
#### Delivering Backend-to-Backend Notifications
|
||||||
|
|
||||||
Unlike client applications, server-side integrations are universally utilizing a single approach to implementing a bidirectional data flow [apart from polling, which is as applicable to server-to-server integrations as to client-server ones, and bears the same pros and cons] — a separate communication channel for callbacks. In case of public APIs, the dominating practice is using callback URLs (aka “webhooks”).
|
Unlike client applications, server-side integrations universally utilize a single approach to implementing a bidirectional data flow, apart from polling (which is as applicable to server-to-server integrations as to client-server ones, and bears the same pros and cons). The approach is using a separate communication channel for callbacks. In the case of public APIs, the dominating practice is using callback URLs, also known as “webhooks.”
|
||||||
|
|
||||||
Though long polling, WebSocket, MQTT, and HTTP/2 Push technologies are as well applicable to realizing backend-to-backend communication, we find it difficult to name a popular API that utilizes any of them. We assume that the reasons for this are:
|
Although long polling, WebSocket, HTTP/2 Push, and other technologies discussed above are also applicable to realizing backend-to-backend communication, we find it difficult to name a popular API that utilizes any of them. We assume that the reasons for this are:
|
||||||
* Lesser susceptibility to performance issues (servers rarely hit any limits on network bandwidth, and keeping an open connection is not a problem as well)
|
* Server-to-server integrations are less susceptible to performance issues (servers rarely hit any limits on network bandwidth, and keeping an open connection is not a problem as well)
|
||||||
* A broad choice of ready-to-use components to develop a *webhook* service (as it's basically a regular webserver)
|
* There are higher expectations regarding message delivery guarantees
|
||||||
* The possibility to have a specification covering the communication, and use the advantages of code-generation.
|
* A broad choice of ready-to-use components to develop a *webhook* service (as it's basically a regular webserver) is available
|
||||||
|
* It is possible to have a specification covering the communication format and use the advantages of code-generation.
|
||||||
|
|
||||||
To integrate via a *webhook*, a partner specifies a URL of their own message processing server, and the API provider calls this endpoint to notify about status changes.
|
To integrate via a *webhook*, a partner specifies a URL of their own message processing server, and the API provider calls this endpoint to notify about status changes.
|
||||||
|
|
||||||
|
@ -69,6 +69,7 @@ GET /v1/orders/created-history⮠
|
|||||||
|
|
||||||
Хотя long polling, WebSocket, MQTT и HTTP/2 Push тоже вполне применимы для backend-2-backend взаимодействия, мы сходу затрудняемся назвать примеры популярных API, которые использовали бы эти технологии. Главными причинами такого положения дел нам видятся:
|
Хотя long polling, WebSocket, MQTT и HTTP/2 Push тоже вполне применимы для backend-2-backend взаимодействия, мы сходу затрудняемся назвать примеры популярных API, которые использовали бы эти технологии. Главными причинами такого положения дел нам видятся:
|
||||||
* меньшая критичность к проблемам производительности (у сервера фактически нет ограничений по расходу трафика, и поддержание открытых соединений тоже не является проблемой);
|
* меньшая критичность к проблемам производительности (у сервера фактически нет ограничений по расходу трафика, и поддержание открытых соединений тоже не является проблемой);
|
||||||
|
* бо́льшая требовательность к гарантиям доставки;
|
||||||
* широкий выбор готовых компонентов для разработки webhook-ов (поскольку, фактически, это просто обычный веб-сервер);
|
* широкий выбор готовых компонентов для разработки webhook-ов (поскольку, фактически, это просто обычный веб-сервер);
|
||||||
* возможность описать такое взаимодействие спецификацией и использовать кодогенерацию.
|
* возможность описать такое взаимодействие спецификацией и использовать кодогенерацию.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user