ویرگول
ورودثبت نام
Nastooh
Nastooh
Nastooh
Nastooh
خواندن ۱۰ دقیقه·۴ روز پیش

API - Idempotency

Idempotency چیست؟

Idempotency یعنی اگر یک درخواست یکسان چند بار به API ارسال شود، اثر نهایی روی سیستم فقط یک‌بار اعمال شود و تکرار همان درخواست باعث ایجاد داده‌ی تکراری، عملیات تکراری یا تغییر وضعیت ناخواسته نشود.

به بیان ساده‌تر:
اگر یک Request به دلیل timeout، retry، network issue، double click کاربر یا ارسال مجدد از سمت Client دوباره فرستاده شود، سیستم باید بتواند تشخیص دهد این همان درخواست قبلی است و دوباره همان عملیات را تکرار نکند.


چرا Idempotency مهم است؟

در سیستم‌های واقعی، مخصوصاً بانکی، مالی، پرداخت، انتقال وجه، ثبت سفارش و ایجاد مشتری، تکرار ناخواسته‌ی یک درخواست می‌تواند فاجعه بسازد.
مثلاً:

  • یک تراکنش دوبار ثبت شود

  • یک مشتری دوبار ساخته شود

  • یک پرداخت دوبار از حساب کم شود

  • یک درخواست ثبت وام دوبار پردازش شود

Idempotency دقیقاً برای جلوگیری از همین duplicate processing و double execution است.


تعریف امتحانی Idempotency

اگر یک Operation را با ورودی یکسان چند بار اجرا کنیم، نتیجه‌ی نهایی سیستم باید معادل اجرای یک‌بار آن Operation باشد.
در API Testing، Idempotency یعنی تکرار یک Request نباید باعث ایجاد رکورد تکراری، تراکنش تکراری یا تغییر وضعیت غیرمنتظره شود.


Idempotency با Retry چه ربطی دارد؟

خیلی زیاد.
در سیستم‌های توزیع‌شده یا حتی در APIهای معمولی، این سناریو زیاد پیش می‌آید:

  • Client درخواست را می‌فرستد

  • Server عملیات را انجام می‌دهد

  • ولی Response به Client نمی‌رسد، چون timeout یا network issue رخ می‌دهد

  • Client فکر می‌کند درخواست fail شده و دوباره همان Request را می‌فرستد

اگر API Idempotent نباشد، ممکن است همان عملیات دوباره انجام شود.
پس Idempotency جلوی آسیب ناشی از retry را می‌گیرد.


Idempotency در چه عملیات‌هایی مهم‌تر است؟

بیشترین اهمیت را در این سناریوها دارد:

  • Transfer Money

  • Payment

  • Create Order

  • Create Customer

  • Submit Application

  • Create Invoice

  • Reserve Seat / Booking

  • هر جایی که Create یا Business Transaction داریم و تکرار آن خطرناک است


تفاوت Idempotent و Non-Idempotent

Idempotent Operation

اگر یک درخواست را چند بار تکرار کنیم، نتیجه‌ی نهایی همان نتیجه‌ی اجرای اول است.

مثال:

  • چند بار یک وضعیت را روی inactive بگذاری و هر بار همان inactive بماند

  • یک PUT که هر بار دقیقاً همان داده را جایگزین می‌کند

Non-Idempotent Operation

اگر تکرار درخواست باعث تغییر جدید، رکورد جدید یا اثر جدید شود.

مثال:

  • هر بار POST /payments یک پرداخت جدید بسازد

  • هر بار POST /customers یک مشتری جدید ثبت کند

  • هر بار POST /transfer دوباره از حساب کم کند


Idempotency و HTTP Method

در طراحی RESTful API معمولاً از نظر مفهومی این‌طور نگاه می‌شود:

GET

باید Idempotent باشد.
چند بار صدا زدن GET نباید state سیستم را تغییر دهد.

PUT

معمولاً Idempotent است.
چون قرار است یک Resource را با یک representation مشخص جایگزین کند. اگر همان PUT را چند بار با همان Body بفرستی، نتیجه‌ی نهایی نباید فرق کند.

DELETE

