📜 ⬆️ ⬇️

Duma about the web-API. Part one

At one point, in the process of creating the next web service, I decided to gather all my knowledge and thoughts on the design of a web API to serve the needs of client applications and arrange them as an article or a series of articles. Of course, my experience does not claim to be absolute, and constructive criticism and additions are more than welcome.

Fiction turned out more philosophical than technical, but for fans of the technical part there will be something to think about. I doubt that I will say something fundamentally new in this article, something that you have never heard, did not read, and did not think about. Just try to put everything in a single system, first of all in my own head, and this is already worth a lot. Nevertheless, I will be glad if my fabrications will be useful to you in your practice. So let's go.

Approaching first: protagonists


Client and server


In this case, we consider the server to be an abstract machine on the network that can receive an HTTP request, process it and return the correct response. In the context of this article, its physical essence and internal architecture are absolutely not important, whether it be a student laptop or a huge cluster of industrial servers scattered around the world. It is equally unimportant to us that under his hood, who meets a request at the door, Apache or Nginx, which unknown beast, PHP, Python or Ruby performs its processing and forms the answer, which data repository is used: Postgresql, MySQL or MongoDB . The main thing is that the server responds to the main rule - to hear, understand and forgive the answer.

The client can also be anything that is able to form and send an HTTP request. Up to a certain point in this article, we also will not be particularly interested in the goals that the client sets himself by sending this request, as well as what he will do with the answer. The client may be a JavaScript script running in a browser, a mobile application, an evil (or not) demon running on the server, or a too-smart refrigerator (there are already such).
')
For the most part, we will talk about the method of communication between the two listed above, such a way that they understand each other, and no one has any questions left.

REST philosophy


REST (Representational state transfer) was originally conceived as a simple and unambiguous interface for managing data, which involved only a few basic operations with direct network storage (server): data extraction (GET) , saving (POST) , changing (PUT / PATCH) and deleting (DELETE) . Of course, this list was always accompanied by such options as error handling in the request (whether the request was made correctly), access control to the data (all of a sudden you should not know this) and validation of incoming data (all of a sudden you wrote nonsense), in general, with all possible checks which the server executes before fulfilling the desire of the client.

In addition, REST has a number of architectural principles, a list of which can be found in any other article on REST. Let's go over them briefly so that they are at hand, and do not have to go anywhere:

Server independence from the client - servers and clients can be instantly replaced by others independently of each other, since the interface between them does not change. The server does not store client states.

Uniqueness of resource addresses - each data unit (of any degree of nesting) has its own unique URL, which, in fact, is a unique identifier of the resource.

Example: GET / api / v1 / users / 25 / name

The independence of the data storage format on the transmission format — the server can support several different formats for transmitting the same data (JSON, XML etc), but stores data in its internal format, regardless of which data is supported.

Presence in the response of all the necessary metadata - in addition to the data itself, the server must return details of the request processing, for example, error messages, various properties of the resource necessary for further work with it, for example, the total number of records in the collection for the correct display of page-by-page navigation. We will go through the varieties of resources.

What we lack


Classic REST implies that the client works with the server as a flat data storage, while nothing is said about the connectivity and interdependence of the data among themselves. All of this, by default, falls entirely on the shoulders of the client application. However, modern subject areas for which data management systems are being developed, be it social services or Internet marketing systems, imply a complex relationship between entities stored in a database. Support for these links, i.e. data integrity is the responsibility of the server side, while the client is only an interface to access this data. So what are we missing from REST?

Function calls


The necessity of separating functions as a separate data management method is dictated by the fact that the principles of encapsulation of methods, transaction atomicity and maintenance of data integrity come into force. In order not to change the data and the connections between them manually, we simply call the function (single object, or collection) function and “feed” the necessary parameters as an argument. This operation does not fit the standards of REST, for it there is no special verb, as well as a way to specify the name of the function, which causes us, the developers, to get out who is in that much.

The simplest example is user authorization. We call the POST / api / v1 / auth / login function, pass an object containing the credentials as an argument to it, and in return receive an access key. What is happening with the data on the server side - we do not care.

Another option is to create and break links between entities. For example, adding a user to a group. We call the entity function POST / api / v1 / groups / 1 / addUser , we pass the user object as a parameter, we get the result. An example, of course, is far-fetched, but often when creating connections, additional operations with data on the server side are possible.

And there are operations that are generally not directly related to the preservation of data as such, for example, sending notifications, confirming or rejecting any operations (completion of the reporting period, etc).

In one of the following articles, I will try to classify these operations and suggest options for possible requests and responses, based on which ones I encountered in practice.

Multiple operations


It often happens that the client developers will understand what I mean, that it is more convenient for the client application to create / modify / delete / several homogeneous objects at once in one request, and for each object a server-side verdict is possible. There are at least a few options: either all changes are made, or they are partially implemented (for part of the objects), or an error has occurred. Well, there are also several strategies: to apply changes only in case of success for everyone, or to apply partially, or to roll back in case of any error, and this already draws on a full-fledged transaction mechanism.

For web-api, striving for the ideal, I would also like to somehow bring such operations into the system. I will try to do it in one of the sequels.

Statistical queries, aggregators, data formatting


It often happens that, on the basis of the data stored on the server, we need to obtain a statistical squeeze or data formatted in a special way: for example, for plotting on the client side. In fact, this data is generated on demand, to some extent on the fly, and is read-only, so it makes sense to put them in a separate category. One of the distinguishing features of statistics, in my opinion, is that they do not have a unique ID.

I am sure that this is not all that can be encountered in the development of real-world applications, and I will be glad for your additions and corrections.

Varieties of data


Objects


The key data type in communication between the client and the server is the object. In essence, an object is a list of properties and their corresponding values. We can send an object to the server in a request and get the result of the query as an object. At the same time, the object will not necessarily be a real entity stored in the database, at least in the form in which it was sent or received. For example, the credentials for authorization are transmitted as an object, but are not an independent entity. Even objects stored in the database tend to be clouded with additional intra-system properties, for example, creation and editing dates, various system labels and flags. Properties of objects can be either their own scalar values, or contain related objects and collections of objects that are not part of the object. Some properties of objects can be editable, part of the system, read-only, and some can be statistical in nature and be calculated on the fly (for example, the number of likes). Some properties of the object may be hidden, depending on the rights of the user.

Object Collections


Speaking of collections, we mean a kind of server resource that allows you to work with a list of similar objects, i.e. add, delete, modify objects and select from them. In addition, the collection can theoretically have its own properties (for example, the maximum number of elements per page) and functions (here I am confused, but this also happened).

Scalar values


In their pure form, scalar values ​​as a separate entity in my memory were extremely rare. Usually they appeared as properties of objects or collections, and as such they can be available both for reading and for writing. For example, a username can be obtained and changed individually by the GET / api / v1 / users / 1 / name . In practice, this opportunity rarely comes in handy, but if necessary, I would like it to be at hand. This is especially true of collection properties, for example, the number of records (with or without filtering): GET / api / v1 / news / count .

Files


Files are files - they should be considered as a single, unseparated unit. Another issue is that in most cases when saving a file in a database, a service entity can be created containing the metadata of this file: size, real name, status, etc.

To be continued...

Source: https://habr.com/ru/post/312360/


All Articles