Idempotency Explained: Ensuring Reliable and Repeated API Calls in Nestjs

Idempotency refers to an operation that can be performed multiple times without causing additional effects. In other words, no matter how many times the same action is repeated, the result will always be the same as if it had been executed only once.


This content originally appeared on DEV Community and was authored by João Paulo

Idempotency refers to an operation that can be performed multiple times without causing additional effects. In other words, no matter how many times the same action is repeated, the result will always be the same as if it had been executed only once.

Idempotency ensures that the operation is only processed once, even if it's executed multiple times, preventing duplicate payments or unintended outcomes. This is particularly useful in scenarios where operations, such as processing a credit transaction, might be retried due to network failures or system crashes.

In the context of web development, certain HTTP methods are idempotent and others no.

methods-idempotency

  • GET: Retrieving a resource using a GET request should not change the state of the resource on the server. Whether you request the same resource once or multiple times, the result should be the same.
  • PUT: Updating a resource using a PUT request should result in the same resource state regardless of how many times the request is made with the same data.

Some HTTP methods are not idempotent, meaning that repeated applications of the same request can lead to different results. Two common examples are POST and PATCH:

  • POST: The POST method is typically used to create new resources or submit data. Each POST request can create a new resource or initiate a new action, so sending the same POST request multiple times can result in multiple new resources or actions being created.
  • PATCH: The PATCH method is used to apply partial modifications to a resource. Since the PATCH request updates only certain fields, the outcome can change with each request, depending on the state of the resource before the update.

Why Idempotency Matters

Idempotency is crucial in systems where reliability and consistency are important. It helps in:

  1. Fault Tolerance: Idempotent operations ensure that retrying operations won’t lead to inconsistent states or unintended effects.
  2. Simplicity: Designing systems with idempotent operations can simplify error handling and recovery processes.
  3. Concurrency: Idempotency helps in managing concurrent operations, reducing the risk of conflicting changes.

Implementing an idempotent endpoint in Nestjs

1. Create the Idempotency Middleware

import {
  Injectable,
  NestMiddleware,
  BadRequestException,
} from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { IdempotencyService } from '../services/idempotency.service';

@Injectable()
export class IdempotencyMiddleware implements NestMiddleware {
  constructor(private readonly idempotencyService: IdempotencyService) {}

  async use(req: Request, res: Response, next: NextFunction) {
    const idempotencyKey = req.headers['x-idempotency-key'] as string;
    if (!idempotencyKey) {
      throw new BadRequestException('Idempotency key is missing');
    }

    const cachedKey = await this.idempotencyService.getKey(idempotencyKey);

    if (cachedKey) {
      res.status(200).json(cachedKey);
      return;
    }

    res.on('finish', async () => {
      if (res.statusCode < 400) {
        await this.idempotencyService.saveKey(idempotencyKey);
      }
    });
    next();
  }
}

2. Create the Idempotency Service

import { Inject, Injectable } from '@nestjs/common';
import {
  iDistributedCacheService,
  IDistributedCacheService,
} from './distributed-cache.service';
import { TEN_MINUTES } from '../constants/app.constants';

@Injectable()
export class IdempotencyService {
  constructor(
    @Inject(iDistributedCacheService)
    private readonly distributedCache: IDistributedCacheService,
  ) {}

  async getKey(key: string): Promise<string> {
    return await this.distributedCache.get(key);
  }

  async saveKey(key: string): Promise<void> {
    this.distributedCache.set(key, key, TEN_MINUTES);
  }
}

Note, in this case i used a general cache service, you can store it in a simple HashMap local or something more robust like redis

3. Register the middleware in your app module

import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common';
import { TransactionsModule } from './modules/transactions/transactions.module';
import { PrismaModule } from './modules/prisma/prisma.module';
import { PrismaService } from './modules/prisma/prisma.service';
import { ClientsModule } from './modules/clients/clients.module';
import { ConfigModule } from '@nestjs/config';
import { IdempotencyMiddleware } from './libs/commons/middlewares/idempotency.middleware';
import { RedisDistributedCacheService } from './libs/commons/services/redis-distributed-cache.service';
import { iDistributedCacheService } from './libs/commons/services/distributed-cache.service';
import { IdempotencyService } from './libs/commons/services/idempotency.service';

@Module({
  imports: [
  ],
  providers: [
    IdempotencyService
  ],
})
export class AppModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(IdempotencyMiddleware)
      .forRoutes({ path: 'transactions', method: RequestMethod.POST });
  }
}

Yow can now test the implemetation. Make a POST request to the route that you registered with the x-idempotency-key in header. The server should not proccess duplicate requests.

Thank you for reaching this point. If you need to contact me, here is my email: joaopauloj405@gmail.com


This content originally appeared on DEV Community and was authored by João Paulo


Print Share Comment Cite Upload Translate Updates
APA

João Paulo | Sciencx (2024-09-14T22:42:29+00:00) Idempotency Explained: Ensuring Reliable and Repeated API Calls in Nestjs. Retrieved from https://www.scien.cx/2024/09/14/idempotency-explained-ensuring-reliable-and-repeated-api-calls-in-nestjs/

MLA
" » Idempotency Explained: Ensuring Reliable and Repeated API Calls in Nestjs." João Paulo | Sciencx - Saturday September 14, 2024, https://www.scien.cx/2024/09/14/idempotency-explained-ensuring-reliable-and-repeated-api-calls-in-nestjs/
HARVARD
João Paulo | Sciencx Saturday September 14, 2024 » Idempotency Explained: Ensuring Reliable and Repeated API Calls in Nestjs., viewed ,<https://www.scien.cx/2024/09/14/idempotency-explained-ensuring-reliable-and-repeated-api-calls-in-nestjs/>
VANCOUVER
João Paulo | Sciencx - » Idempotency Explained: Ensuring Reliable and Repeated API Calls in Nestjs. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/09/14/idempotency-explained-ensuring-reliable-and-repeated-api-calls-in-nestjs/
CHICAGO
" » Idempotency Explained: Ensuring Reliable and Repeated API Calls in Nestjs." João Paulo | Sciencx - Accessed . https://www.scien.cx/2024/09/14/idempotency-explained-ensuring-reliable-and-repeated-api-calls-in-nestjs/
IEEE
" » Idempotency Explained: Ensuring Reliable and Repeated API Calls in Nestjs." João Paulo | Sciencx [Online]. Available: https://www.scien.cx/2024/09/14/idempotency-explained-ensuring-reliable-and-repeated-api-calls-in-nestjs/. [Accessed: ]
rf:citation
» Idempotency Explained: Ensuring Reliable and Repeated API Calls in Nestjs | João Paulo | Sciencx | https://www.scien.cx/2024/09/14/idempotency-explained-ensuring-reliable-and-repeated-api-calls-in-nestjs/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.