DEV Community

Cover image for Implementing Idempotency with NestJS RedisX: A Practical Guide
Suren Krmoian
Suren Krmoian

Posted on

Implementing Idempotency with NestJS RedisX: A Practical Guide

Handling duplicate requests in APIs, especially in payment systems, is a headache. NestJS RedisX offers a neat way to tackle this with its Idempotency Plugin. Let’s dig into how you can set this up.

Getting Started with Idempotency

First things first, install the necessary packages. You'll need both the core and idempotency packages of NestJS RedisX:

npm install @nestjs-redisx/core @nestjs-redisx/idempotency
Enter fullscreen mode Exit fullscreen mode

Configuring the Module

To make the Idempotency Plugin work its magic, you need to configure it in your main module. This setup ensures that the plugin is ready to catch any duplicate requests globally.

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { RedisModule } from '@nestjs-redisx/core';
import { IdempotencyPlugin } from '@nestjs-redisx/idempotency';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { IdempotencyInterceptor } from '@nestjs-redisx/idempotency';

@Module({
  imports: [
    ConfigModule.forRoot(),
    RedisModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      plugins: [
        IdempotencyPlugin.registerAsync({
          imports: [ConfigModule],
          inject: [ConfigService],
          useFactory: (config: ConfigService) => ({
            defaultTtl: 86400, // 24 hours
            headerName: 'Idempotency-Key',
          }),
        }),
      ],
      useFactory: (config: ConfigService) => ({
        clients: {
          host: config.get('REDIS_HOST', 'localhost'),
          port: config.get('REDIS_PORT', 6379),
        },
      }),
    }),
  ],
  providers: [
    { provide: APP_INTERCEPTOR, useClass: IdempotencyInterceptor },
  ],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Decorating Your Endpoints

Once your module is good to go, use the @Idempotent decorator on your endpoints. This ensures that each request is uniquely processed based on the Idempotency-Key.

import { Controller, Post, Body } from '@nestjs/common';
import { Idempotent } from '@nestjs-redisx/idempotency';

@Controller('payments')
export class PaymentsController {
  constructor(private readonly paymentService: PaymentService) {}

  @Post()
  @Idempotent()
  async createPayment(@Body() dto: CreatePaymentDto) {
    return this.paymentService.process(dto);
  }
}
Enter fullscreen mode Exit fullscreen mode

Behind the Scenes

Here’s the lowdown: the Idempotency Plugin checks each request’s Idempotency-Key. If it’s seen the key before, it serves the cached result. No re-processing, no fuss.

  • Body Fingerprinting: It goes a step further by ensuring the request body’s fingerprint matches the key. This prevents using the same key for different data.
  • Concurrent Handling: If multiple requests with the same key pop up, the plugin handles them in sequence, avoiding any duplication.

Incorporating an idempotency layer using NestJS RedisX is pretty straightforward. It's a solid way to dodge duplicate processing in sensitive areas like payments. Want to dive deeper? Check out the official documentation.

Top comments (0)