📜 ⬆️ ⬇️

REST passion for 200



I have long wanted to write this article. I was thinking - from which side should I go? But, suddenly, recently, a similar article appeared on Habré, which caused a storm in a glass. Most of all I was surprised by the simple fact that the article began to drive into the minus, although she did not even declare something, but rather just raised the question of using the response codes of the web server in REST. The debate is hot. And the apotheosis was that the article went into drafts ... kilobytes of comments, opinions, etc. just disappeared. Many have become karma victims, count for nothing :)

In general, it was the fate of the article that prompted me to write this. And I very much hope that it will be useful and clarify a lot.

I warn you, everything written below is a real experience, not a cognitive balancing act. And so, drove.

HTTP


The first thing you need to very clearly separate the layers. Transport layer is http. Well, actually REST. This is a fundamentally important thing in accepting everything and “yourself” in it. Let's first talk only about http.

I used the term “transport layer”. And I did not make a reservation. The thing is that http itself implements the functions of transporting requests to the server and content to the client, regardless of tcp / ip. Yes, it is based on tcp / ip. And it seems, it is necessary to consider his transport. But no. And this is why - socket connections are not direct, i.e. This is not a client-server connection. Both the http request and the http response can go a long way through a lot of services. Can be aggregated or decomposed. Can be cached, can be modified.

Those. the http request as well as the http response have their own route. And it does not depend on the final back-up, nor on the final front. Please pay special attention to this.

The http paths are not static. They can be very complex. For example, if a balancer is built into the infrastructure, it can send received requests to any of the backend nodes. At the same time, the back itself can implement its own strategy for working with queries. Some of them will go to microservices directly, some will be processed by the web server itself, some will be supplemented and transferred to someone else, and some will be cached, etc. This is how the Internet works. Nothing new.

And here it is important to understand - why do we need response codes? The thing is that the whole model described above makes decisions based on them. Those. These are codes that allow you to make infrastructure and transport decisions during http routing.

For example, if the balancer encounters a response code from back 503, when sending a request, it can take it as a reason to assume that the node is temporarily unavailable. I note that the response with code 503 provides for the header Retry-After. Having received an interval from the header for re-polling, the balancer will leave the node alone for a specified period and will work with those available. Moreover, such strategies are implemented out of the box by web servers.

A small oftopik for depth of understanding - and if the node responded 500? What should a balancer do? Switch to another? And many will answer - of course, all 5xx are the basis for disabling the node. And they will be wrong. Code 500 is an unexpected error code. Those. one that can never happen again. And most importantly, switching to another node may not change anything. Those. we just turn off the nodes without any benefit.

In the case of the 500 we come to the aid of statistics. The local WEB server of the node can transfer the node itself to the unavailable status with a large number of 500 responses. In this case, the balancer having addressed this node will receive the answer 503 and will not touch it. The result is the same, but now, this decision is meaningful and eliminates “false” triggers.

But that's not all. In such a situation, monitoring will allow admins to connect to the situation to service the node. Those. we get not just the implementation of a highly available service, with balancing, etc., but also an effective support process.

And all this can make the server response codes. Any architecture of a web application must begin with the design of the transport layer. I hope there is no doubt about it.

REST


Ask a rhetorical question - what is it? And what did you answer to him? I will not give links to obvious proofs, but most likely not quite what it is in essence :) This is just an ideology, a style. Some thoughts on the topic - how best to communicate with the back. And not just communicate, but communicate in the WEB infrastructure. Those. based on http. With all those “useful things” that I wrote about above. The final decisions on implementing your interface are always yours .

Have you ever thought why a separate transport for REST is not invented? For example, for websocket it is. Yes, it also starts with http, but then, after the connection is established, it is generally a separate song. Why not do the same for REST?

The answer is simple - why? There is a beautiful, ready, verified protocol - http. It scales well. Allows you to implement complex, high-availability services that can cope with a large load. All that is needed is to introduce certain conceptual rules so that the developers understand each other.

From here follows a simple, obvious conclusion - everything that is inherent in http is also inherent in REST. These are inseparable entities. There is no separate REST header, not even a hint that REST is REST. For any REST server, the request is exactly the same as any other. Those. REST is just what we have in mind.

Http response codes in REST


Let's talk about how your server should respond to a REST request? Personally, it seems to me that from all the above written, the answer is already obvious: REST is no different from any other request; it must be subject to exactly the same rules. The response code is an integral part of REST and must be relevant to the essence of the response. Those. if the object is not found on request, it is 404, if the client has applied with an incorrect request 400, etc. But, most often, this debate does not end there. Therefore, I will continue.

Is it possible to respond to all with code 200? And who will forbid you? Please ... code 200 is the same code as the others. True, this approach is based on a very simple thesis - my system is perfect, it has no errors. If you are a person who can create such systems - this can only be envied!

But most likely ... it is not perfect. And mistakes still happen. And it happens that they happen due to circumstances beyond our control. And here the typical solution is to create your own error coding system. This is bad? Yes this is bad. This is super bad. Let's figure out why.