از نظر مفهومی Idempotent در نظر گرفته می‌شود.
چون اگر Resource یک بار حذف شده باشد، حذف دوباره نباید اثر جدیدی بسازد. ممکن است بار دوم 404 بدهد یا پاسخ دیگری، ولی نباید دوباره اثر بیزینسی جدیدی ایجاد کند.

POST

به‌طور پیش‌فرض Idempotent نیست.
چون معمولاً برای Create یا Action استفاده می‌شود و هر بار می‌تواند اثر جدیدی بسازد.
برای همین در POSTها، مخصوصاً عملیات مالی، Idempotency را معمولاً با مکانیزم‌های اضافی پیاده‌سازی می‌کنند.


Idempotency در POST چطور پیاده می‌شود؟

رایج‌ترین راه، استفاده از Idempotency Key است.

Idempotency Key چیست؟

یک شناسه‌ی یکتا است که Client همراه Request می‌فرستد تا Server بتواند بفهمد این درخواست قبلاً پردازش شده یا نه.

معمولاً در Header می‌آید، مثلاً:

Idempotency-Key: 8f6d9b1a-45e2-4c3a-9e11-abc123xyz

یا گاهی:

X-Idempotency-Key: 8f6d9b1a-45e2-4c3a-9e11-abc123xyz

جریان کار Idempotency Key

فرض کن Client می‌خواهد انتقال وجه انجام دهد:

POST /transfers Idempotency-Key: 12345-abc Content-Type: application/json
{ "fromAccount": "1001", "toAccount": "2001", "amount": 500000 }

بار اول

Server این درخواست را می‌گیرد، Idempotency Key را ذخیره می‌کند، عملیات را انجام می‌دهد و Response برمی‌گرداند.

بار دوم با همان Key و همان Request

Server باید تشخیص دهد این درخواست قبلاً پردازش شده و نباید دوباره انتقال وجه انجام شود.
در عوض باید:

  • یا همان نتیجه‌ی قبلی را برگرداند

  • یا به‌صورت کنترل‌شده بگوید این Request قبلاً پردازش شده


Idempotency فقط با Header نیست

گرچه Idempotency-Key رایج‌ترین روش است، اما تنها راه نیست.
گاهی سیستم با این‌ها هم جلوی duplicate را می‌گیرد:

  • Unique business key

  • Database unique constraint

  • Request fingerprint

  • Deduplication logic

  • Transaction lock

  • Message deduplication در سیستم‌های async

اما از دید تست API، مهم‌ترین چیزی که زیاد با آن روبه‌رو می‌شوی Idempotency-Key است.


رفتار درست API در سناریوی تکرار Request

فرض کن یک POST /payments با یک Idempotency-Key مشخص ارسال شده و موفق بوده. حالا همان Request دوباره ارسال می‌شود.

رفتار درست معمولاً یکی از این‌هاست:

  1. همان نتیجه‌ی قبلی را برگرداند

  2. بگوید این درخواست قبلاً پردازش شده

  3. به هیچ‌وجه پرداخت جدید یا رکورد جدید نسازد

نکته مهم این است که state سیستم دوباره تغییر نکند.


سناریوی بانکی مهم

فرض کن کاربر روی دکمه‌ی «انتقال وجه» دوبار کلیک می‌کند یا اپلیکیشن به‌خاطر timeout دوباره درخواست را می‌فرستد.

Request:

POST /transfers Idempotency-Key: transfer-9981
{ "fromAccount": "1111", "toAccount": "2222", "amount": 1000000 }

اگر API Idempotency نداشته باشد، ممکن است:

  • دوبار از حساب کم شود

  • دوبار سند حسابداری ثبت شود

  • دوبار notification ارسال شود

اگر Idempotency درست پیاده شده باشد:

  • فقط یک تراکنش واقعی ثبت می‌شود

  • درخواست دوم اثر جدیدی ندارد


فرق Idempotency با Duplicate Validation

این دو به هم نزدیک‌اند، ولی یکی نیستند.

Duplicate Validation

یعنی سیستم بررسی کند مثلاً email یا nationalCode تکراری ثبت نشود.

Idempotency

یعنی همان درخواست تکراری دوباره باعث اجرای عملیات نشود.

