Build Retry-able API using idempotency key
If you have been working on API implementation for awhile and try to make your API resilient & bulletproof, the topic today might be something you will find interesting. Today, nobody can guarantee the microservices that you built will not run into trouble. When issue occurred, we often hope that the simplest way to solve the issue is to retry and invoke the API again. Retry can be an easy mechanism handled by your middleware/ API orchestration product. The challenge for doing so will always be on the business logic of the API if the nature of the record can gracefully managed the duplication through something like Primary Key. (e.g. create a car record with car registration number) You probably won't hit a problem when performing record update (if multiple updates is not a problem. e.g. update status of your car record from "available" to "sold"), but it will be tricky for scenario of record creation.(e.g. create a sales record for a car)
Making microservices resilient can be a nightmare if the solution to this has to always be implemented in business logic. Every business logic will then need to be reviewed and ensure that the logic can gracefully manage duplication. What if I tell you there is a consistent approach to check duplication without touching the business logic? You don't even need to crack your head to analyse the primary key and manage the duplication when your API need to be retried by your API workflow.
I found the answer as I looking at the implementation of idempotency key for API and it is really simple and straightforward. Basically, idempotency key is an unique key to represent a specific transaction within a particular validity period. Instead of implementing a business logic to check data duplication, API consumer need to issue a unique key called idempotency key when making a request. You can ten check idempotency key to confirm if this is an identical transaction. (Please see the diagram below for illustration.)
Hands on Implementation
Sample Implementation
I am using the latest version of threadfin-http for this implementation; which allows me to create API handler for different HTTP methods. In this example, I will create an API for HTTP PUT method. To do this, you need to create a "put" folder in your API folder. Then create a handler.js in the put folder. In this example I am creating an API call process. Hence, I will name my handler process_handler.js (with handler POSTFIX set as _handler in config.json)
Below is the sample code of my process_handler.js:
Firstly, you need to extract the idempotency-key from request header (Please see below)
var idempotency_key = req.headers['idempotency-key']
After that, you can use redis.get method to check the idempotency key in Redis server. Redis server will return null value if the submitted idempotency key is not available.
If idempotency key doesn't exist, it means this request has not been processed previously. It will be safe for us to create the record accordingly. After the record successfully processed, We can then use redis.set method to create an entry in Redis server. I use "EX", 120 to set TTL to 120 seconds for this record. TTL will automatically be used by Redis to purge the record when the set TTL is lapsed.
If result does exist (i.e. else condition in sample code) , We may then set HTTP status code to 409 and send conflict status back to API consumer.
Testing the implementation
That's all we have to implement checking of idempotency key. Now, we can proceed to test the implementation using any HTTP client tool (e.g. POSTMAN).
First, I send a HTTP PUT request (http:/localhost:8888/process) by setting Idempotency-Key to "123-123-123". You use received HTTP status 200 as the idempotency key has not been used before.
When you submit the request again with the same Idempotency-Key, HTTP status code 409 will return instead HTTP status code 200 which we previously received.
If you wait for the TTL to lapse and you submit again with the same Idempotency Key, the API request will return HTTP status code 200 again.
Wrapping Up...
I hope today's sharing give you a brief idea of how to use idempotency key to address you business problem. Do drop me a comment if you have any question. Happy coding !
Comments
Post a Comment