How to Implement Idempotent API (Part 1)

  • Post last modified:January 24, 2023
  • Reading time:5 mins read

Discussing Idempotency, strategy to implement one

Introduction

  • As we are moving towards more microservice base architecture and interacting with different services and having a dependency on them is a very common design.
  • Since now we have more loosely coupled microservices that spans across different region, we have network partition to take care of. We have to handle error situations a little differently.
  • Making API Idempotent is one of the items that prevent servers from doing the same stuff more than once.
  • In this article, we will learn about idempotency and we can design our API to support idempotency so that we can avoid the side effects of rerunning the same process more than once.

What is Idempotency?

  • Idempotency essentially means that we are getting the same output if we do the same action N times.
  • For example, if we access https://www.google.com, we receive the same webpage. Our action doesn’t change anything on the server and we always get on the same page.
  • But consider a case where we making transactions with the vendor. If we make the same request more than once, we will be deducted more than once and hence this is not idempotency.
  • In the REST API concept, GET, PUT, UPDATE, DELETE, and OPTIONS are idempotent operation since they don’t change anything on the server and returns the same response every time.
  • While POST is not idempotent since it creates a new resource on the server/database every time we execute it.
  • Let’s understand idempotent and non-idempotent requests through the example

Examples

Idempotent Request

  • In the below example, the client makes a request to calculate two parameters a, and b. The client makes a post request and sends these two parameters as a request body.
  • In the happy path scenario, The server accepts the request and calculates the sum, and returns the result to the client. 
  • But now let’s consider the error path scenario, let’s say while returning results to the client, the server got crashed. The client waited for the response and finally timed out.
  • If the retry mechanism is implemented, then the client will make the request again after a timeout.
  • This time server responded correctly. If a client makes this retry request N times, the result will be the same, and no side effects of that. 
  • Such requests are Idempotent. In this case, we as engineers didn’t do anything because the nature of the request is by default Idempotent.
  • But all the requests are not like that, so a certain strategy would be needed to make the request Idempotent.

Before discussing the strategy to implement idempotency, first, let’s see an example of a non-idempotent request and the potential side effects from it

Non-Idempotent

  • Consider a use case where we have a job scheduler client that calls Job Scheduler API to schedule JOB_A.
  • Let’s consider the Happy path scenario. The client makes a request to the server, the server saves the status in the database and executes the job, and returns the response back to the client.
  • In case of a server crash, the client will not receive a response.
  • If the retry mechanism is implemented at the client then the client will make another request, this time job scheduler will kick off the JOB_A again, so now we have duplicate execution. this can be a serious issue if the JOB_A is doing critical operations.
  • Now we will see one strategy of making our API idempotent so that retry doesn’t end up scheduling the same job more than once.

Design Idempotent API

  • In this section, we will learn one potential strategy that we can use to make our API idempotent.
  • Consider the example mentioned in the previous section. 
    We will first request job_id from the server. The server will create Job_id and store it in the database with the current status, then return back job_id to the client.
  • Now client uses this job_id to request job execution to the server. Server checks if this job_id exists in the database and checks the status and accordingly executes the job and then returns a response to the client.
  • In this approach, we are binding requests with server-generated IDs.
  • Now if our server crashes before notifying the job execution result to the client then the client will make the same request again.
  • Now the server will check in the database if the job_id is already present in the database and confirm the execution status, after that it will send the response with the latest status and not rerun the job.
  • This is how we are using job_id as the binding key to the jobs and avoiding rerunning the job in the retry action.

Conclusion

  • In this article, we discuss Idempotency and why making API idempotent is important.
  • This article mostly covers theory, We will see the implementation of it in part 2 of this article.

BestSeller Course

Leave a Reply