How to write a bad API

    Write the code as if it would be accompanied by a violent psychopath who knows where you live.


    Hello!


    I work as team lead Integration Development team when online hotel reservation Ostrovok.ru and today I would like to share my experience with the API.



    As a developer of a system working with external providers, I often come across various APIs - most often it is SOAP / REST or something similar to them. However, working with many of them leaves the impression that they were written, not guided by either technical rules or common sense - as if from the book “Bad Advice” by Grigory Oster. In this article I will try to describe such cases in the style of “bad advice” and consider examples related to XML. Comments and discussion are welcome.


    Historical reference

    SOAP (from the English. Simple Object Access Protocol - a simple protocol for accessing objects) - a protocol for exchanging structured messages in a distributed computing environment. SOAP was originally intended primarily for implementing remote procedure call (RPC). Now the protocol is used for exchanging arbitrary messages in XML format, and not just for calling procedures.


    Go to the examples


    1. Passing xml to url


    What do API users want most? Of course, simplicity, reliability and conciseness. So let's not read the request body, but accept XML as url-encoded information as a parameter of the request path! What could be better:


    http://exapmple.com/xml/form.jsp?RequestName%3DHotelRequest2%26XML%3D%3C%3Fxml%2Bversion%3D%221.0%22%2Bencoding%3D%22UTF-8%22%3F%3E%0A%3CHotelRequest2%2BBuyerId%3D%22test%22%2BUserId%3D%22test%22%2BPassword%3D%22test%22%2BLanguage%3D%22en%22%2BHotel%3D%22-100%22%2BProductCode%3D%221--%22%2BArrivalDate%3D%2223.12.2018%22%2BDepartureDate%3D%2224.12.2018%22%2BArrivalTime%3D%22%22%2BDepartureTime%3D%22%22%2BCurrency%3D%222%22%2BWhereToPay%3D%223%22%2BNumberOfGuests%3D%220%22%2BNumberOfExtraBedsAdult%3D%220%22%2BNumberOfExtraBedsChild%3D%220%22%2BNumberOfExtraBedsInfant%3D%220%22%2B%2F%3E

    Everything becomes simple, and there is no need to subtract some body from the query - you never know what problems there may be with it.


    Spoiler

    I won’t know why this was done. The problems here are the following: many servers have a limit on the length of the request path that can go through them. If the XML is large in data volume, then you can cause the 413 Entity Too Large error as one of the scenarios. In addition, the amount of information is increasing, since we do url-encoding before sending.


    2. Information transfer through excessive nesting of data objects


    Let's think about how to make the information in the answers as difficult as possible? Let's use nested structures, and even in different formats! No sooner said than done -


    [{"someInfo":"base64Data"}]
    

    Indeed, the top-level xml, inside it is another xml, and inside it is json, in which the data is presented in base64, and again json in it, and it will already contain the information we need! A great solution, almost like a fairy tale about the death of Koshchei, hidden in an egg.


    Spoiler

    One of the most noticeable drawbacks is the slowdown in parsing the response until all the nested structures are traversed, and afterwards it may turn out that the error code is wired in json, rather than at levels higher. I understand that encoding binary data in base64 inside xml / json is a common practice, but encoding a different format inside a different format is already beyond good and evil.


    3. Adding information that is not related to the request data and is not valid within the data format


    Suppose XML comes to us in the request body, we process it and give an answer. It looks too complicated for a well-designed and heavily loaded system. Let's oblige users to send data type in request body. How to do this? Right in the body of the request, of course.


    XML=
    
    ...
    

    In such a simple way, we will always know that we received a request in XML format.


    Spoiler

    It turns out that we must add more leading bytes to the already formed body of the request and only after that it will be possible to make a request. Lucky if you do not need to change the leading bytes depending on the type of request data. In this case, it would be better to use http Header to indicate the data type, and not to change the request body.


    4. Duplication of data without the need


    Suppose we have very, very important information in the structure of the XML response. How to show this to the user? The most obvious - let's show it several times as part of the answer, then he will definitely pay attention to it.


    SomeNameImportant

    After that, the end user will definitely pay attention to the Info field.


    Spoiler

    In this case, I thought about it and even asked the company that provided the API about the meaning of the Info field and whether the information in the tags at different levels would differ. The answer was: no, it won’t - they duplicate each other. Why mislead users and make the answer more difficult if this is not necessary?


    5. Passing parameters of the same type individually, not an array


    In one of the APIs that we use to search for hotels, there are fields indicating the age of the guests. What presentation format is best used to convey this information? Let the format be like this: each age will be a separate mandatory XML tag, and we will consider the value 0 as the absence of this parameter.


    20
    20
    0
    0
    

    Spoiler

    There are several problems here at once: non-extensibility, redundant information, in addition, the age can really be zero if the guests are newborn children. In this case, you need to use an array, rather than uniquely named tags.


    6. Forwarding information from previous requests as part of the API call chain


    It's time to think about the security of our API. How do we understand that the user receives information from our previous answers? Let him send us our answer, of course!


    
        ...
        

    Spoiler

    To continue working with the API, it is necessary to send the entire response of the external system from the previous steps of the API, and not some important data from it, or even a hash that will definitely correspond to this answer. Excess data in all its glory.


    7. Do not use markers of an error that occurred, such as an error tag or an http code


    We made our beautiful API and introduced it to the world. But once something went wrong, and we were not able to formulate a response to the user due to an internal error. What to do in this case? Just give a response template, without data, without error codes or any other information. No one should know that our ideal API may sometimes not work!
    An example of such an answer:



    - with a response code of 200 OK.


    Spoiler

    Hushing up mistakes made is a very bad practice. The problem is that everything looks as if there are no problems in the answer: there is no tag , the http status says that everything is in order. In this case, it is necessary to do additional validation of the received information so that there are no unforeseen consequences already in our system.


    Conclusion
    Despite the large amount of documentation on working with SOAP / XML technologies and API design, many problems are still relevant, and some solutions are contrary to common sense. I hope that with this article I will be able to draw the attention of developers to not the most successful approaches in order to reduce their number in the future.


    Also popular now: