mirror of
https://github.com/twirl/The-API-Book.git
synced 2025-05-31 22:09:37 +02:00
major refactoring
This commit is contained in:
parent
a24a670b0f
commit
40dab74771
BIN
docs/API.en.epub
BIN
docs/API.en.epub
Binary file not shown.
517
docs/API.en.html
517
docs/API.en.html
File diff suppressed because one or more lines are too long
BIN
docs/API.en.pdf
BIN
docs/API.en.pdf
Binary file not shown.
BIN
docs/API.ru.epub
BIN
docs/API.ru.epub
Binary file not shown.
196
docs/API.ru.html
196
docs/API.ru.html
File diff suppressed because one or more lines are too long
BIN
docs/API.ru.pdf
BIN
docs/API.ru.pdf
Binary file not shown.
@ -62,8 +62,8 @@
|
||||
<ul class="section">
|
||||
<li><a href="API.en.html#intro-structure">Chapter 1. On the Structure of This Book</a></li>
|
||||
<li><a href="API.en.html#intro-api-definition">Chapter 2. The API Definition</a></li>
|
||||
<li><a href="API.en.html#intro-api-solutions-overview">Chapter 3. An Overview of Existing API Development Solutions</a></li>
|
||||
<li><a href="API.en.html#intro-api-quality">Chapter 4. API Quality Criteria</a></li>
|
||||
<li><a href="API.en.html#intro-api-quality">Chapter 3. API Quality Criteria</a></li>
|
||||
<li><a href="API.en.html#intro-api-choosing-solutions">Chapter 4. Choosing Solutions for API Development</a></li>
|
||||
<li><a href="API.en.html#intro-api-first-approach">Chapter 5. The API-First Approach</a></li>
|
||||
<li><a href="API.en.html#intro-back-compat">Chapter 6. On Backward Compatibility</a></li>
|
||||
<li><a href="API.en.html#intro-versioning">Chapter 7. On Versioning</a></li>
|
||||
@ -112,7 +112,7 @@
|
||||
<li>
|
||||
<h4><a href="API.en.html#section-5">Section IV. HTTP APIs & the REST Architectural Principles</a></h4>
|
||||
<ul class="section">
|
||||
<li><a href="API.en.html#http-api-concepts">Chapter 33. On the HTTP API Concept and Terminology</a></li>
|
||||
<li><a href="API.en.html#http-api-concepts">Chapter 33. On the HTTP API Concept. Paradigms of Developing Client-Server Communication</a></li>
|
||||
<li><a href="API.en.html#http-api-pros-and-cons">Chapter 34. Advantages and Disadvantages of HTTP APIs Compared to Alternative Technologies</a></li>
|
||||
<li><a href="API.en.html#http-api-rest-myth">Chapter 35. The REST Myth</a></li>
|
||||
<li><a href="API.en.html#http-api-requests-semantics">Chapter 36. Components of an HTTP Request and Their Semantics</a></li>
|
||||
@ -125,7 +125,7 @@
|
||||
<li>
|
||||
<h4><a href="API.en.html#section-6">[Work in Progress] Section V. SDKs & UI Libraries</a></h4>
|
||||
<ul class="section">
|
||||
<li><a href="API.en.html#sdk-toc">Chapter 41. On the Content of This Section</a></li>
|
||||
<li><a href="API.en.html#sdk-toc-technology-overview">Chapter 41. On Terminology. An Overview of Technologies for UI Development</a></li>
|
||||
<li><a href="API.en.html#sdk-problems-solutions">Chapter 42. SDKs: Problems and Solutions</a></li>
|
||||
<li><a href="API.en.html#sdk-ui-components">Chapter 43. Problems of Introducing UI Components</a></li>
|
||||
<li><a href="API.en.html#sdk-decomposing">Chapter 44. Decomposing UI Components</a></li>
|
||||
|
@ -62,8 +62,8 @@
|
||||
<ul class="section">
|
||||
<li><a href="API.ru.html#intro-structure">Глава 1. О структуре этой книги</a></li>
|
||||
<li><a href="API.ru.html#intro-api-definition">Глава 2. Определение API</a></li>
|
||||
<li><a href="API.ru.html#intro-api-solutions-overview">Глава 3. Обзор существующих решений в области разработки API</a></li>
|
||||
<li><a href="API.ru.html#intro-api-quality">Глава 4. Критерии качества API</a></li>
|
||||
<li><a href="API.ru.html#intro-api-quality">Глава 3. Критерии качества API</a></li>
|
||||
<li><a href="API.ru.html#intro-api-choosing-solutions">Глава 4. Выбор подхода к разработке API</a></li>
|
||||
<li><a href="API.ru.html#intro-api-first-approach">Глава 5. API-first подход</a></li>
|
||||
<li><a href="API.ru.html#intro-back-compat">Глава 6. Обратная совместимость</a></li>
|
||||
<li><a href="API.ru.html#intro-versioning">Глава 7. О версионировании</a></li>
|
||||
@ -112,7 +112,7 @@
|
||||
<li>
|
||||
<h4><a href="API.ru.html#section-5">Раздел IV. HTTP API и архитектурные принципы REST</a></h4>
|
||||
<ul class="section">
|
||||
<li><a href="API.ru.html#http-api-concepts">Глава 33. О концепции HTTP API и терминологии</a></li>
|
||||
<li><a href="API.ru.html#http-api-concepts">Глава 33. О концепции HTTP API. Парадигмы разработки клиент-серверного взаимодействия</a></li>
|
||||
<li><a href="API.ru.html#http-api-pros-and-cons">Глава 34. Преимущества и недостатки HTTP API в сравнении с альтернативными технологиями</a></li>
|
||||
<li><a href="API.ru.html#http-api-rest-myth">Глава 35. Мифология REST</a></li>
|
||||
<li><a href="API.ru.html#http-api-requests-semantics">Глава 36. Составляющие HTTP запросов и их семантика</a></li>
|
||||
@ -125,7 +125,7 @@
|
||||
<li>
|
||||
<h4><a href="API.ru.html#section-6">[В разработке] Раздел V. SDK и UI</a></h4>
|
||||
<ul class="section">
|
||||
<li><a href="API.ru.html#sdk-toc">Глава 41. О содержании раздела</a></li>
|
||||
<li><a href="API.ru.html#sdk-toc-technology-overview">Глава 41. Терминология. Обзор технологий разработки SDK</a></li>
|
||||
<li><a href="API.ru.html#sdk-problems-solutions">Глава 42. SDK: проблемы и решения</a></li>
|
||||
<li><a href="API.ru.html#sdk-ui-components">Глава 43. Проблемы встраивания UI-компонентов</a></li>
|
||||
<li><a href="API.ru.html#sdk-decomposing">Глава 44. Декомпозиция UI-компонентов</a></li>
|
||||
|
@ -30,7 +30,7 @@ HTTP was developed to transfer hypertext which poorly fits for developing progra
|
||||
|
||||
On one hand, HTTP was a simple and easily understandable protocol for making arbitrary calls to remote servers using their domain names. On the other hand, it quickly gained a wide range of extensions beyond its base functionality. Eventually, HTTP became another “attractor” where all the network technology stacks converge. Most API calls within TCP/IP networks are made through the HTTP protocol. However, unlike the TCP/IP case, it is each developer's own choice which parts of the functionality provided by the HTTP protocol and its numerous extensions they are going to use. Remarkably enough, HTTP was a full antithesis to RPC as it does not provide any native wrappers to make remote calls, let alone memory sharing. Instead, HTTP provided some useful concepts to improve the scalability of client-server systems, such as managing caches out of the box and the idea of transparent proxies.
|
||||
|
||||
As a result, starting from the mid-'90s, RPC frameworks were gradually abolished in favor of a new approach, to which Roy Fielding in his doctoral dissertation of 2001 gave the name “Representational State Transfer” or “REST” (to be discussed in the corresponding chapter). In the new paradigm, the relations between data and operations on it were inversed:
|
||||
As a result, starting from the mid-'90s, RPC frameworks were gradually abolished in favor of a new approach, to which Roy Fielding in his doctoral dissertation of 2000 gave the name “Representational State Transfer” or “REST” (to be discussed in the corresponding chapter). In the new paradigm, the relations between data and operations on it were inversed:
|
||||
* Clients do not call procedures on a remote server, passing the call parameters. Instead, they provide an abstract address (a *locator*) of a data fragment (a *resource*) to which the operation is to be applied.
|
||||
* The list of operations is restricted to a limited and standardized number of actions with clearly defined semantics.
|
||||
* The client and the server are independent and, in principle, do not share any state — any parameters needed to fulfill the operation must be transmitted explicitly.
|
||||
|
@ -1,6 +1,17 @@
|
||||
### [Advantages and Disadvantages of HTTP APIs Compared to Alternative Technologies][http-api-pros-and-cons]
|
||||
|
||||
After reviewing the previous chapter, the reader may wonder why this dichotomy exists in the first place, i.e., why do some HTTP APIs rely on HTTP semantics, while others reject it in favor of custom arrangements, and still others are stuck somewhere in between? For example, if we consider the JSON-RPC response format,[ref JSON-RPC 2.0 Specification. Response object](https://www.jsonrpc.org/specification#response_object) we quickly notice that it could be replaced with standard HTTP protocol functionality. Instead of this:
|
||||
As we discussed in the previous chapter, today, the choice of a technology for developing client-server APIs comes down to selecting either a resource-oriented approach (commonly referred to as “REST API”; let us reiterate that we will use the term “HTTP API” instead) or a modern RPC protocol. As we mentioned earlier, *conceptually* the difference is not that significant. However, *technically* these frameworks use the HTTP protocol quite differently:
|
||||
|
||||
**First**, different frameworks rely on different data formats:
|
||||
* HTTP APIs and some RPC protocols (such as *JSON-RPC*[ref JSON-RPC](https://www.jsonrpc.org/), *GraphQL*[ref GraphQL](https://graphql.org/), etc.) use the *JSON*[ref JSON](https://www.ecma-international.org/publications-and-standards/standards/ecma-404/) format (sometimes with additional endpoints for transferring binary data).
|
||||
* *gRPC*[ref gRPC](https://grpc.io/) and some specialized RPC protocols like *Thrift*[ref Apache Thrift](https://thrift.apache.org/) and *Avro*[ref Apache Avro](https://avro.apache.org/docs/) utilize binary formats (such as *Protocol Buffers*[ref Protocol Buffers](https://protobuf.dev/), *FlatBuffers*[ref FlatBuffers](https://flatbuffers.dev/), or *Apache Avro*'s own format).
|
||||
* Finally, some RPC protocols (notably *SOAP*[ref SOAP](https://www.w3.org/TR/soap12/) and *XML-RPC*[ref XML-RPC](http://xmlrpc.com/)) employ the *XML*[ref Extensible Markup Language (XML)](https://www.w3.org/TR/xml/) data format (which is considered a rather outdated practice by many developers).
|
||||
|
||||
**Second**, these approaches utilize HTTP capabilities differently:
|
||||
* Either the client-server interaction heavily relies on the features described in the HTTP standard, or
|
||||
* HTTP is used as a transport, with an additional abstraction layer built upon it (i.e., the HTTP capabilities, such as headers and status codes nomenclatures, are deliberately reduced to a bare minimum, and all metadata is handled by the higher-level protocol).
|
||||
|
||||
The reader may wonder why this dichotomy exists in the first place, i.e., why some HTTP APIs rely on HTTP semantics, while others reject it in favor of custom arrangements, and still others are stuck somewhere in between. For example, if we consider the JSON-RPC response format,[ref JSON-RPC 2.0 Specification. Response object](https://www.jsonrpc.org/specification#response_object) we quickly notice that it could be replaced with standard HTTP protocol functionality. Instead of this:
|
||||
|
||||
```json
|
||||
HTTP/1.1 200 OK
|
||||
@ -15,11 +26,13 @@ HTTP/1.1 200 OK
|
||||
}
|
||||
```
|
||||
|
||||
the server could have simply responded with a `400 Bad Request`, passing the request identifier as a custom header like `X-OurCoffeeAPI-RequestId`. Nevertheless, protocol designers decided to introduce their own custom format.
|
||||
the server could have simply responded with a `400 Bad Request`, passing the request identifier as a custom header like `X-JSONRPC2-RequestId`. Nevertheless, protocol designers decided to introduce their own custom format.
|
||||
|
||||
This situation (not only with JSON-RPC but with essentially every high-level protocol built on top of HTTP) has developed due to various reasons. Some of them are historical (such as the inability to use many HTTP protocol features in early implementations of the `XMLHttpRequest` functionality in web browsers). However, new RPC protocols relying on the bare minimum of HTTP capabilities continue to emerge today. We can enumerate at least four groups of reasons leading to this situation.
|
||||
This situation (not only with JSON-RPC but with essentially every high-level protocol built on top of HTTP) has developed due to various reasons. Some of them are historical (such as the inability to use many HTTP protocol features in early implementations of the `XMLHttpRequest` functionality in web browsers). However, new RPC protocols that rely on the bare minimum of HTTP capabilities continue to emerge today.
|
||||
|
||||
##### Metadata readability
|
||||
We can enumerate at least three groups of reasons (apart from the ideological ones, which we described in the previous chapter) leading to this situation:
|
||||
|
||||
##### Metadata Readability
|
||||
|
||||
Let us emphasize a very important distinction between application-level protocols (such as JSON-RPC in our case) and pure HTTP. In the example above, a `400 BadRequest` error is a transparent status for every intermediary network agent but a JSON-RPC custom error is not. Firstly, only a JSON-RPC-enabled client can read it. Secondly, and more importantly, in JSON-RPC, the request status *is not metadata*. In pure HTTP, the details of the operation, such as the method, requested URL, execution status, and request / response headers are readable *without the necessity to parse the entire body*. In most higher-level protocols, including JSON-RPC, this is not the case: even a protocol-enabled client must read a body to retrieve that information.
|
||||
|
||||
@ -29,9 +42,9 @@ How does an API developer benefit from the capability of reading request and res
|
||||
* Intermediary proxy servers between a client and a server
|
||||
* Various abstractions used in server programming, including server frameworks, programming languages, and operating systems
|
||||
* Web server software that is typically placed in front of backend handlers
|
||||
* Additional modern microservice-oriented tools such as API gateways and proxies
|
||||
* Additional modern microservice-oriented tools such as API gateways and proxies.
|
||||
|
||||
The main advantage that following the letter of the HTTP standard offers is the possibility to rely on intermediary agents, from client frameworks to API gateways, to read the request metadata and perform actions based on it. This includes regulating timeouts and retry policies, logging, proxying, and sharding requests, among other things, without the necessity to write additional code to achieve these functionalities. If we try to formulate the main principle of designing HTTP APIs, it will be: **you would rather design an API in a way that intermediary agents can read and interpret request and response metadata**.
|
||||
The main advantage that following the letter of the HTTP standard offers is the possibility of relying on intermediary agents, from client frameworks to API gateways, to read the request metadata and perform actions based on it. This includes regulating timeouts and retry policies, logging, proxying, and sharding requests, among other things, without the necessity to write additional code to achieve these functionalities. If we try to formulate the main principle of designing HTTP APIs, it will be: **you would rather design an API in a way that intermediary agents can read and interpret request and response metadata**.
|
||||
|
||||
The main disadvantage of HTTP APIs is that you have to rely on intermediary agents, from client frameworks to API gateways, to read the request metadata and perform actions based on it *without your consent*. This includes regulating timeouts and retry policies, logging, proxying, and sharding requests, among other things. Since HTTP-related specifications are complex and the concepts of REST can be challenging to comprehend, and software engineers do not always write perfect code, these intermediary agents (including partners' developers!) will sometimes interpret HTTP metadata *incorrectly*, especially when dealing with exotic and hard-to-implement standards. Usually, one of the stated reasons for developing new RPC frameworks is the desire to make working with the protocol simple and consistent, thereby reducing the likelihood of errors when writing integration code.
|
||||
|
||||
@ -44,18 +57,10 @@ The ability to read and interpret the metadata of requests and responses leads t
|
||||
|
||||
Of course, most of these instruments will work with APIs that utilize other paradigms. However, the ability to read HTTP metadata and interpret it *uniformly* makes it possible to easily design complex pipelines such as exporting nginx access logs to Prometheus and generating response status code monitoring dashboards in Grafana that work out of the box.
|
||||
|
||||
The downside of this versatility is the quality of these solutions and the amount of time one needs to integrate them, especially if one's technological stack is not common. On the other hand, the development of alternative technologies is usually driven by a single large IT company (such as Facebook, Google, or Apache Software Foundation). Such a framework might be less functional, but it will certainly be more homogeneous and qualitative in terms of convenience for developers, supporting users, and the number of known issues.
|
||||
The downside of this versatility is the quality of these solutions and the amount of time one needs to integrate them, especially if one's technological stack is not common. On the other hand, the development of alternative technologies is usually driven by a single large IT company (such as Facebook, Google, or the Apache Software Foundation). Such a framework might be less functional, but it will certainly be more homogeneous and qualitative in terms of convenience for developers, supporting users, and the number of known issues.
|
||||
|
||||
This observation applies not only to software but also to its creators. Developers' knowledge of HTTP APIs is fragmented as well. Almost every programmer is capable of working with HTTP APIs to some extent, but a significant number of them lack a thorough understanding of the standards and do not consult them while writing code. As a result, implementing business logic that effectively and consistently works with HTTP APIs can be more challenging than integrating alternative technologies. This statement holds true for both partner integrators and API providers themselves.
|
||||
|
||||
Additionally, let's emphasize that the HTTP API paradigm is currently the default choice for *public* APIs. Because of the aforementioned reasons, partners can integrate an HTTP API without significant obstacles, regardless of their technological stack. Moreover, the prevalence of the technology lowers the entry barrier and the requirements for the qualification of partners' engineers.
|
||||
|
||||
##### The Design Paradigm
|
||||
|
||||
Modern HTTP APIs inherited the design paradigm from the times when the HTTP protocol was mainly used to transfer hypertext. It implies that an HTTP request constitutes an operation performed on some object (*a resource*) identified by a URL. Many alternative solutions stick to other concepts; notably, in these technologies, URLs identify *a function* to call with the given parameters. This semantics doesn't exactly contradict the HTTP architectural principles, as making remote procedure calls is covered by the protocol pretty well, but it makes using some HTTP capabilities (such as, let's say, the `Range-*` headers) meaningless, and some even dangerous as ambivalences of interpretations of some fields (such as, let's say, `ETag`) arise.
|
||||
|
||||
From the client developers' perspective, following the HTTP paradigms implies implementing an additional layer of logic that transforms calling methods on objects to HTTP operations on corresponding resources. RPC technologies are more convenient to integrate in this sense. (Although, any complex RPC API will require such an adapter level, and GraphQL requires it from the very beginning.)
|
||||
|
||||
##### The Question of Performance
|
||||
|
||||
When discussing the advantages of alternative technologies such as GraphQL, gRPC, Apache Thrift, etc., the argument of lower performance of JSON-over-HTTP APIs is often presented. Specifically, the following issues with the technology are commonly mentioned:
|
||||
@ -67,13 +72,14 @@ When discussing the advantages of alternative technologies such as GraphQL, gRPC
|
||||
4. The need to introduce additional encoding, such as Base64, to handle binary data
|
||||
5. Performance quirks of the HTTP protocol itself, particularly the inability to serve multiple simultaneous requests through one connection.
|
||||
|
||||
Let's be honest: HTTP APIs do suffer from the listed problems. However, we can confidently say that the impact of these factors is often overestimated. The reason API vendors care little about HTTP API performance is that the actual overhead is not as significant as perceived. Specifically:
|
||||
Let's be honest: HTTP APIs do suffer from the listed problems. However, we can confidently say that the impact of these factors is often overestimated. The reason API vendors care little about HTTP API performance is that the actual overhead is not as significant as it is perceived. Specifically:
|
||||
|
||||
1. Regarding the verbosity of the format, it is important to note that these issues are mainly relevant when compresiion algorithms are not utilized. Comparisons have shown[ref Comparing sizes of protobuf vs json](https://nilsmagnus.github.io/post/proto-json-sizes/) that enabling compression algorithms such as *gzip* largely reduces the difference in sizes between JSON documents and alternative binary formats (and there are compression algorithms specifically designed for processing text data, such as *brotli*[ref Brotli Compressed Data Format](https://datatracker.ietf.org/doc/html/rfc7932)).
|
||||
1. Regarding the verbosity of the format, it is important to note that these issues are mainly relevant when compression algorithms are not utilized. Comparisons have shown[ref Comparing sizes of protobuf vs json](https://nilsmagnus.github.io/post/proto-json-sizes/) that enabling compression algorithms such as *gzip* largely reduces the difference in sizes between JSON documents and alternative binary formats (and there are compression algorithms specifically designed for processing text data, such as *brotli*[ref Brotli Compressed Data Format](https://datatracker.ietf.org/doc/html/rfc7932)).
|
||||
|
||||
2. If necessary, API designers can customize the list of returned fields in HTTP APIs. It aligns well with both the letter and the spirit of the standard. However, as we already explained to the reader in the “[Partial Updates](#api-patterns-partial-updates)” chapter, trying to minimize traffic by returning only subsets of data is rarely justified in well-designed APIs.
|
||||
|
||||
3. If standard JSON deserializers are used, the overhead compared to binary standards might indeed be significant. However, if this overhead is a real problem, it makes sense to consider alternative JSON serializers such as *simdjson*[ref simdjson : Parsing gigabytes of JSON per second](https://github.com/simdjson/simdjson). Due to their low-level and highly optimized code, *simdjson* demonstrates impressive throughput which would be suitable for all APIs except some corner cases.
|
||||
* The combination of gzip/brotli + simdjson largely renders the use of optimized JSON derivatives, such as BSON, unnecessary in client-server communication.[ref BSON](https://bsonspec.org/)
|
||||
|
||||
4. Generally speaking, the HTTP API paradigm implies that binary data (such as images or video files) is served through separate endpoints. Returning binary data in JSON is only necessary when a separate request for the data is a problem from the performance perspective. These situations are virtually non-existent in server-to-server interactions and/or if HTTP/2 or a higher protocol version is used.
|
||||
|
||||
@ -89,7 +95,34 @@ However, on many occasions (including this book) developers prefer the textual J
|
||||
|
||||
Apart from being human-readable, JSON features another important advantage: it is strictly formal meaning it does not contain any constructs that can be interpreted differently in different architectures (with a possible exception of the sizes of numbers and strings), and the deserialization result aligns very well with native data structures (i.e., indexed and associative arrays) of almost every programming language. From this point of view, we actually had no other choice when selecting a format for code samples in this book.
|
||||
|
||||
If you happen to design a less general API for a specific subject area, we still recommend the same approach for choosing a format:
|
||||
* Estimate the overhead of preparing and introducing tools to decipher binary protocols versus the overhead of using not the most optimal data transfer protocols.
|
||||
* Make an assessment of what is more important to you: having a quality but restricted in its capabilities set of bundled software or having the possibility of using a broad range of tools that work with HTTP APIs, even though their quality is not that high.
|
||||
* Evaluate the cost of finding developers proficient with the format.
|
||||
#### Choosing a Client-Server Development Technology
|
||||
|
||||
As we see, HTTP APIs and alternative RPC protocols occupy different market niches:
|
||||
* For public APIs, exposing JSON-over-HTTP endpoints is the default option because the technology:
|
||||
* Is familiar to a broad circle of software engineers
|
||||
* Allows for developing applications on top of virtually any platform.
|
||||
* For specialized APIs, choosing specialized frameworks (such as selecting Apache Avro to work with Apache Hadoop) is an obvious solution.
|
||||
|
||||
The practice of providing public APIs in, let's say, gRPC format has been slowly gaining popularity but is still close to negligible. Therefore, the selection problem only arises when we discuss private general-purpose APIs. As of today, the choice appears to be as follows:
|
||||
* HTTP (“REST”) API
|
||||
* gRPC
|
||||
* GraphQL
|
||||
* Other smaller technologies which we will skip.
|
||||
|
||||
**gRPC** is a classical second-generation technology featuring all the advantages we discussed earlier:
|
||||
* It relies on the state-of-the-art capabilities of the HTTP/2 protocol and the Protobuf data exchange format (the latter is non-mandatory, although the majority of gRPC API implementations use it).
|
||||
* It is developed by Google and comes with a broad selection of tools.
|
||||
* It features the contract-first approach, i.e., developing an API begins with writing a specification.
|
||||
* The use of code generation allows for conveniently working with the protocol in imperative programming languages.
|
||||
|
||||
The disadvantages of gRPC are:
|
||||
* The complexity of decoding messages and debugging communication.
|
||||
* Poor support of Web browsers.
|
||||
* Its less widespread adoption, which results in a higher entry threshold for developers.
|
||||
* Potential vendor lock-in.
|
||||
|
||||
Otherwise, gRPC is undoubtedly one of the most advanced and efficient protocols.
|
||||
|
||||
**GraphQL** features a curious approach that combines the concept of “resources” in HTML (i.e., it focuses on detailed descriptions of data formats and domain relations) while providing a rich query vocabulary to retrieve the needed subset of fields. Its main application is in data-heavy subject areas with complex entity hierarchies. (As evident from the name, GraphQL is more of a mechanism for distributed querying of abstract data storages than an API development paradigm.) Exposing *external* GraphQL APIs is rather an exotic practice as of today, mainly because managing a GraphQL service becomes increasingly challenging with growing data size and query numbers.[ref Mehta, S., Barodiya, K. Lessons learned from running GraphQL at scale](https://blog.dream11engineering.com/lessons-learned-from-running-graphql-at-scale-2ad60b3cefeb)
|
||||
|
||||
**NB**: in theory, an API could provide a dual interface — let's say, both JSON-over-HTTP and gRPC. Since the formal description of data formats and applicable operations is fundamental to all modern frameworks, these formats could be converted from one to another, thus making such a multi-API possible. However, in practice, we are not aware of any examples of such an API. We would venture to say that the potential benefits of increased convenience for developers do not outweigh the overhead expenses of maintaining dual interfaces.
|
@ -1,8 +1,8 @@
|
||||
### [The REST Myth][http-api-rest-myth]
|
||||
|
||||
Before we proceed to discuss HTTP API design patterns, we feel obliged to clarify one more important terminological issue. Often, an API matching the description we gave in the “[On the HTTP API Concept and Terminology](#http-api-concepts)” chapter is called a “REST API” or a “RESTful API.” In this Section, we don't use any of these terms as it makes no practical sense.
|
||||
Before we proceed to discuss HTTP API design patterns, we feel obliged to clarify one more important terminological issue. Often, an API matching the description we gave in the “[On the HTTP API Concept](#http-api-concepts)” chapter is called a “REST API” or a “RESTful API.” In this Section, we don't use any of these terms as it makes no practical sense.
|
||||
|
||||
What is “REST”? In 2000, Roy Fielding, one of the authors of the HTTP and URI specifications, published his doctoral dissertation titled “Architectural Styles and the Design of Network-based Software Architectures,” the fifth chapter of which was named “Representational State Transfer (REST).[ref:{"short":"Fielding, R. (2000)","extra":["Architectural Styles and the Design of Network-based Software Architectures","Representational State Transfer (REST)"]}](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm)”
|
||||
What is “REST”? As we mentioned earlier, in 2000, Roy Fielding, one of the authors of the HTTP and URI specifications, published his doctoral dissertation titled “Architectural Styles and the Design of Network-based Software Architectures,” the fifth chapter of which was named “Representational State Transfer (REST).[ref:{"short":"Fielding, R. (2000)","extra":["Architectural Styles and the Design of Network-based Software Architectures","Representational State Transfer (REST)"]}](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm)”
|
||||
|
||||
As anyone can attest by reading this chapter, it features a very much abstract overview of a distributed client-server architecture that is not bound to either HTTP or URL. Furthermore, it does not discuss any API design recommendations. In this chapter, Fielding methodically *enumerates restrictions* that any software engineer encounters when developing distributed client-server software. Here they are:
|
||||
* The client and the server do not know how each of them is implemented
|
||||
@ -36,7 +36,7 @@ The concept of “Fielding-2008 REST” implies that clients, after somehow obta
|
||||
|
||||
We have no idea why, out of all the overviews of abstract network-based software architecture, Fielding's concept gained such popularity. It is obvious that Fielding's theory, reflected in the minds of millions of software developers, became a genuine engineering subculture. By reducing the REST idea to the HTTP protocol and the URL standard, the chimera of a “RESTful API” was born, of which nobody knows the definition.[ref Gupta, L. What is REST](https://restfulapi.net/)
|
||||
|
||||
Do we want to say that REST is a meaningful concept? Definitely not. We only aimed to explain that it allows for quite a broad range of interpretations, which is simultaneously its main power and its main weakness.
|
||||
Do we want to say that REST is a meaningless concept? Definitely not. We only aimed to explain that it allows for quite a broad range of interpretations, which is simultaneously its main power and its main weakness.
|
||||
|
||||
On one hand, thanks to the multitude of interpretations, the API developers have built a perhaps vague but useful view of “proper” HTTP API architecture. On the other hand, the lack of concrete definitions has made REST API one of the most “holywar”-inspiring topics, and these holywars are usually quite meaningless as the popular REST concept has nothing to do with the REST described in Fielding's dissertation (and even more so, with the REST described in Fielding's manifesto of 2008).
|
||||
|
||||
|
@ -12,4 +12,12 @@ This Section will be dedicated to these two types of program toolkits:
|
||||
|
||||
To avoid being wordy, we will use the term “SDK” for the former and “UI libraries” for the latter.
|
||||
|
||||
**NB**: Strictly speaking, a UI library might either include a client-server API “wrapper” or not (i.e., just provide a “pure” API to some underlying system engine). In this Section, we will mostly talk about the first option as it is the most general case and the most challenging one in terms of API design. Most SDK development patterns we will discuss are also applicable to “pure” libraries.
|
||||
**NB**: Strictly speaking, a UI library might either include a client-server API “wrapper” or not (i.e., just provide a “pure” API to some underlying system engine). In this Section, we will mostly talk about the first option as it is the most general case and the most challenging one in terms of API design. Most SDK development patterns we will discuss are also applicable to “pure” libraries.
|
||||
|
||||
#### Selecting a Framework for UI Component Development
|
||||
|
||||
As UI is a high-level abstraction built upon OS primitives, there are specialized visual component frameworks available for almost every platform. Choosing such a framework might be regretfully challenging. For instance, in the case of the Web platform, which is both low-level and highly popular, the number of competing technologies for SDK development is beyond imagination. We could mention the most popular ones today, including React[ref React](https://react.dev/), Angular[ref Angular](https://angular.io/), Svelte[ref Svelte](https://svelte.dev/), Vue.js[ref Vue.js](https://vuejs.org/), as well as those that maintain a strong presence like Bootstrap[ref Bootstrap](https://getbootstrap.com/) and Ember.[ref Ember](https://emberjs.com/) Among these technologies, React demonstrates the most widespread adoption, still measured in single-digit percentages.[ref How Many Websites Use React in 2023? (Usage Statistics)](https://increditools.com/react-usage-statistics/) At the same time, components written in “pure” JavaScript/CSS often receive criticism for being less convenient to use in these frameworks as each of them implements a rigid methodology. The situation with developing visual libraries for Windows is quite similar. The question of “which framework to choose for developing UI components for these platforms” regretfully has no simple answer. In fact, one will need to evaluate the markets and make decisions regarding each individual framework.
|
||||
|
||||
In the case of actual mobile platforms (and MacOS), the current state of affairs is more favorable as they are more homogeneous. However, a different problem arises: modern applications typically need to support several such platforms simultaneously, which leads to code (and API nomenclatures) duplication.
|
||||
|
||||
One potential solution could be using cross-platform mobile (React Native[ref React Native](https://reactnative.dev/), Flutter[ref Flutter](https://flutter.dev/), Xamarin[ref Xamarin](https://dotnet.microsoft.com/en-us/apps/xamarin), etc.) and desktop (JavaFX[ref JavaFX](https://openjfx.io/), QT[ref QT](https://www.qt.io/), etc.) frameworks, or specialized technologies for specific tasks (such as Unity[ref Unity](https://docs.unity3d.com/Manual/index.html) for game development). The inherent advantages of these technologies are faster code-writing and universalism (of both code and software engineers). The disadvantages are obvious as well: achieving maximum performance could be challenging, and many platform tools (such as debugging and profiling) will not work. As of today, we rather see a parity between these two approaches (several independent applications for each platform vs. one cross-platform application).
|
@ -52,7 +52,7 @@ try {
|
||||
Достаточно очевидно, что подобного рода подход крайне редко реализуется в распределённых сетевых API, из-за комплекса связанных проблем:
|
||||
|
||||
1. Ожидание получения блокировки вносит во взаимодействие дополнительные плохо предсказуемые и, в худшем случае, весьма длительные задержки.
|
||||
2. Сама по себе блокировка — это ещё одна сущность, для работы с которой нужно иметь отдельную весьма производительную подсистему, поскольку для работы блокировок требуется ещё и обеспечить сильную консистентность в API: метод `getPendingOrders` должен вернуть актуальное состояние системы, иначе повторный заказ всё равно будет создан.
|
||||
2. Сама по себе блокировка — это ещё одна сущность, для работы с которой нужно иметь отдельную весьма производительную подсистему, поскольку для работы блокировок требуется ещё и обеспечить сильную консистентность[ref Strong consistency](https://en.wikipedia.org/wiki/Strong_consistency) в API: метод `getPendingOrders` должен вернуть актуальное состояние системы, иначе повторный заказ всё равно будет создан.
|
||||
3. Поскольку клиентская часть разрабатывается сторонними партнёрами, мы не можем гарантировать, что написанный ими код корректно работает с блокировками; неизбежно в системе появятся «висящие» блокировки, а, значит, придётся предоставлять партнёрам инструменты для отслеживания и отладки возникающих проблем.
|
||||
4. Необходимо разработать достаточную гранулярность блокировок, чтобы партнёры не могли влиять на работоспособность друг друга. Хорошо, если мы можем ограничить блокировку, скажем, конкретным конечным пользователем в конкретной системе партнёра; но если этого сделать не получается (например, если система авторизации общая и все партнёры имеют доступ к одному и тому же профилю пользователя), то необходимо разрабатывать ещё более комплексные системы, которые будут исправлять потенциальные ошибки в коде партнёров — например, вводить квоты на блокировки.
|
||||
|
||||
|
@ -37,7 +37,7 @@ GET /v1/orders/created-history↵
|
||||
|
||||
Самый очевидный вариант — использование технологий, позволяющих передавать по одному соединению сообщения в обе стороны. Наиболее известной из таких технологий является WebSockets[ref WebSockets](https://websockets.spec.whatwg.org/). Иногда для организации полнодуплексного соединения применяется Server Push, предусмотренный протоколом HTTP/2[ref Hypertext Transfer Protocol Version 2 (HTTP/2). Server Push](https://datatracker.ietf.org/doc/html/rfc7540#section-8.2), однако надо отметить, что формально спецификация не предусматривает такого использования. Также существует протокол WebRTC[ref WebRTC](https://www.w3.org/TR/webrtc/), но он, в основном, используется для обмена медиа-данными между клиентами, редко для клиент-серверного взаимодействия.
|
||||
|
||||
Несмотря на то, что идея в целом выглядит достаточно простой и привлекательной, в реальности её использование довольно ограничено. Поддержки инициирования *сервером* отправки сообщения обратно на клиент практически нет в популярном серверном ПО и фреймворках (gRPC поддерживает потоки сообщений с сервера, но их всё равно должен инициировать клиент; использование потоков для пересылки сообщений по мере их возникновения — то же самое использование HTTP/2 Server Push в обход спецификации, что, фактически, работает как тот же самый long polling, только чуть более современный), и существующие стандарты спецификаций API также не поддерживают такой обмен данными: WebSockets является низкоуровневым протоколом, и формат взаимодействия придётся разработать самостоятельно.
|
||||
Несмотря на то, что идея в целом выглядит достаточно простой и привлекательной, в реальности её использование довольно ограничено. Поддержки инициирования *сервером* отправки сообщения обратно на клиент практически нет в популярном серверном ПО и фреймворках (gRPC поддерживает потоки сообщений с сервера[ref gRPC. Server streaming RPC](https://grpc.io/docs/what-is-grpc/core-concepts/#server-streaming-rpc), но их всё равно должен инициировать клиент; использование потоков для пересылки сообщений по мере их возникновения — то же самое использование HTTP/2 Server Push в обход спецификации, что, фактически, работает как тот же самый long polling, только чуть более современный), и существующие стандарты спецификаций API также не поддерживают такой обмен данными: WebSockets является низкоуровневым протоколом, и формат взаимодействия придётся разработать самостоятельно.
|
||||
|
||||
Дуплексные соединения по-прежнему страдают от ненадёжной сети и требуют дополнительных ухищрений для того, чтобы отличить сетевую проблему от отсутствия новых сообщений. Всё это приводит к тому, что данная технология используется в основном веб-приложениями.
|
||||
|
||||
@ -47,7 +47,7 @@ GET /v1/orders/created-history↵
|
||||
* технология в первую очередь предназначена для имплементации паттерна pub/sub и ценна наличием соответствующего серверного ПО (MQTT Broker); применить её для других задач, особенно для двунаправленного обмена данными, может быть сложно;
|
||||
* низкоуровневый протокол диктует необходимость разработки собственного формата данных.
|
||||
|
||||
Существует также веб-стандарт отправки серверных сообщений Server-Sent Events[ref Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html) (SSE). Однако по сравнению с WebSocket он менее функциональный (только текстовые данные, однонаправленный поток сообщений) и поэтому используется редко.
|
||||
Существует также веб-стандарт отправки серверных сообщений Server-Sent Events[ref HTML Living Standard. Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html) (SSE). Однако по сравнению с WebSocket он менее функциональный (только текстовые данные, однонаправленный поток сообщений) и поэтому используется редко.
|
||||
|
||||
##### Сторонние сервисы отправки push-уведомлений
|
||||
|
||||
@ -130,7 +130,7 @@ GET /v1/orders/created-history↵
|
||||
|
||||
Однако все проблемы Webhook-ов, описанные нами выше, для таких обратных вызовов всё ещё актуальны. Вызов внутреннего сервиса всё ещё может окончиться false negative-ошибкой, внутренние клиенты могут не ожидать нарушения порядка пересылки сообщений и так далее.
|
||||
|
||||
Для решения этих проблем, а также для большей горизонтальной масштабируемости технологий обратного вызова, были созданы сервисы очередей сообщений[ref Message Queue](https://en.wikipedia.org/wiki/Message_queue) и, в частности, различные серверные реализации паттерна pub/sub. В настоящий момент pub/sub-архитектуры пользуются большой популярностью среди разработчиков, вплоть до перевода любого межсервисного взаимодействия на очереди событий.
|
||||
Для решения этих проблем, а также для большей горизонтальной масштабируемости технологий обратного вызова, были созданы сервисы очередей сообщений[ref Message Queue](https://en.wikipedia.org/wiki/Message_queue) и, в частности, различные серверные реализации паттерна pub/sub[ref Publish / Subscribe Pattern](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern). В настоящий момент pub/sub-архитектуры пользуются большой популярностью среди разработчиков, вплоть до перевода любого межсервисного взаимодействия на очереди событий.
|
||||
|
||||
**NB**: отметим, что ничего бесплатного в мире не бывает, и за эти гарантии доставки и горизонтальную масштабируемость необходимо платить:
|
||||
* межсерверное взаимодействие становится событийно-консистентным со всеми вытекающими отсюда проблемами;
|
||||
|
@ -30,7 +30,7 @@ HTTP появился изначально для передачи размеч
|
||||
|
||||
Поскольку, с одной стороны, HTTP был простым и понятным протоколом, позволяющим осуществлять произвольные запросы к удаленным серверам по их доменным именам, и, с другой стороны, быстро оброс почти бесконечным количеством разнообразных расширений над базовой функциональностью, он стал второй точкой, к которой сходятся сетевые технологии: практически все запросы к API внутри TCP/IP-сетей осуществляются по протоколу HTTP (и даже если используется альтернативный протокол, запросы в нём всё равно зачастую оформлены в виде HTTP-пакетов просто ради удобства). HTTP, однако, идеологически совершенно противоположен RPC, поскольку не предполагает ни нативной обвязки для функций удалённого вызова, ни тем более разделяемого доступа к памяти. Зато HTTP предложил несколько очень удобных концепций для наращивания производительности серверов, такие как управление кэшированием из коробки и концепцию прозрачных прокси.
|
||||
|
||||
В итоге в середине 1990-х годов происходит постепенный отказ от RPC-фреймворков первого поколения в пользу нового подхода, который позднее Рой Филдинг в своей диссертации 2001 года обобщит под названием «Representational State Transfer» или «REST» (о чём мы поговорим чуть позже в соответствующей главе). В новой парадигме отношения между данными и операциями над ними переворачиваются с ног на голову:
|
||||
В итоге в середине 1990-х годов происходит постепенный отказ от RPC-фреймворков первого поколения в пользу нового подхода, который позднее Рой Филдинг в своей диссертации 2000 года обобщит под названием «Representational State Transfer» или «REST» (о чём мы поговорим чуть позже в соответствующей главе). В новой парадигме отношения между данными и операциями над ними переворачиваются с ног на голову:
|
||||
* клиент не вызывает процедуры на сервере с передачей параметров — клиент указывает серверу абстрактный адрес (локатор) фрагмента данных (*ресурса*), к которому он хочет применить операцию;
|
||||
* сам список операций лимитирован и стандартизирован, семантика их чётко определена в стандарте;
|
||||
* клиент и сервер независимы и *принципиально* не имеют никакого разделяемого состояния; все необходимые для исполнения операции параметры должны быть переданы явно;
|
||||
|
@ -1,10 +1,10 @@
|
||||
### [Преимущества и недостатки HTTP API в сравнении с альтернативными технологиями][http-api-pros-and-cons]
|
||||
|
||||
Как мы обсудили в предыдущей главе, в настоящий момент выбор технологии для разработки клиент-серверных API сводится к выбору либо ресурсоориентированного подхода (то, что принято называть «REST API», а мы, напомним, будем использовать термин «HTTP API»), либо одного из современных RPC-протоколов. Как мы отмечали, *концептуально* разница не очень значительна; однако *технически* разные фреймворки используют протокол совершенно по-разному:
|
||||
Как мы обсудили в предыдущей главе, в настоящий момент выбор технологии для разработки клиент-серверных API сводится к выбору либо ресурсоориентированного подхода (то, что принято называть «REST API», а мы, напомним, будем использовать термин «HTTP API»), либо одного из современных RPC-протоколов. Как мы отмечали, *концептуально* разница не очень значительна; однако *технически* разные фреймворки используют протокол HTTP совершенно по-разному:
|
||||
|
||||
**Во-первых**, разные фреймворки опираются на разные форматы передаваемых данных:
|
||||
* HTTP API и некоторые RPC (JSON-RPC[ref JSON-RPC](https://www.jsonrpc.org/), GraphQL[ref GraphQL](https://graphql.org/)) полагаются в основном на формат JSON[ref JSON](https://www.ecma-international.org/publications-and-standards/standards/ecma-404/) (опционально дополненный передачей бинарных файлов);
|
||||
* gRPC[ref gRPC](https://grpc.io), а также Apache Avro[ref Apache Avro](https://avro.apache.org/docs/) и другие специализированные RPC-протоколы полагаются на бинарные форматы (такие как Protocol Buffers[ref Protocol Buffers](https://protobuf.dev/), FlatBuffers[ref FlatBuffers](https://flatbuffers.dev/) и собственный формат Apache Avro);
|
||||
* gRPC[ref gRPC](https://grpc.io), а также Thrift[ref Apache Thrift](https://thrift.apache.org/), Avro[ref Apache Avro](https://avro.apache.org/docs/) и другие специализированные RPC-протоколы полагаются на бинарные форматы (такие как Protocol Buffers[ref Protocol Buffers](https://protobuf.dev/), FlatBuffers[ref FlatBuffers](https://flatbuffers.dev/) и собственный формат Apache Avro);
|
||||
* наконец, некоторые RPC-протоколы (SOAP[ref SOAP](https://www.w3.org/TR/soap12/), XML-RPC[ref XML-RPC](http://xmlrpc.com/)) используют для передачи данных формат XML[ref Extensible Markup Language (XML)](https://www.w3.org/TR/xml/) (что многими разработчиками сегодня воспринимается скорее как устаревшая практика).
|
||||
|
||||
**Во-вторых**, существующие реализации различаются подходом к утилизации протокола HTTP:
|
||||
@ -81,6 +81,7 @@ HTTP/1.1 200 OK
|
||||
2. Вообще говоря, если такая нужда появляется, то и в рамках HTTP API вполне можно регулировать список возвращаемых полей ответа, это вполне соответствует духу и букве стандарта. Однако, мы должны заметить, что экономия трафика на возврате частичных состояний (которую мы рассматривали подробно в главе «[Частичные обновления](#api-patterns-partial-updates)») очень редко бывает оправдана.
|
||||
|
||||
3. Если использовать стандартные десериализаторы JSON, разница по сравнению с бинарными форматами может оказаться действительно очень большой. Если, однако, эти накладные расходы являются проблемой, стоит обратиться к альтернативным десериализаторам — в частности, simdjson[ref simdjson : Parsing gigabytes of JSON per second](https://github.com/simdjson/simdjson). Благодаря оптимизированному низкоуровневому коду simdjson показывает отличную производительность, которой может не хватить только совсем уж экзотическим API.
|
||||
* Комбинация gzip/brotli + simdjson во многом делает бессмысленным использование в клиент-серверной коммуникации оптимизированных вариантов JSON — таких как, например, BSON[ref BSON](https://bsonspec.org/).
|
||||
|
||||
4. Вообще говоря, парадигма HTTP API подразумевает, что для бинарных данных (такие как изображения или видеофайлы) предоставляются отдельные эндпойнты. Передача бинарных данных в теле JSON-ответа необходима только в случаях, когда отдельный запрос за ними представляет собой проблему с точки зрения производительности. Такой проблемы фактически не существует в server-2-server взаимодействии и в протоколе HTTP 2.0 и выше.
|
||||
|
||||
@ -96,31 +97,34 @@ HTTP/1.1 200 OK
|
||||
|
||||
Помимо человекочитаемости у JSON есть ещё одно важное преимущество: он максимально формален. В нём нет никаких конструкций, которые могут быть по-разному истолкованы в разных архитектурах (с точностью до ограничений на длины чисел и строк), и при этом он удобно ложится в нативные структуры данных (индексные и ассоциативные массивы) почти любого языка программирования. С этой точки зрения у нас фактически не было никакого другого выбора, какой ещё формат данных мы могли бы использовать при написании примеров кода для этой книги.
|
||||
|
||||
В случае же разработки API менее общего назначения, мы рекомендуем подходить к выбору формата по тому же принципу:
|
||||
* взвесить накладные расходы на подготовку и внедрение инструментов чтения бинарных форматов и расшифровки бинарных протоколов против накладных расходов на неоптимальную передачу данных;
|
||||
* оценить, хватит ли вам качественного, но ограниченного в возможностях набора программного обеспечения, идущего в комплекте с альтернативным форматом, или вам важнее возможность использовать широкий спектр инструментов, умеющих работать с HTTP API, пусть они и не всегда высокого качества;
|
||||
* прикинуть, насколько дорого вам обойдутся разработчики, способные работать с этим форматом.
|
||||
|
||||
#### Выбор технологии разработки клиент-серверного API
|
||||
|
||||
Как мы видим из вышесказанного, HTTP API и альтернативные RPC-протоколы занимают разные ниши:
|
||||
* для публичных API архитектурный стиль REST является выбором по умолчанию, поскольку он (а) понятен максимально широкому кругу разработчиков, (б) позволяет разрабатывать клиентские приложения практически на любой платформе;
|
||||
* для публичных API предоставление JSON-over-HTTP эндпойнтов является выбором по умолчанию, поскольку эта технология:
|
||||
* понятна максимально широкому кругу программистов;
|
||||
* позволяет разрабатывать клиентские приложения практически на любой платформе;
|
||||
* для узкоспециализированных API логично использовать узкоспециализированные фреймворки (например, Apache Avro для работы с Apache Hadoop).
|
||||
|
||||
Практика предоставления публичных API в формате, скажем, gRPC, постепенно набирает популярность, но пока ещё незначительна на общем фоне. Таким образом, проблема выбора технологии возникает только для непубличных API общего назначения. На сегодня этот выбор выглядит так:
|
||||
* REST API;
|
||||
* HTTP («REST») API;
|
||||
* gRPC;
|
||||
* GraphQL;
|
||||
* множество технологий поменьше, на которых мы не будем останавливаться подробно.
|
||||
|
||||
gRPC является классической технологией второго поколения, сочетающей все перечисленные выше достоинства:
|
||||
* полагается на новейшие возможности протокола HTTP/2 и эффективный формат обмена данными Protobuf (последнее необязательно, но практически мы не встречали имплементаций gRPC API поверх других форматов данных);
|
||||
**gRPC** является классической технологией второго поколения, сочетающей все перечисленные выше достоинства:
|
||||
* полагается на новейшие возможности протокола HTTP/2 и эффективный формат обмена данными Protobuf (последнее необязательно, но практически абсолютное большинство gRPC API полагается именно на него);
|
||||
* разрабатывается компанией Google и поставляется с широким выбором разнообразных инструментов;
|
||||
* предлагает contract-first подход, в котором разработка API начинается с написания спецификации;
|
||||
* благодаря кодогенерации, позволяет удобно работать с протоколом на императивных языках программирования.
|
||||
|
||||
К недостаткам gRPC следует отнести сложность чтения и отладки (сообщения в формате Protobuf нечеловекочитаемые, а без `.proto`-файла и немашиночитаемые), слабую поддержку браузеров, меньшую распространённость (и отсюда более высокий порог вхождения для разработчиков) и потенциальную зависимость от Google. В остальном, gRPC вне всяких сомнений один из наиболее современных и производительных протоколов.
|
||||
К недостаткам gRPC следует отнести:
|
||||
* сложность декодирования сообщений и отладки коммуникации;
|
||||
* слабую поддержку браузеров;
|
||||
* меньшую распространённость (и отсюда более высокий порог вхождения для разработчиков);
|
||||
* потенциальную зависимость от Google.
|
||||
|
||||
GraphQL представляет собой любопытный подход, который объединяет концепцию «ресурсов» в HTML (т.е. фокусируется на подробном описании форматов доступных данных), при этом предоставляя чрезвычайно богатый язык запросов для извлечения нужных наборов полей. Основная область его применения — это насыщенные разнородными данными предметные области (как, в общем-то, и следует из названия, GraphQL — скорее механизм распределённых запросов к абстрактному хранилищу данных, нежели парадигма разработки API). Предоставление внешних GraphQL API на сегодня скорее экзотика, поскольку с ростом количества данных и запросов GraphQL-сервисом становится очень сложно управлять[ref Mehta, S., Barodiya, K. Lessons learned from running GraphQL at scale](https://blog.dream11engineering.com/lessons-learned-from-running-graphql-at-scale-2ad60b3cefeb).
|
||||
В остальном, gRPC вне всяких сомнений один из наиболее современных и производительных протоколов.
|
||||
|
||||
**NB**: теоретически, API может обладать двойным интерфейсом, например, и REST, и gRPC. Так как в основе всех современных фреймворков лежит формальное описание форматов данных, и эти форматы можно при желании транслировать друг в друга, такой мульти-API технически возможен. Практически же примеры таких API нам неизвестны — по-видимому, накладные расходы на поддержание двойного интерфейса не покрывают потенциальную выгоду от большего удобства для разработчиков.
|
||||
**GraphQL** представляет собой любопытный подход, который объединяет концепцию «ресурсов» в HTML (т.е. фокусируется на подробном описании форматов доступных данных и отношений между доменами), при этом предоставляя чрезвычайно богатый язык запросов для извлечения нужных наборов полей. Основная область его применения — это насыщенные разнородными данными предметные области (как, в общем-то, и следует из названия, GraphQL — скорее механизм распределённых запросов к абстрактному хранилищу данных, нежели парадигма разработки API). Предоставление *внешних* GraphQL API на сегодня скорее экзотика, поскольку с ростом количества данных и запросов GraphQL-сервисом становится очень сложно управлять[ref Mehta, S., Barodiya, K. Lessons learned from running GraphQL at scale](https://blog.dream11engineering.com/lessons-learned-from-running-graphql-at-scale-2ad60b3cefeb).
|
||||
|
||||
**NB**: теоретически, API может обладать двойным интерфейсом, например, и JSON-over-HTTP, и gRPC. Так как в основе всех современных фреймворков лежит формальное описание форматов данных и доступных операций, и эти форматы можно при желании транслировать друг в друга, такой мульти-API технически возможен. Практически же примеры таких API нам неизвестны — по-видимому, накладные расходы на поддержание двойного интерфейса не покрывают потенциальную выгоду от большего удобства для разработчиков.
|
@ -1,8 +1,8 @@
|
||||
### [Мифология REST][http-api-rest-myth]
|
||||
|
||||
Прежде, чем перейти непосредственно к паттернам проектирования HTTP API, мы должны сделать ещё одно терминологическое отступление. Очень часто HTTP API, соответствующие данному нами в главе «[О концепции HTTP API и терминологии](#http-api-concepts)» определению, называют «REST API» или «RESTful API». В настоящем разделе мы эти термины не используем, поскольку оба этих термина неформальные и не несут конкретного смысла.
|
||||
Прежде, чем перейти непосредственно к паттернам проектирования HTTP API, мы должны сделать ещё одно терминологическое отступление. Очень часто HTTP API, соответствующие данному нами в главе «[О концепции HTTP API](#http-api-concepts)» определению, называют «REST API» или «RESTful API». В настоящем разделе мы эти термины не используем, поскольку оба этих термина неформальные и не несут конкретного смысла.
|
||||
|
||||
Что такое «REST»? В 2000 году один из авторов спецификаций HTTP и URI Рой Филдинг защитил докторскую диссертацию на тему «Архитектурные стили и дизайн архитектуры сетевого программного обеспечения», пятая глава которой была озаглавлена как «Representational State Transfer (REST)»[ref:{"short":"Fielding, R. (2000)","extra":["Architectural Styles and the Design of Network-based Software Architectures","Representational State Transfer (REST)"]}](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm).
|
||||
Что такое «REST»? Как мы упоминали ранее, в 2000 году один из авторов спецификаций HTTP и URI Рой Филдинг защитил докторскую диссертацию на тему «Архитектурные стили и дизайн архитектуры сетевого программного обеспечения», пятая глава которой была озаглавлена как «Representational State Transfer (REST)»[ref:{"short":"Fielding, R. (2000)","extra":["Architectural Styles and the Design of Network-based Software Architectures","Representational State Transfer (REST)"]}](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm).
|
||||
|
||||
Как нетрудно убедиться, прочитав эту главу, она представляет собой абстрактный обзор распределённой сетевой архитектуры, вообще не привязанной ни к HTTP, ни к URL. Более того, она вовсе не посвящена правилам дизайна API — в этой главе Филдинг методично *перечисляет ограничения*, с которыми приходится сталкиваться разработчику распределённого сетевого программного обеспечения. Вот они:
|
||||
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
#### Выбор фреймворка для разработки UI-компонентов
|
||||
|
||||
Поскольку UI — высокоуровневая абстракция над примитивами ОС, почти для всех платформ существуют специализированные фреймворки для разработки визуальных компонентов. Выбор такого фреймворка, увы, может быть непростым занятием. Например, в случае веб-платформы её низкоуровневость и популярность привели к тому, что на сегодня количество конкурирующих технологий, предоставляющих фреймворки для разработки SDK, превосходит всякое воображение. Можно упомянуть наиболее распространённые на сегодня React[ref React](https://react.dev/), Angular[ref Angular](https://angular.io/), Svelte[ref Svelte](https://svelte.dev/), Vue.js[ref Vue.js](https://vuejs.org/) и не сдающие своих позиций Bootstrap[ref Bootstrap](https://getbootstrap.com/) и Ember[ref Ember](https://emberjs.com/). Из перечисленных технологий наибольшее проникновение имеет React, но оно всё ещё измеряется в единицах процентов[ref How Many Websites Use React in 2023? (Usage Statistics)](https://increditools.com/react-usage-statistics/). При этом компоненты на «чистом» JavaScript/CSS при этом часто критикуются как неудобные к использованию в перечисленных фреймворках, так как каждый из них реализует весьма строгие методологии. Примерно такая же ситуация наблюдается, например, с разработкой визуальных компонентов для Windows. Вопрос «на каком фреймворке разрабатывать компоненты для этих платформ», увы, не имеет простого ответа — фактически, вам придётся измерять рынки и принимать решения по каждому фреймворку отдельно.
|
||||
Поскольку UI — высокоуровневая абстракция над примитивами ОС, почти для всех платформ существуют специализированные фреймворки для разработки визуальных компонентов. Выбор такого фреймворка, увы, может быть непростым занятием. Например, в случае веб-платформы её низкоуровневость и популярность привели к тому, что на сегодня количество конкурирующих технологий, предоставляющих фреймворки для разработки SDK, превосходит всякое воображение. Можно упомянуть наиболее распространённые на сегодня React[ref React](https://react.dev/), Angular[ref Angular](https://angular.io/), Svelte[ref Svelte](https://svelte.dev/), Vue.js[ref Vue.js](https://vuejs.org/) и не сдающие своих позиций Bootstrap[ref Bootstrap](https://getbootstrap.com/) и Ember[ref Ember](https://emberjs.com/). Из перечисленных технологий наибольшее проникновение имеет React, но оно всё ещё измеряется в единицах процентов[ref How Many Websites Use React in 2023? (Usage Statistics)](https://increditools.com/react-usage-statistics/). При этом компоненты на «чистом» JavaScript/CSS при этом часто критикуются как неудобные к использованию в перечисленных фреймворках, так как каждый из них реализует весьма строгие методологии. Примерно такая же ситуация наблюдается, например, с разработкой визуальных библиотек для Windows. Вопрос «на каком фреймворке разрабатывать UI-компоненты для этих платформ», увы, не имеет простого ответа — фактически, вам придётся измерять рынки и принимать решения по каждому фреймворку отдельно.
|
||||
|
||||
Лучше дела обстоят с современными мобильными платформами (а также MacOS), которые гораздо более гомогенны. Однако здесь возникает другая проблема — современные приложения, как правило, поддерживают сразу несколько таких платформ, что приводит к дублированию кода (и номенклатуры API).
|
||||
Лучше дела обстоят с актуальными мобильными платформами (а также MacOS), которые гораздо более гомогенны. Однако здесь возникает другая проблема — современные приложения, как правило, поддерживают сразу несколько таких платформ, что приводит к дублированию кода (и номенклатуры API).
|
||||
|
||||
Решением этой проблемы может быть использование кросс-платформенных мобильных (React Native[ref React Native](https://reactnative.dev/), Flutter[ref Flutter](https://flutter.dev/), Xamarin[ref Xamarin](https://dotnet.microsoft.com/en-us/apps/xamarin)) и десктопных фреймворков (JavaFX[ref JavaFX](https://openjfx.io/), QT[ref QT](https://www.qt.io/)), а также узкоспециализированных решений для конкретных задач (например, Unity[ref Unity](https://docs.unity3d.com/Manual/index.html) для разработки игр). Несомненным преимуществом таких технологий является скорость разработки и универсальность (как кода, так и программистов). Недостатки также достаточно очевидны — от таких приложений может быть сложно добиться оптимальной производительности, и к ним часто неприменимы многие стандартные инструменты, доступные для конкретной платформы; например, отладка и профайлинг могут быть затруднены. На сегодня скорее наблюдается паритет между двумя этими подходами (несколько фактически независимых приложений, написанных на поддерживаемых платформой языках vs. одно кросс-плафторменное приложение).
|
||||
Решением этой проблемы может быть использование кросс-платформенных мобильных (React Native[ref React Native](https://reactnative.dev/), Flutter[ref Flutter](https://flutter.dev/), Xamarin[ref Xamarin](https://dotnet.microsoft.com/en-us/apps/xamarin)) и десктопных (JavaFX[ref JavaFX](https://openjfx.io/), QT[ref QT](https://www.qt.io/)) фреймворков, а также узкоспециализированных решений для конкретных задач (например, Unity[ref Unity](https://docs.unity3d.com/Manual/index.html) для разработки игр). Несомненным преимуществом таких технологий является скорость разработки и универсальность (как кода, так и программистов). Недостатки также достаточно очевидны — от таких приложений может быть сложно добиться оптимальной производительности, и к ним часто неприменимы многие стандартные инструменты, доступные для конкретной платформы; например, отладка и профайлинг могут быть затруднены. На сегодня скорее наблюдается паритет между двумя этими подходами (несколько фактически независимых приложений, написанных на поддерживаемых платформой языках vs. одно кросс-плафторменное приложение).
|
Loading…
x
Reference in New Issue
Block a user