 The next talk will be a restful SPI best practices by Malvina, let's give her a big applause. Hi everybody, I'm Malvina, I'm a developer at STXnext, the biggest Python software house in Europe. Almost five years ago I wrote my first line of code and that's how my Python journey began. When I'm not hacking, I'm trying to spend time actively at the gym or in the nature. Okay, so let's begin with a short story. Some time ago, in one of my previous projects, I had to make many integrations with many providers. And each of them had a very different level of APIs. We were working on module which was offering tickets for many kinds of events from many suppliers. At the beginning, we started implementing integration with the main provider. Our first task was to implement a simple search. The endpoint for searching was limited. The API provider offered us only searching but date or text. So after consultation of our product owner, we decided to develop the same functionality. While working on it, we started to see, first started to get to know better the API and started to see first minor issues. The first surprise was fact that they didn't have paginations. So in result, we had to store all data on client side. Other fact, the documentation was so poor besides the fact that it was really hard to find any information. This information was incomplete. For example, there was no info about return object types, which started to make sense after noticing that the return object types are not consistent. Some feeds could start on an empty array, or there was a feed that store a data time object for regular events and string with date range for festives. From our PO point of view, the saddest thing was fact that we didn't display prices on a list view. This information wasn't returned by endpoint for searching and calling the other endpoint for all return events would be too expensive. So after first print, we developed something like this. To cheer up our PO and improve user experience, our next task was enlarging searching. We wanted to add filtering and searching the events. The API provider wasn't offered as such complicated features, so to achieve this goal, we decided to store all data in our database. We developed the cron jobs that were downloading events every day at midnight. Additional advantage of this approach was fact that we could also download the prices by calling other ad points. Every frame seems to go well, but it was a calm before the storm. The problem appeared when all developers and testers started using in on their own local instances. It was edge people. The API provider wasn't prepared for so many calls, so they didn't catch the queries, and in result, they banned our IP addresses. After this action, they spent us another couple of times. Another visible dropback was fact that they didn't have test environment. The outcome of this was a small disaster. First of all, there was so many fake data on production, like special demo events specially prepared for testing buying the tickets. You have to spend a lot of time on their side to find it, whereas on our result page, this data was more exposed. Also, to prevent buying real tickets, our API key was locked. But when we wanted to release our feature, we needed to test buying real tickets. So API provider delivered us other unlock API key. Unfortunately, some misunderstanding occurred, and they unlocked rank API key. We found it out when a postman came to our office one beautiful day and delivered us a ticket. During integration with another provider, the most surprising were URA names. They were very unintuitive. To get the events, you have to go to slash localization endpoints, and event endpoints were performances. Sorry, I just lost myself again in the matter of mentioning it. Also, the data structure was so messy. This API was developed without understanding the client's need. We spent a lot of hours to get the logic and to map the structure of events to ours. So the question is, what could the API provider have done better? One of the answers can be a restful API. Rest stands for representation stage transfer. It's an architectural style with a set of constraints that allows a simple communication between two systems, basically a client and a server, where communication between these is based on HTTP. And now is the question for you guys, who can name all rest architectural constraints? I thought so. So the former rest describes six architectural constraints. Clean server architectural style is the basic restriction for a restful application. The client is disconnected. For example, clients are not concerned with data storage, and the servers are not concerned with user interface or user state. The purpose of this division is to separate architecture and responsibilities in both environments. In result, we improved the portability of the client's code by simplifying the server's components. The last is the constraints to the client-server interactions. One client can send multiple requests to the server, and each of them must be independent. This means that all requests to the server must contain all needed information to service the request. In order to improve network efficiency, all return data from server are explicitly labeled as cacheable or non-cacheable. We can cache response messages on client on the server or above site. The rule to create a cache can be different for each resource. We can clear the cache after a given period of time, or whenever there's a change in some state. Uniform interface is a central feature that distinguishes restful architectural styles from other network-based styles. It's a well-defined contract for communication between client and the server. The four guiding principles of uniform interface are identifying the resources, manipulating the resources through representations, sending descriptive messages, and hypermedia as the engine of application state. The layer system style allows an architecture to be composed of hierarchical layers. There can be multiple layers of software involved in retrieving information. So server may improve scalability by adding features like gateway, load balancer, firewall, or by providing short caches. Code-on-demand is an optional constraint. Servers can temporarily extend or customize the functionality of clients by transfer of executable code. Code-on-demand typically relies on web browser features like web browser plugins, applets, or client-side scripting languages. Complaining with these constraints rest-introduced certain architectural properties. Web service APIs that adhere to the rest-architecture constraints are called REST for APIs. Many people would go on to say that have a RESTful API uses only HTTP adjacent, and all of this is important and is part of RESTful itself. But to consider an API RESTful, it must strictly follow all the rules designed and defined in REST architecture. It's works to be familiarized with learner-to-track zone REST maturity model. A maturity model is a MIPE that guides users into level-increasing levels of compilance with some definition, methodology, or architecture. REST-zone-REST maturity model is the same time of improvement map for building web services. This maturity model knows four levels where the last one designates a truly RESTful API. The concept of REST is to separate the API structure into logical resources. Individual resources are identified by URIs. During design, the API resources don't directly map one-to-one your database into resources. You don't want to irrelevant implementation details in your API. Use sensible resource names. For example, in our ticketing module, some of the resources could look like these. You should notice that all of these resources are nouns, not verbs. Also, don't mix up singular and plural nouns. Keep it simple and use only plural. Use one case convention. There are three main case conventions. Common case, snake case, and spinal case. As a Pythonist, we would probably pick the snake case. Also, avoid apostrophes, spacing, and other exotic characters. Resources are identified by URIs and manipulated by HTTP operations. Post-get push-patch delete corresponds to create, read, update, and delete. So remember, get method should not alter the state. To sum up, if you want to retrieve a list of events, use method get or resource event. To get a specific event, just add ID to this resource. And if you want to create the event-use-pot method on resource events to update some event-use-put-or-patch method on the resource of concrete event and to delete-use-method delete. If you have a relations, good practice is to use two resources, but make at most two levels of nested API object. Operations on those resources look the same. Also, you can consider add to your response related resource representations. By default, use only this almost access-together. Avoid accumulating too much information and don't embed collections if it has too many components. By just the approach, you then can avoid making extra API calls and improve efficiency. And if that feature would be in our... would be in API in my previous project, you would have had prices on the list view from the beginning, and our PO would be happy. To describe return values, our API should return relevant HTTP status codes. Of course, we should use this well-known. For example, 200 OOK can be used to a successful get. When we create a successfully API... successfully a resource, API should return 201 created. Also, in this case, we should add to our response related URL to the just created resource. To handle the errors, also we should use HTTP status codes, like here in an example. Also, to inform user what happened, put... show a useful error message. For large datasets, limit the return amount of data as important. Try to make advance searching just add query parameters to the URL. If you want to enable further link, just use attributes name with an equal sign and expected values. To sort the results, use parameter sort, or ordered by with the name of attributes on which sorting will be performed. This will understand the just add hyphen before the attribute name. Sometimes basic filtering does not fit our needs. Then we should consider providing full text search, querying by multiple fields. A nice approach is to enable to think which are in response. Clients can save valuable memory by retrieving only needed information. There's parameters that takes a comma-separated fields to include. According to the rest theory, actions on resources are constrained to create read update delete. But in real life, there are some cases that doesn't fit this rule. For example, if you want to implement a multi-resource search, compute or convert something. For these exceptions, you should use verbs as URL names rather than an ounce. We should use URL names that are the most fitting. But also carefully describe these exceptions in your documentation. It's hard to foresee all resource representations. Almost each evolve after time. It's natural to version your API. There are many best approaches for versioning APIs. The most famous is to include version in your URL path. But other piece of work to use it by adding version in HTTP header. And don't advance default versioning. Paginate the results to make response easier to handle. Even if at the beginning you don't have large amount of data, you don't know how it will be in the future. And do this in an early design phase is easier. So there's also no one paging mechanism. You can add paging to your request by URL or HTTP header. In response, you can return pagination and envelope or header. For example, write or link header. As a result, we can easily navigate through the pages and consume the results. Both client and server needs to know which format is used for communications. We can use HTTP headers dedicated for this. In content type, define the request format. And accept specified return format. In response messages, enable pre-apprent. It will be easier to debug or analyzing your API through the browser. Try to avoid developing your response messages. In most cases, an unnecessary extra layer in the response messages. HyperMedia is the engine of application state. It is the most omitted constraint. But you should try to use it in your API. Just provide links to your API. If you don't have links in your API, your API will still be useful. But after providing them, it's more discoverable and self-descriptive. For example, if you want to find Madonna concert and some events portal, you have to go to search page, type Madonna, and pick proper event. To do this for your API, first you have to go to documentation and find endpoint for searching. And then you have to do the same to find out how you can display a proper event. And after providing the links, you have to find Madonna concert by API is your root address. You can interact with API just like you interact with browser. Documentation is an important part of API. It should enhance newcomers and make life easier for current users. So describe all features in that information. Put the examples of usage or requests or responses. Use code for this and your API will be easier to debug. Documentation should be easy to find and user-friendly. So try not to use developer jargon and make it pretty. From my experience point of view, I have this strange feeling that many developers are in kind of student state of mind. I mean they're not business nor user focus. They forgot they developed feature for real users which is totally opposite to 100% back-free demo path, specially created to satisfy professor need and pass some classes. And there is a high chance that it will fail each other way. And I'm sure you know what I'm talking about because we all did this. So remember, have a doubt. Make sure your code follows the best practices. Even the slices. Investigate how some part of your API should look like. Check how web giants do this. Use Google search to solve problem or use this issue to initiate the small talk in the kitchen or put this subject in your team. Use best practices where they make sense. But of course don't get stuck in infinitive loop of researching best approaches. Think, commit and go. The most important part is fact that you are thinking about the user. Thank you. Time for questions. I've got a question. When you talk about links in your API did you use or is specified anywhere the names? The examples of links? The example of links? For example, the metadata? Yes, you should use your names. The method. And you can also provide a short description about what this link is. Thanks. Questions? So you mentioned indeed about putting links in the response I guess that's what you indeed do as practice. Do you have any recommendation of how nested your response can be? I'm sorry, can you say something louder? Yeah, you can hear me now? Yes, better. So I was wondering how nested can response be? So how many layers of nesting you can do? By providing links, yes. By providing links or directly in the response so that you do not have to go to all the links? I think that should be at most the levels of nested links. But I think that the smartest approach is to you to pick the proper one which is the link which would be the most useful uses from this point of response. Anyone? No more questions? Thanks, Marvin, again.