OperationResult: The server response is always clear to the user

en-US | создано: 15.11.2018 | опубликовано: 15.11.2018 | обновлено: 02.08.2019 | просмотров за всё время: 183

This article will discuss how to tell the user that his request is incorrect and not to throw an exception or any other incomprehensible HTTP request status code.

History

Once, a long time ago, I had the opportunity to work on one very complex project, which was a complex system, not just from different projects, but even from different platforms. I still find it difficult compared to all those that met on my way to the developer. This is not about the WebAPI platform and Xamarin. For this "pair" at the moment, there are already invented a huge variety of different layers, greatly simplifying the development. In that complex project, there were such "bricks" as Rational DOORS, InterSystems Caché, all kinds of standards like ISO9001. In other words, the project was not simple. Then I had to solve a lot of different tasks and often not always simple tasks. I will not go into details, I’ll just say that one of the simplest tasks sounded like this: “correct processing the status of responses from a Web server”.

It is certainly not news for you that the responses from the Web server contain not only "incomprehensible" text, but also special codes. So, it was necessary to process these codes and, in accordance with the result of the processing, “direct” the user's actions according to the correct scenario. The decision was taken at that time I use so far.

Solution

In order not to torture the server and not to write mountains of code, we made a decision, which later became the rule:

The server should always return a single response code as the result of processing the request. This is code 200. And all additional information is required to be transmitted in the body of the answer.

Naturally, everything is good in moderation and if the error code is 500, then it does not make sense to process it in any way.

This is how OperationResult appeared. So what is OperationResult? This is a request to the server, as it was then supposed, or a request to perform an operation if you use the updated terminology. In the following, only with new terms, it is implied that you need to get the result of any operation from any service (method, module, server, access level, stream, etc., etc.).

How it works

Suppose we have a WebAPI service that works with orders from our online store. Let the user sends a request to add 143 packs of juice to the basket. The JavaScript code that makes the post looks like this:

var data = {
    code: "PR2018-3-06",
    name: "Juice",
    count: 143
}
_cardService.addToBasket(data)
    .done(function (response){
        if(response && response.ok){
            showMessage(response.metadata.success);
        } else {
            if (response.metadata.warning) showMessage(response.metadata.warning);
            if (response.metadata.error) showMessage(response.metadata.error);
        }
    })
    .fail(function (response){
        showMessage("Something gone wrong")
    });

What are the response options from the server in this case? There are several:

  1. The order added to cart.
  2. Juice ran out of stock.
  3. In the basket already have such a product.
  4. Service error or service not available.

When using OperationResult we can easily handle all the options. With the resulting number 1, we can show a message, for example, "The product was successfully added to the basket". Moreover, knowing what kind of product, we can return the accompanying product as an offer in a special object, which is returned to the OperationResult, for example, “Bouquet of flowers” and show this product on the tab “At the same time buy ...”. etc. With result number 2, when the quantity is in stock 53, we can show the buyer information that there are not enough condoms in the warehouse, and “ask” what to do in this case, add 53 or cancel the addition. With the resulting number 3, we also have the opportunity to ask the user what actions should be taken further, or add to the existing quantity in the basket the added quantity or cancel the addition. As a result, number 4, we know for sure that the service has broken down and we will not be able to complete an order.

OperationResult

All of these options can be easily implemented using a wrapper. Because along with the answer, we send additional information to the client. And when you consider that OperationResult initially laid the following parameters for the answer:

T Result {get; set;}
A generic object for the result, that is, it can be either a primitive type or a class, or even a collection of classes.

Exception Error {get; set;}
Error performing operation. We can pass an error to the client entirely if it is required for post-processing already on the client or some other information, for example, from the stack.

Dictionary <OperationInfo, object> Metadata {get; set;}
These are objects with a predefined key type, where the key type OperationInfo is an enumeration.

public enum OperationInfo {
    Info,
    Success,
    Warning,
    Error,
    DataObject
}

In general, there is nothing more in the OperationResult. But the listed set provides tremendous opportunities for managing application processes and managing user actions. Believe me, this approach can and should be used not only WebAPI but on any other types of interaction between modules, services, objects and other components (components) of any application on any platform. Especially useful when interacting with loosely coupled components, for example, when getting a NULL result when executing the Send method in EmailService, you will not know what happened and additional information, in this case, would definitely not hurt you.

Links

OperationResult is an assembly that lies in a NuGet-package, in which, in addition to the mentioned functionality, there are a number of useful utilities.