And so, taking code 200 as the only correct one, we assume responsibility for the development of a whole layer (critical layer) of the system - error handling. Those. The work of many people to develop this layer is sent to the scrap. And the construction of his “bicycle” begins. But this megastroyka is doomed to failure.

Let's start with the code. If we are going to answer all 200, we ourselves will have to handle errors. The classic method is try constructions. We wrap each code segment with an additional code. Handlers that do something useful. For example, put something in the log. Something important. That will allow to localize the error. And if the error occurred not where it was expected? Or if the error occurred in the error handler? Those. This code-level strategy is non-working a priori. And in the end, the interpreter or platform will process your bugs. OS, finally. The essence of the bug is that you do not expect it. You do not need to hide it, you need to find and fix it. Therefore, if any REST requests respond with error 500, this is normal . And what's more - right .

Let's go back to the question - why is this right? Because:

  1. Code 500 is an infrastructure marker, on the basis of which the node on which the problem occurs can be disabled;
  2. The 5xx codes is what is being monitored and if such a code occurs, any monitoring system will notify you immediately. And the support service will be able to connect to the solution of the problem on time;
  3. You do not write additional code. Do not spend this precious time. Do not complicate the architecture. You are not involved in problems that are unusual for you - you write application code. What they want from you. What are they paying for?
  4. A trace that falls by mistake 500 will be much more useful than your attempts to beat it.
  5. If the REST request returns 500 code, the front will already know at what time it’s processing the algorithm by which algorithm to process it. Moreover, the essence of the matter will not change in any way; you have not received anything sensible either from 200 or from 500. But from 500 you received a profit - the realization that this is an UNEXPECTED error.
  6. Code 500 will come guaranteed. No matter how bad or well you wrote your code. This is your fulcrum.

Separately, I will drive a nail into the entire “body” of code 200:

7. Even if you try very hard to avoid other response codes from the server other than 200 to your requests, you will not be able to do this. Any intermediary server can respond to your request with absolutely any code. And you MUST process this answer correctly.

So, at the logical level, the struggle for code 200 is meaningless.

Now let's go back to the infrastructure level. Very often I hear an opinion - the 5xx code is not at the application level, it cannot be given back. Hmm, well ... there is a contradiction in the statement itself. You can give. But this code is not an application layer. That's true. To understand this, I propose to consider the case:
You implement the gateway. You have several DCs, each with its own communication channel to a certain private service. Well, for example, to pay for VPN. And there is a communication channel with the Internet. You receive a request for an operation with a gateway, but ... it is unavailable.
And so, what should you answer? To whom? This is an infrastructural problem and, precisely, backing ran into it. Of course, you need to safely answer 503. These actions will lead to the fact that the node will be disabled by the balancer for a while. In this case, the balancer, if properly configured, without breaking the connection with the client, will send a request to another node. And ... the final client, with a high degree of probability, received 200. And not a custom description of the error, which will not help him in any way.

Where and what code to use


This is a difficult question. There is no definite answer to it. For each system, a transport layer is designed and the codes in it can be specific.

There are accepted standards. They can be easily found and, again, I will not give obvious proofs. But, I will give the unobvious - developer.mozilla.org/ru/docs/Web/HTTP/Status
Why him? The point is that code handlers can behave in different ways, depending on the implementation and context of “code understanding”. For example, browsers have a caching strategy tied to response codes. And some services have their own, custom codes. For example, CloudFlare.

Those. making decisions about the use of codes, you need to base on all elements of the transport layer from your code on the back code to the code on the client. This is the only way to find the right answers. I will not even try to give everyone a universal pill.

Roots of evil


Already the third project in which I come suffers with code 200 in REST. It suffers. There is no other word. If you have carefully read everything up to the present moment, you already understand that as soon as the project starts to grow, it will need to develop the infrastructure, its sustainability. Code 200 kills all these attempts at the root. And the first thing you have to do is break stereotypes.

The root of evil, it seems to me lies in the fact that the code 500 is the first thing that a web developer meets in his professional activity. This can be said to be a child injury. And all his efforts at first boil down to getting code 200.

By the way, for some reason, at this stage a stable opinion is developed that only answers with code 200 can be supplied with a body. Of course, this is not the case and with any code any answer can “come”. Code is code. The body is the body.

Further, with the development of the developer, he has a need to manage the bugs of his own application. But ... he does not know how to use logs. Cannot configure web server. He is studying. And they are born the very "great." Because they are available to him and he can quickly make them. Further, on this “great” it mounts new wheels, strengthens the frame, etc. And this one is becoming his companion for a sufficiently long period of time, until ... until he has really complex, multicomponent tasks. And here, as they say - the entrance to the supermarket with "great" and on the rollers is prohibited.

PS: The author of the mentioned article restored it from drafts - habr.com/ru/post/440382 , so you can read it too.

PPS: I tried to state all the facets of the need to use the relevant response codes in REST. I will not respond to comments, please understand me correctly. I will read them with great attention, but I have nothing to add. Thank you so much for having the patience to read the article!

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