{"id":1965,"date":"2022-07-07T11:10:46","date_gmt":"2022-07-07T08:10:46","guid":{"rendered":"http:\/\/52.91.248.125\/idempotent-apis-tips-to-build-resilient-apps-2\/"},"modified":"2023-02-28T11:53:24","modified_gmt":"2023-02-28T09:53:24","slug":"idempotent-apis-tips-to-build-resilient-apps-2","status":"publish","type":"post","link":"https:\/\/www.orfium.com\/ja\/news\/idempotent-apis-tips-to-build-resilient-apps-2\/","title":{"rendered":"Idempotent APIs \u2014 Tips to build resilient apps"},"content":{"rendered":"\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh5.googleusercontent.com\/B75l-r_5z9SOh2V-wAd14ayPsCUZHOPNeCOtpQl1y_bzLaw_6kwusppd3XNmg79yXXn0XCra1jqJUoIP0vLoBfBsnM4Lva9CMA7uu5QJzNwc4oEoUNzA2DZ5U9P9XuYOEpm7D0zoFS3jZ0X9Ug\" alt=\"\"\/><\/figure>\n\n\n\n<p>Photo by <a href=\"https:\/\/unsplash.com\/@timmossholder\">Tim Mossholder<\/a> on <a href=\"https:\/\/unsplash.com\/photos\/GoHaYpu7-ks\">Unsplash<\/a><\/p>\n\n\n\n<p>There is a question to which typically we, as Developers, kind of turn a blind eye.<\/p>\n\n\n\n<p><strong><em>When was the last time your product had downtime? How did it affect your customers?<\/em><\/strong><\/p>\n\n\n\n<p>And why wouldn\u2019t we?<\/p>\n\n\n\n<p>We follow all the Agile processes, we go through multiple debates during the code review phase, we have automated and unit tests, we have QA teams that catch nasty bugs early, we write types on both Frontend and Backend, we use state-of-the-art tools, we do everything by the book. We trust that <strong>our code represents our best collective work.<\/strong> <strong>We expect it to simply work!<\/strong><\/p>\n\n\n\n<p>&#8230;<\/p>\n\n\n\n<p>&#8230;<\/p>\n\n\n\n<p>&#8230;<\/p>\n\n\n\n<p><em>Until it doesn\u2019t<\/em><strong>.<\/strong><\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/52.91.248.125\/wp-content\/uploads\/2023\/02\/elisa-ventur-bmJAXAz6ads-unsplash-1-scaled.jpg\" alt=\"\" class=\"wp-image-1056\" width=\"768\" height=\"512\"\/><figcaption>Photo by <a href=\"https:\/\/unsplash.com\/@elisa_ventur?utm_source=medium&amp;utm_medium=referral\">Elisa Ventur<\/a> on <a href=\"https:\/\/unsplash.com\/?utm_source=medium&amp;utm_medium=referral\">Unsplash<\/a><\/figcaption><\/figure>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p><strong>API resiliency<\/strong> refers to the idea that we build APIs which are able to recover from failure. Failures can be caused by either our own or third-party service problems, server outages, DDoS attacks, network issues, and so much more. Frankly, there are innumerable reasons for which these failures occur. What\u2019s more important is how you recover from them and ensuring they do no lasting damage. Let\u2019s talk about an example.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Case: Artist wants to upload his song to our App<\/strong><\/h3>\n\n\n\n<p>We have created an <strong>App <\/strong>that has a <strong>Client <\/strong>and an <strong>API Server.<\/strong><\/p>\n\n\n\n<p>In our case, let\u2019s say that <strong>our user is an artist<\/strong> who is trying to<strong> submit their<\/strong> <strong>song<\/strong> to our platform, so we can collect royalties on their behalf.<\/p>\n\n\n\n<p>We wrote a POST HTTP method that creates the song in the Server\u2019s Database. This endpoint has many ways to respond back. It could return 200 for success, 400 for unauthorized access, 500 for server errors, or even worse, it might never answer back.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"alignleft is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/7UU3RBBUe-Zf0sYcuEePU09BpIGrNfSeNWczzRh20Nja-H7bi2RaPSqRlJCGDWl8ktc3JSQr3J7N0hwCZf4pgVhRt-BkXOxiZVA0-vVP9DtEpZ3YIU8NyyDWvLj1AjopVmqHrbkUD-eXkDt32A\" alt=\"\" width=\"1395\" height=\"384\"\/><\/figure><\/div>\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>In cases of failure, clients either deal with it with error handling methods that give our artist some information about what went wrong or, in case we don\u2019t want to interrupt the artist\u2019s journey, they schedule it to try again. But beware: We want to be careful in this case to not overload the system with requests. Which is why it is recommended to implement exponential backoff.<\/p>\n\n\n\n<p><strong>Exponential backoff<\/strong> is a standard error-handling strategy for network applications. In this approach, a client periodically retries a failed request with increasing delays. Clients should use exponential backoff for all requests that return HTTP 5xx and 429 response codes, as well as for disconnections from the server. Eventually, the client should reach either a limit of maximum retries or time and stop attempting to communicate with the server. The great thing about exponential backoff is that it ensures that, when the Server is amidst an incident, it is not flooded with requests.<\/p>\n\n\n\n<p><strong>But, how do we know if the first request actually failed<\/strong>?<\/p>\n\n\n\n<p>As we said before, there can be many reasons why an API could not respond back to the client. So, how are we sure that the server\u2019s database hasn\u2019t already saved the song? If one of our retries succeeds, we could end up having submitted the same song twice. This is a big problem, because what we actually wanted to do is to make sure our whole operation is <strong>idempotent.<\/strong><\/p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><strong>Idempotence means that, if an identical request has been made once or several times in a row, it results in the same effect while leaving the server in the same state.<\/strong><\/p><\/blockquote>\n\n\n\n<p>A great everyday example of idempotence is a dual button ON\/OFF setup. Pressing ON once or multiple times results in only 1 result: the system is on. Same goes for the OFF button.&nbsp;<\/p>\n\n\n\n<p>When talking about idempotence in the context of HTTP, another term that pops up is <strong>data safety<\/strong>. In that case, safety means that <strong>the request doesn\u2019t mutate data on invocation<\/strong>. The table below shows commonly used HTTP methods, their safety and idempotence.<\/p>\n\n\n\n<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<\/p>\n\n\n\n<p>|&nbsp; &nbsp; Http Method&nbsp; &nbsp; |&nbsp; &nbsp; Safety&nbsp; &nbsp; |&nbsp; &nbsp; Idempotency&nbsp; &nbsp; |<\/p>\n\n\n\n<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<\/p>\n\n\n\n<p>| GET &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Yes&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Yes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<\/p>\n\n\n\n<p>| PUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | No &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Yes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<\/p>\n\n\n\n<p>| POST&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | No &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | No&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<\/p>\n\n\n\n<p>| DELETE&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | No &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Yes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<\/p>\n\n\n\n<p>| PATCH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | No &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | No&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<\/p>\n\n\n\n<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<\/p>\n\n\n\n<p>So as we can see, our POST method fails at both. <em>Great.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Solution<\/strong><\/h3>\n\n\n\n<p>Let\u2019s go back to our whole operation. What do we have?<\/p>\n\n\n\n<p>We have a client that tells the Server that it needs to save the song. A possible scenario of that JSON request could look like this:<\/p>\n\n\n\n<p style=\"font-style:italic;font-weight:300\">{<\/p>\n\n\n\n<p style=\"font-style:italic;font-weight:300\">&nbsp;userID: \u201cUID-123\u201d,<\/p>\n\n\n\n<p style=\"font-style:italic;font-weight:300\">&nbsp;songTitle: \u201cComfortably Numb\u201d,<\/p>\n\n\n\n<p style=\"font-style:italic;font-weight:300\">&nbsp;songArtist: \u201cPink Floyd\u201d,<\/p>\n\n\n\n<p style=\"font-style:italic;font-weight:300\">&nbsp;songReleaseDate: \u201c1979\u201d<\/p>\n\n\n\n<p style=\"font-style:italic;font-weight:300\">}<\/p>\n\n\n\n<p>We could ask the client to perform this request as an idempotent request, by providing an additional Idempotency-Key: &lt;key&gt; header to the request.<\/p>\n\n\n\n<p>An <strong>idempotency key<\/strong> is a unique value generated by the Client, which the server uses to recognize subsequent attempts of the same request. How you create unique keys is up to you, but it\u2019s suggested to use V4 UUIDs, or another random string with enough entropy to avoid collisions.<\/p>\n\n\n\n<p>When the Server receives this Idempotency-Key, it should save in the database the <strong>body of the first request made <\/strong>for any given idempotency key<strong> <\/strong>and <strong>resulting status code<\/strong>, regardless of whether it succeeded or failed.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"alignleft\"><img decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/Ht-AIbEniUcj2r93eiFp83ihUcNPjDGAUdwKaTr_TGriWghsz96zqHqtPdXwNeIUFHLJvGEF5ClYX4eoFgzsblaLhH4zb5LZ_KS_FVgwgrLfEc8EphBgORw9nVUr0kz0ylq3oOVKbl-sQUx9lQ\" alt=\"\"\/><\/figure><\/div>\n\n\n<div style=\"height:31px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Now, for every request that comes, the Server can verify if i<strong>t has already<\/strong> <strong>mutated the data, <\/strong>just by checking the status in its DB. The idempotency layer should compare incoming parameters to those of the original request and errors (unless they\u2019re the same) to prevent accidental misuse.<\/p>\n\n\n\n<p>With this solution, we no longer have to worry about duplication of data or conflicts. it ensures that, no matter how many times we repeat this process, our operation is idempotent and the artist will receive the success message when the system is able to save their song.<\/p>\n\n\n\n<p>These Idempotency-Keys should be eligible for removal automatically after they\u2019re at least 24 hours old.<\/p>\n\n\n\n<p><strong>P.S. <\/strong>For the simplicity of the example we saved our songs and the keys to the same database. Ideally, you will save these keys on a cache server (e.g. Redis) with a TTL of 24hours, so the removal of the old keys happens by default.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>In conclusion<\/strong><\/h3>\n\n\n\n<p>An application that uses an API which implements idempotence can follow the steps below to ensure proper usage:<\/p>\n\n\n\n<ol><li>Create idempotence keys and attach them to the header.<\/li><li>When a request is unsuccessful, follow a retry policy such as exponential backoff.<\/li><li>Save the request body and idempotency key in a cache server.<\/li><li>Mutate the data.<\/li><li>Update the idempotency key with the result of the mutation<\/li><li>After a failure of either 5xx, 429 or no response from the server, the client retries the request.<\/li><li>The server validates if the idempotency key exists on the cache server.<\/li><li>The server validates if the body of the request is the same as the one in cache server<\/li><li>If everything is the same, the server will not mutate the data but return the previously saved result of the mutation.<br><br><\/li><\/ol>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-layout-1 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full is-resized is-style-rounded\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/52.91.248.125\/wp-content\/uploads\/2023\/02\/Elektra_Bilali.jpeg\" alt=\"\" class=\"wp-image-1058\" width=\"144\" height=\"144\"\/><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p>Elektra Bilali Simou<\/p>\n\n\n\n<p>Engineering manager ORFIUM<\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/elektracodes\" target=\"_blank\">https:\/\/github.com\/elektracodes<\/a><\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/www.linkedin.com\/in\/elektra-bilali-simou\/\" target=\"_blank\">https:\/\/www.linkedin.com\/in\/elektra-bilali-simou\/<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/elektracodes\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/elektracodes\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><\/p>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Photo by Tim Mossholder on Unsplash There is a question to which typically we, as Developers, kind of turn a b [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":1929,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_seopress_robots_primary_cat":"none","_seopress_titles_title":"","_seopress_titles_desc":"","_seopress_robots_index":"","content-type":"","footnotes":""},"categories":[19],"tags":[],"acf":[],"_links":{"self":[{"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/posts\/1965"}],"collection":[{"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/comments?post=1965"}],"version-history":[{"count":1,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/posts\/1965\/revisions"}],"predecessor-version":[{"id":1966,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/posts\/1965\/revisions\/1966"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/media\/1929"}],"wp:attachment":[{"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/media?parent=1965"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/categories?post=1965"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/tags?post=1965"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}