مثلاً:

  • Duplicate Validation: نگذارد دو مشتری با یک nationalCode ساخته شوند

  • Idempotency: نگذارد همان درخواست ثبت مشتری به خاطر retry دوبار اجرا شود

ممکن است هر دو لازم باشند.


Idempotency و Concurrency

در سیستم‌های بانکی فقط retry مهم نیست؛ هم‌زمانی هم مهم است.
مثلاً اگر دو درخواست تقریباً هم‌زمان با یک Idempotency-Key برسند، سیستم باید طوری طراحی شده باشد که هر دو را به‌عنوان دو عملیات مستقل پردازش نکند.

پس Idempotency فقط یک validation ساده نیست؛ بخشی از system design، transaction control و concurrency handling هم هست.


از دید تستر چه چیزهایی را باید تست کرد؟

سناریوی اصلی 1: تکرار همان Request با همان Idempotency-Key

  • Request اول موفق شود

  • Request دوم با همان Key و همان Body ارسال شود

  • سیستم نباید رکورد جدید بسازد

  • سیستم نباید تراکنش جدید انجام دهد

  • Response باید مطابق Contract باشد

سناریوی اصلی 2: همان Idempotency-Key با Body متفاوت

این خیلی مهم است.
اگر همان Idempotency-Key را با payload متفاوت بفرستی، رفتار سیستم باید مشخص و کنترل‌شده باشد. معمولاً این حالت باید خطا بدهد، چون یک Key واحد نباید برای دو عملیات متفاوت استفاده شود.

سناریوی اصلی 3: نبودن Idempotency-Key در APIای که آن را لازم دارد

اگر API طبق Contract برای عملیات حساس به Idempotency-Key نیاز دارد، نبودن آن باید رفتار مشخصی داشته باشد.

سناریوی اصلی 4: retry بعد از timeout

حتی اگر دستی timeout را شبیه‌سازی نکنی، باید سناریوی منطقی‌اش را در نظر بگیری:

  • آیا درخواست دوم باعث double processing می‌شود یا نه؟

سناریوی اصلی 5: بررسی دیتابیس

برای تست Idempotency فقط Status Code کافی نیست. باید در Database هم چک کنی:

  • فقط یک رکورد ساخته شده؟

  • فقط یک تراکنش ثبت شده؟

  • فقط یک سند/لاگ/مرجع بیزینسی ساخته شده؟


چه چیزهایی را در Response باید تحلیل کنی؟

در تست Idempotency باید این‌ها را نگاه کنی:

  • Status Code

  • Response Body

  • Reference Number / Transaction Id

  • DB state

  • Logs / audit trail اگر دسترسی داری

مثلاً اگر بار اول transactionId=TX1001 ساخته شد، درخواست دوم با همان Idempotency-Key نباید TX1002 بسازد.


Idempotency و Status Code

اینجا یک پاسخ ثابت جهانی وجود ندارد؛ بستگی به Contract دارد.
اما معمولاً این حالت‌ها را می‌بینی:

بار اول

  • 200 OK

  • 201 Created

بار دوم با همان Request و همان Key

ممکن است:

  • همان 200/201 قبلی برگردد

  • یا پاسخ دیگری که نشان دهد request قبلاً پردازش شده

مهم این است که اثر بیزینسی تکرار نشود.


Failure مرتبط با Idempotency چه شکلی است؟

مثلاً اگر:

  • یک POST /transfer با یک Idempotency-Key مشخص ارسال شود

  • دوباره همان Request با همان Key ارسال شود

  • و سیستم دوباره انتقال وجه انجام دهد

این یک Failure است، چون Actual Result با Expected Result برابر نیست.
پشت این Failure معمولاً یکی از این Defectهاست:

  • عدم پیاده‌سازی Idempotency check

  • ذخیره‌نشدن Idempotency-Key

  • race condition در پردازش هم‌زمان

  • ضعف در transaction boundary

  • مشکل در unique constraint یا deduplication logic


ارتباط Idempotency با سرفصل‌های دیگر

با HTTP Methods

باید بدانی کدام methodها ذاتاً idempotent هستند و کدام‌ها نه.

با Headers

چون Idempotency-Key معمولاً در Header می‌آید.

با Status Codes

چون باید رفتار پاسخ در request اول و دوم را تحلیل کنی.

با DB Testing

چون بدون بررسی دیتابیس، تست idempotency ناقص است.

با Concurrency / Distributed Systems

چون تکرار درخواست فقط از سمت کاربر نیست؛ ممکن است از retryهای سیستمی، message redelivery یا timeout هم بیاید.


اهمیت این سرفصل برای Backend Tester

Backend Tester باید بتواند:

  • تشخیص دهد کدام APIها نیاز جدی به Idempotency دارند

  • برای عملیات مالی، create و transaction-based سناریوی تکرار Request طراحی کند

  • تفاوت duplicate validation و idempotency را بداند

  • هم Response و هم Database state را بررسی کند

  • Idempotency-Key، retry، timeout و concurrency risk را در تحلیل تست لحاظ کند


نکته امتحانی مهم

در پاسخ امتحانی فقط نگویید:

Idempotency یعنی درخواست تکراری دوباره اثر نگذارد.

این تعریف ناقص است. پاسخ خوب باید این کلیدواژه‌ها را داشته باشد:
same request, same effect, retry, duplicate processing, Idempotency-Key, POST operations, financial transactions, double execution, database verification, concurrency risk


نمونه پاسخ کامل کوتاه

Idempotency یعنی اگر یک Request یکسان چند بار به API ارسال شود، اثر نهایی آن روی سیستم معادل اجرای یک‌بار همان Request باشد و تکرار درخواست باعث ایجاد داده‌ی تکراری، تراکنش تکراری یا تغییر وضعیت ناخواسته نشود. این مفهوم در APIهای مالی، پرداخت، انتقال وجه و عملیات POST بسیار مهم است، چون ممکن است به دلیل timeout یا retry یک درخواست دوباره ارسال شود. برای پیاده‌سازی آن معمولاً از Idempotency-Key در Header استفاده می‌شود تا Server تشخیص دهد Request قبلاً پردازش شده است. در تست Idempotency باید علاوه بر Status Code، Response Body و Database state هم بررسی شود تا مطمئن شویم عملیات دوباره اجرا نشده است.


کلیدواژه‌ها

Idempotency Idempotent Operation Non-Idempotent Operation Retry Duplicate Processing Double Execution Idempotency-Key POST PUT DELETE GET Timeout Network Retry Request Replay Duplicate Request Database Verification Unique Constraint Deduplication Concurrency Race Condition Transaction Financial Operation


Idempotency (ویژگی‌ای که باعث می‌شود تکرار یک Request یکسان اثر بیزینسی جدید ایجاد نکند): برای جلوگیری از پردازش تکراری در APIهای حساس استفاده می‌شود.

Idempotent Operation (عملیاتی که اجرای چندباره‌ی آن با ورودی یکسان، نتیجه نهایی یکسان دارد): در تحلیل رفتار GET، PUT و DELETE اهمیت دارد.

Non-Idempotent Operation (عملیاتی که تکرار آن اثر جدید ایجاد می‌کند): در POSTهای مالی، create و transaction-based زیاد دیده می‌شود.

Retry (ارسال مجدد Request بعد از timeout، failure یا عدم دریافت پاسخ): یکی از مهم‌ترین دلایل نیاز به Idempotency است.

Duplicate Processing (پردازش تکراری یک عملیات واحد): در سیستم‌های مالی و ثبت اطلاعات ریسک جدی ایجاد می‌کند.

Double Execution (اجرای دوباره‌ی یک عملیات به‌جای تشخیص تکراری بودن آن): نشانه‌ی failure در Idempotency است.

Idempotency-Key (شناسه یکتایی که همراه Request ارسال می‌شود تا Server بتواند درخواست تکراری را تشخیص دهد): رایج‌ترین روش پیاده‌سازی Idempotency در POSTهای حساس است.

POST (متدی که معمولاً به‌طور پیش‌فرض idempotent نیست): برای عملیات create و business action نیاز بیشتری به Idempotency دارد.

PUT (متدی که معمولاً idempotent در نظر گرفته می‌شود): تکرار همان درخواست نباید state نهایی را تغییر دهد.

DELETE (متدی که از نظر مفهومی idempotent است): حذف دوباره نباید اثر بیزینسی جدید ایجاد کند.

GET (متد خواندن داده که نباید state سیستم را تغییر دهد): به‌طور طبیعی باید idempotent باشد.

Timeout (عدم دریافت پاسخ در زمان مشخص): یکی از علت‌های رایج retry و تکرار Request است.

Network Retry (ارسال مجدد درخواست به دلیل اختلال شبکه یا timeout): سناریوی کلیدی برای تست Idempotency است.

Request Replay (ارسال مجدد همان Request قبلی): اگر کنترل نشود می‌تواند منجر به duplicate transaction شود.

Duplicate Request (درخواست تکراری با همان محتوا یا همان intent بیزینسی): در طراحی تست Idempotency باید بررسی شود.

Database Verification (بررسی دیتابیس برای اطمینان از عدم ثبت رکورد یا تراکنش تکراری): بخش ضروری تست Idempotency است.

Unique Constraint (قید یکتایی در دیتابیس): یکی از لایه‌های کمکی برای جلوگیری از داده‌ی تکراری است، ولی جایگزین کامل Idempotency نیست.

Deduplication (منطق تشخیص و حذف درخواست یا پیام تکراری): در معماری API و سیستم‌های توزیع‌شده برای جلوگیری از duplicate processing استفاده می‌شود.

Concurrency (پردازش هم‌زمان چند درخواست): در سناریوهای تکرار هم‌زمان Request می‌تواند باعث شکستن Idempotency شود.

Race Condition (شرایط رقابتی در پردازش هم‌زمان): یکی از دلایل فنی failure در پیاده‌سازی Idempotency است.

Transaction (واحد عملیاتی بیزینسی یا دیتابیسی): در انتقال وجه، پرداخت و عملیات حساس باید در برابر duplicate execution محافظت شود.

Financial Operation (عملیات مالی مثل پرداخت یا انتقال وجه): مهم‌ترین حوزه‌ی کاربرد Idempotency به دلیل ریسک بالای تکرار عملیات است.


Request Replay (ارسال مجدد همان درخواست قبلی): در سناریوهای timeout، retry و تست Idempotency برای تشخیص پردازش تکراری استفاده می‌شود.

Replay Result (برگرداندن نتیجه‌ی قبلی به درخواست تکراری به‌جای اجرای مجدد عملیات): در رفتار صحیح APIهای idempotent به‌کار می‌رود.

Duplicate Processing (پردازش دوباره‌ی یک عملیات واحد): ریسک اصلی در انتقال وجه، پرداخت و ثبت تراکنش است.

Request Fingerprint (نمایه/اثر انگشت منطقی یک درخواست شامل payload یا فیلدهای مهم آن): برای مقایسه‌ی same key + same body در برابر same key + different body استفاده می‌شود.

Atomic Check-and-Save (بررسی و ثبت یک داده در یک عملیات اتمیک و غیرقابل‌تفکیک): در پیاده‌سازی امن Idempotency-Key برای جلوگیری از race condition حیاتی است.

Idempotency Store (محل ذخیره‌سازی mapping بین Idempotency-Key و نتیجه/تراکنش قبلی): در تحلیل معماری و RCA مربوط به replay و duplicate transaction کاربرد دارد.

Transaction Reference / Reference Number (شناسه‌ی بیزینسی یا بانکی یک تراکنش): در تست idempotency باید چک شود که در replay همان reference قبلی برگردد، نه reference جدید.

Ledger Entry (رکورد حسابداری بدهکار/بستانکار مرتبط با تراکنش): در تست بانکی برای اطمینان از اینکه فقط یک debit و یک credit ثبت شده استفاده می‌شود.

Contract Enforcement (اعمال دقیق قواعد تعریف‌شده در contract API): برای سناریوهایی مثل same idempotency key + different body یا missing required header مهم است.

Business Intent (قصد بیزینسی واقعی یک درخواست، مثل یک انتقال وجه مشخص): در Idempotency مهم است چون سیستم باید تشخیص دهد replay همان intent قبلی است یا یک عملیات جدید.

مالی پرداختapi
۲
۰
Nastooh
Nastooh
شاید از این پست‌ها خوشتان بیاید