JAVASCRIPT

Ensure Idempotency for API Write Operations to Prevent Duplicates

Implement client-side strategies to make API write requests idempotent, preventing duplicate operations on the server side due to retries or network issues.

const axios = require('axios');
const { v4: uuidv4 } = require('uuid'); // Install with: npm install uuid

const API_PAYMENT_URL = 'https://api.your-payment-gateway.com/charges'; // Example payment endpoint

/**
 * Creates a unique idempotency key for the request.
 * This key should be generated once per logical operation.
 */
function generateIdempotencyKey() {
  // A UUID is a common choice for an idempotency key.
  // For requests involving a specific user/session, you might prefix or suffix it
  // with a user ID or session ID for better server-side lookup, if applicable.
  return uuidv4();
}

/**
 * Makes an API call for a payment, ensuring idempotency.
 * @param {object} paymentDetails - Details for the payment.
 * @param {string} idempotencyKey - A unique key for this specific operation.
 */
async function processPayment(paymentDetails, idempotencyKey) {
  try {
    const response = await axios.post(
      API_PAYMENT_URL,
      paymentDetails,
      {
        headers: {
          'Content-Type': 'application/json',
          'Idempotency-Key': idempotencyKey, // Crucial header for idempotency
          'Authorization': 'Bearer YOUR_AUTH_TOKEN', // Replace with actual auth
        },
        // Optional: you might want a timeout for requests that take too long
        timeout: 10000, // 10 seconds
      }
    );
    console.log('Payment processed successfully:', response.data);
    return response.data;
  } catch (error) {
    if (error.response) {
      console.error('Error processing payment (status:', error.response.status, 'data:', error.response.data);
      // Servers might return specific status codes (e.g., 409 Conflict)
      // to indicate an idempotent request was received and already processed.
      if (error.response.status === 409) { // Example conflict status
        console.warn('Payment with this idempotency key was likely already processed.');
      }
    } else {
      console.error('Network or other error processing payment:', error.message);
    }
    throw new Error('Payment processing failed.');
  }
}

// Example usage:
(async () => {
  const paymentDetails = {
    amount: 5000, // in cents
    currency: 'usd',
    customer_id: 'cust_12345',
    payment_method_id: 'pm_card_visa',
    description: 'Purchase of premium subscription',
  };

  const currentIdempotencyKey = generateIdempotencyKey();
  console.log('Generated Idempotency Key:', currentIdempotencyKey);

  try {
    // First attempt to process payment
    await processPayment(paymentDetails, currentIdempotencyKey);
    console.log('First payment attempt completed.');

    // Simulate a network issue or retry:
    // If the first request timed out or failed *after* the server received it,
    // retrying with the *same* idempotency key ensures the payment isn't duplicated.
    console.log('
Simulating a retry with the same idempotency key...');
    await processPayment(paymentDetails, currentIdempotencyKey);
    console.log('Second payment attempt (retry) completed. Server should handle it idempotently.');

  } catch (error) {
    console.error('Overall process failed:', error.message);
  }
})();
How it works: This Node.js snippet illustrates how to implement client-side idempotency for API write operations, particularly crucial for sensitive actions like payments or order creation. By generating a unique `Idempotency-Key` (typically a UUID) for each logical operation and including it in the request headers, the client signals to the server that multiple identical requests with the same key should be treated as a single operation. This prevents duplicate actions if the client retries a request due to network issues or timeouts, enhancing the reliability of API integrations.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs