وب مدرن، رابط کاربری و تجربهی وب · فصل ۵ — Error Model، REST، Streaming و Webhook · 50
طراحی REST API: Resource، Command، Idempotency و Pagination
میتواند «REST API Design: Resource, Command, Idempotency, Pagination» را در یک feature محدود طراحی/پیادهسازی کند و correctness، accessibility یا failure behavior مرتبط را اثبات کند.
REST API Design: Resources, Commands, Idempotency and Pagination — en-US
خلاصهٔ درس
میتواند «REST API Design: Resource, Command, Idempotency, Pagination» را در یک feature محدود طراحی/پیادهسازی کند و correctness، accessibility یا failure behavior مرتبط را اثبات کند.
خروجی این درس
میتواند «REST API Design: Resource, Command, Idempotency, Pagination» را در یک feature محدود طراحی/پیادهسازی کند و correctness، accessibility یا failure behavior مرتبط را اثبات کند.
۱. صفحه اول: API تا زمانی خوب به نظر میرسد که Client مجبور به Retry شود
فرض کنید سرویس پردازش Job سه کار ساده دارد: فهرست Jobها را برگرداند، یک Job را نشان دهد و برای Job ناموفق درخواست Retry ثبت کند. دموی اولیه معمولاً بینقص به نظر میرسد. GET /jobs JSON میدهد، GET /jobs/J42 یک رکورد برمیگرداند و POST /jobs/J42/retries هم پاسخ موفق دارد. مشکل وقتی شروع میشود که Client درخواست Retry را ارسال میکند اما قبل از دریافت پاسخ Timeout میشود. Client نمیداند درخواست به Server رسیده یا نه؛ همان درخواست را دوباره میفرستد و دو Retry جدا ساخته میشود. همزمان Client دیگری فهرست را صفحهبهصفحه میخواند؛ بین دو درخواست یک Job جدید به ابتدای فهرست اضافه میشود و نتیجه این است که یک Job دوباره دیده میشود و یک Job دیگر جا میافتد.
این مشکل با «RESTمانندتر» کردن نام URL حل نمیشود. هدف این درس محدودتر و دقیقتر است: قراردادی برای HTTP API بسازیم که در آن هویت Resource، مرز Command، رفتار درخواست تکراری، ادامه Pagination و خطای عمومی آنقدر صریح باشد که بتوان آن را آزمود.
خروجی اصلی شما HTTP API Contract Decision Record v1 است. این رکورد باید بین «چیزی که واقعاً مشاهده شده» و «نتیجهای که از آن مشاهده استنباط میکنیم» فرق بگذارد.
سؤال اصلی این نیست که «آیا این API به اندازه کافی RESTful است؟». سؤال این است: آیا Client میداند state را چگونه آدرسدهی کند، یک side effect را چگونه درخواست کند، بعد از نامشخص ماندن نتیجه درخواست چگونه Retry کند، فهرست را چگونه ادامه دهد و خطا را بدون ساختن تضمین خیالی چگونه تفسیر کند؟
پنج ادعای اصلی درس عبارتاند از: ابتدا Resource identity را روشن کن؛ Command را وقتی لازم است صریح مدل کن؛ Idempotency در semantics روش HTTP را با duplicate suppression کاربردی یکی ندان؛ برای Pagination ترتیب و continuation contract تعریف کن؛ و status code را بهجای کل مدل خطای دامنه استفاده نکن.
۲. مسیر یادگیری: Foundation، Repair و Experienced
در هر سه مسیر، سطح Evidence یکسان میماند.
Foundation. سناریوی Job API را قدمبهقدم پیش ببرید و برای هر operation یک ردیف از Contract Matrix را تکمیل کنید. واژههای کلیدی باید روشن باشند: Resource، Command، Safe Method، Idempotent Method، Idempotency Key، Cursor، Pagination، Problem Details و REST. از حفظ کردن یک الگوی URL پرهیز کنید. ابتدا intent کاربر/Client را بنویسید، سپس تصمیم بگیرید آن intent به state یک Resource اشاره دارد یا از Server اجرای یک Command را میخواهد.
Repair. از همان علامت خرابی شروع کنید. اگر Retry تکراری دو اثر میسازد، روی duplicate suppression تمرکز کنید. اگر بین pageها duplicate یا gap دارید، ترتیب و Cursor را بررسی کنید. اگر چند خطای متفاوت همه با یک 404 و یک متن مبهم برمیگردند، روی error contract کار کنید. فقط یک بعد را repair کنید، probe همان بعد را دوباره اجرا کنید و بعد به ماتریس کامل برگردید.
Experienced. میتوانید توضیح syntax را فشرده کنید، اما تصمیمها حذف نمیشوند. Contract Matrix، probe مربوط به duplicate replay، probe مربوط به insert بین pageها، دفاع از یک trade-off و transfer مستقل الزامی هستند.
قبول شدن implementation بهتنهایی پایان کار نیست. خروجی کامل باید implementation artifact، request/response قابل مشاهده، failure mutation، repair evidence، changed-context transfer و حداقل یک residual limitation داشته باشد.
۳. مدل ذهنی: Intent قبل از شکل Endpoint
پیش از نوشتن route از این زنجیره استفاده کنید:
client intent → resource یا command → HTTP method + URI → repeat semantics → ordering/continuation → response/error → evidence
Resource چیزی است که Client میتواند هویت آن را مشخص کند و درباره state آن فکر کند. Job با شناسه J42 یک Resource است. حتی یک Retry Request نیز اگر lifecycle مستقلی داشته باشد میتواند Resource محسوب شود. Command زمانی مفید است که Client از Server انجام یک action را میخواهد و آن action بهطور طبیعی «جایگزینی representation یک Resource» نیست.
اینها تصمیمهای مدلسازیاند، نه قانون جهانی نامگذاری URL. مثلاً POST /jobs/J42/retries میتواند مرز مناسبی باشد، چون Client ایجاد یک Retry Request برای Job را درخواست میکند. سیستم دیگری ممکن است Retry Request را به شکل Resource مستقل مدل کند. معیار کیفیت این است که identity، side effect، repeat behavior و error روشن باشند؛ وجود فعل یا اسم در path بهتنهایی چیزی را اثبات نمیکند.
لایه بعدی، semantics روش HTTP است. HTTP بین Safe Method و Idempotent Method تمایز دارد. Safe Method برای retrieval در نظر گرفته میشود و نباید برای درخواست side effect استفاده شود. Idempotent Method یعنی اثر موردنظر چند درخواست یکسان معادل اثر یک درخواست باشد؛ این تعریف الزام نمیکند responseها byteبهbyte یکسان باشند. timestamp، header یا metadata میتواند تغییر کند، در حالی که state موردنظر ثابت میماند.
duplicate suppression در سطح application سؤال دیگری را جواب میدهد: وقتی Client مطمئن نیست یک Command اجرا شده یا نه، آیا میتواند همان operation instance را دوباره بفرستد بدون اینکه اثر دوم ساخته شود؟ Idempotency-Key یکی از راههای ممکن است. Contract باید scope کلید، binding آن به operation/input، رفتار replay و conflict را تعریف کند. صرف وجود header هیچ تضمینی نمیدهد.
Pagination هم Contract است، نه صرفاً کنترل UI. ترتیب، boundary و رفتار در برابر تغییرات concurrent باید مشخص باشد. Cursor میتواند برای Client opaque باشد ولی در Server deterministic باشد. اگر ترتیب (createdAt DESC, id DESC) است، Cursor میتواند آخرین tuple دیدهشده را نمایش دهد و page بعد از همان boundary ادامه پیدا کند. اگر Job جدیدی بالاتر از boundary وارد شود، میتوان صریحاً گفت در traversal فعلی backfill نمیشود و Client برای دیدن head جدید باید traversal تازه شروع کند. این یک guarantee محدود اما قابل آزمون است.
۴. لایه پایه: پنج Contract واقعی
۴.۱ Resource Model
ابتدا هویتهای پایدار را بنویسید:
- Collection:
GET /jobs - Item:
GET /jobs/{jobId} - Retry command boundary:
POST /jobs/{jobId}/retries - نمونه state replacement:
PUT /jobs/{jobId}/priority
representation مربوط به collection باید identity لازم برای ادامه کار Client را بدهد، ولی storage داخلی را لو ندهد. endpoint اضافه فقط برای زیباتر شدن routing نسازید.
۴.۲ Command Boundary
Retry یک side effect است. قرار دادن آن پشت GET /jobs/J42/retry semantics عمومی Method را خراب میکند، چون GET باید بهعنوان retrieval قابل اتکا باشد. برای intentی که effect میسازد از method غیر-safe استفاده کنید. شکل دقیق URI همچنان یک design decision است.
۴.۳ Idempotency و Duplicate Suppression
در lab، Retry Command به Idempotency-Key نیاز دارد. Server کلید را در scope همان operation و همان Job نگه میدارد. درخواست اول یک Retry Request میسازد و نتیجه را زیر آن کلید ذخیره میکند. replay با همان key و همان target همان logical retry را برمیگرداند و اثر جدید نمیسازد. استفاده از همان key برای target متفاوت conflict است.
این Contract نمیگوید هر POST الزاماً non-idempotent است یا هر API باید Idempotency Key داشته باشد. فقط برای operationای که uncertainty شبکه میتواند duplicate side effect بسازد، یک رفتار روشن تعریف میکنیم.
Lab همچنین PUT /jobs/{id}/priority دارد. دو درخواست یکسان که priority=true میخواهند باید در نهایت همان state را نگه دارند، حتی اگر updatedAt در response دوم تغییر کند. معیار، اثر موردنظر است نه برابری بایتها.
۴.۴ Pagination
Offset Pagination همیشه بد نیست؛ برای dataset کوچک یا تقریباً ثابت میتواند مناسب باشد. مشکل وقتی است که داده قبل از offset فعلی تغییر کند و Client انتظار traversal بدون gap/duplicate داشته باشد. Cursor Pagination هم خودکار درست نیست. Cursor با sort key غیرunique یا mutable میتواند همان مشکل را ایجاد کند.
Fixture از total order زیر استفاده میکند: createdAt DESC و سپس id DESC. Cursor آخرین pair دیدهشده را نگه میدارد. Contract میگوید insertهای جدیدتر از boundary در traversal فعلی backfill نمیشوند. برای دیدن آنها traversal جدید شروع میشود. این guarantee کوچکتر از snapshot است، اما روشن و قابل تست است.
۴.۵ Error Contract
Status code معنی پروتکلی دارد، اما Client معمولاً به reason پایدار هم نیاز دارد. Fixture از representation شبیه Problem Details با type، title، status، detail و extension محدود code استفاده میکند. Job ناشناخته و conflict کلید idempotency در یک متن generic حل نمیشوند.
RFC 9457 کل error taxonomy محصول شما را تعیین نمیکند؛ فقط representation استاندارد Problem Details را فراهم میکند. معنی دامنه و میزان اطلاعاتی که امن است نمایش داده شود، مسئولیت API شماست.
۵. توضیح عمیق: Shortcutهای ظاهراً منطقی کجا شکست میخورند
Shortcut اول: «REST یعنی فقط noun در URL»
این نگاه، discipline مدلسازی را به قانون اسمی تبدیل میکند. intent مهمتر است. اگر Retry یک Retry Request جدید میسازد، POST /jobs/J42/retries میتواند کاملاً روشن باشد. یک سیستم دیگر میتواند operation resource جدا داشته باشد. هیچکدام فقط با اسم path اثبات نمیشوند.
Shortcut دوم: «POST non-idempotent است، پس Retry مشکل Client است»
Semantics Method uncertainty توزیعشده را حذف نمیکند. ممکن است Server درخواست را اجرا کرده باشد ولی Client پاسخ را نگرفته باشد. اگر duplicate effect مهم است، application باید contract تکرار را تعریف کند: Idempotency Key، client-generated ID، conditional request یا مکانیزم محدود دیگری. در این درس Idempotency Key انتخاب شده چون Evidence آن قابل مشاهده است.
Shortcut سوم: «Idempotent یعنی Response یکسان»
اگر PUT مقدار priority=true را تنظیم کند، response اول شاید updatedAt=10:00:01 و response دوم 10:00:02 داشته باشد. Response تغییر کرده، اما state نهایی effect دوم انباشته نکرده است. Idempotency را از روی intended effect بسنجید.
Shortcut چهارم: «Cursor همیشه از Offset بهتر است»
Cursor بدون ordering contract ارزشی ندارد. اگر فقط createdAt در Cursor باشد و دو Job timestamp یکسان داشته باشند، یکی ممکن است skip شود. اگر sort key در حین traversal تغییر کند، Item ممکن است از boundary عبور کند. Fixture از pair تغییرناپذیر (createdAt,id) استفاده میکند تا guarantee اعلامشده قابل تست باشد.
Shortcut پنجم: «2xx یعنی side effect دقیقاً یک بار»
Success response فقط چیزی را اثبات میکند که Contract به آن معنا داده و Client واقعاً دریافت کرده است. response گمشده Client را نامطمئن میگذارد. replay token میتواند duplicate creation را در boundary مشخص کاهش دهد، اما این درس exactly-once جهانی در کل سیستم و downstreamها را ادعا نمیکند.
۶. مثال کامل: Contract Matrix برای Job API
| Intent | Boundary | Method / URI | Repeat Contract | Order / Continuation | Failure |
|---|---|---|---|---|---|
| List jobs | Collection Resource | GET /jobs?limit=2&cursor=... | retrieval بدون side effect | (createdAt DESC, id DESC)؛ Cursor opaque؛ insert جدید به traversal قبلی اضافه نمیشود | cursor نامعتبر → problem response |
| Inspect job | Item Resource | GET /jobs/J42 | retrieval | ندارد | id ناشناخته → 404 problem |
| Request retry | Command / retry-request creation | POST /jobs/J42/retries | Idempotency-Key اجباری؛ replay همان logical retry؛ reuse متناقض → conflict | ندارد | key ناقص یا conflict → problem response |
| Set priority | Resource state replacement | PUT /jobs/J42/priority | درخواست یکسان state نهایی یکسان میسازد؛ metadata response میتواند فرق کند | ندارد | id ناشناخته → 404 problem |
Evidence Record فقط کپی این جدول نیست. باید request/response واقعی fixture را ثبت کند و مشخص کند هر observation از کدام claim حمایت میکند. حداقل یک ردیف باید رفتار خراب را قبل از repair نشان دهد.
برای probe مربوط به Pagination، page اول را با دو Job بگیرید و Cursor را ذخیره کنید. سپس Job جدیدی اضافه کنید که در head قرار میگیرد. با Cursor قبلی ادامه دهید. در Contract این Lab، page بعد باید دقیقاً زیر boundary قبلی ادامه دهد: هیچ ID دیدهشدهای دوباره برنگردد و هیچ Job قدیمی زیر boundary بهخاطر insert جدید جا نیفتد. Job تازه در traversal جدید دیده میشود.
برای Retry، همان Command را دو بار با یک Idempotency-Key بفرستید. شناسه Retry Request باید ثابت بماند و side-effect count فقط یک بار زیاد شود. response دوم میتواند metadata مربوط به replay داشته باشد؛ byte equality شرط نیست.
۷. Failure Modeها و Mutationهای عمدی
قبل از اجرای هر Mutation، prediction بنویسید.
- Duplicate replay: lookup کلید را غیرفعال کنید. انتظار: دو درخواست با یک key دو Retry میسازند. Repair: binding و replay نتیجه ذخیرهشده را برگردانید.
- Unstable pagination: keyset را با offset جایگزین کنید. انتظار: insert در head باعث duplicate یا skip میشود. Repair: boundary بر اساس total order را برگردانید.
- Unsafe GET command: اجازه دهید GET عملیات Retry را اجرا کند. انتظار: retrieval request state را تغییر میدهد. Repair: retrieval و Command را جدا کنید.
- Non-idempotent PUT: بهجای set کردن priority، آن را toggle کنید. انتظار: دو درخواست یکسان state را رفت و برگشت میدهند. Repair: desired state را authoritative کنید.
- Weak error contract: conflict را با
200 {error: ...}برگردانید. انتظار: status و public domain reason با Contract سازگار نیستند. Repair: problem representation محدود را بازگردانید.
Mutation فقط برای «قرمز کردن تست» نیست. باید رابطه علت و معلولی بسازد: test به این دلیل fail شود که Contract مشخص شکسته شده و repair همان بعد را بدون ورود به scope Streaming، Webhook یا معماری Framework برگرداند.
۸. پل حرفهای: Guarantee را قبل از Mechanism انتخاب کنید
برای duplicate suppression بپرسید Client تا چه زمانی ممکن است retry کند، key در چه scopeای معتبر است، آیا request fingerprint نگه داشته میشود، reuse متناقض چه میشود و original result چگونه replay میشود. سیستم production احتمالاً persistence و expiration میخواهد. Lab در حافظه است و durability بعد از process restart را اثبات نمیکند.
برای Pagination مشخص کنید traversal زنده میخواهید یا snapshot. Snapshot ممکن است version یا query state نگه دارد. live keyset ارزانتر است اما میتواند صریحاً بگوید insertهای جدید در head تا traversal بعدی دیده نمیشوند. Offset نیز وقتی تغییر داده کم است یا direct page jump مهم است میتواند انتخاب مناسب باشد.
برای Command Modeling بپرسید action هویت و lifecycle مستقلی دارد یا نه. اگر دارد، تبدیل درخواست action به Resource میتواند observability را بهتر کند. اگر intent صرفاً تنظیم state معلوم است، PUT یا PATCH ممکن است طبیعیتر باشد. هدف ساختن pseudo-resource برای رعایت شعار نیست.
۹. Alternativeها و Trade-offها
Client-generated Resource ID در برابر Idempotency Key. اگر Client بتواند identity creation را انتخاب کند، PUT /retry-requests/{clientId} میتواند repeat behavior را از طریق identity روشن کند. Idempotency Key زمانی مفید است که Server ID را میسازد. هر دو collision/conflict policy میخواهند.
Offset در برابر Keyset Cursor. Offset ساده و مناسب page number است. Keyset میتواند traversal ترتیبی را در برابر برخی insertها پایدارتر کند، ولی به order مناسب نیاز دارد و معمولاً random page jump را سخت میکند. انتخاب باید از user journey و data-change pattern بیاید.
Live در برابر Snapshot. برای dashboard ممکن است live traversal کافی باشد. برای export یا audit شاید stable snapshot لازم باشد. Guarantee قویتر معمولاً هزینه state/versioning بیشتری دارد.
Status-only در برابر Problem Details. API داخلی کوچک شاید با status و error body ساده شروع کند. Contract عمومیتر از reason machine-readable سود میبرد. exception داخلی و stack trace نباید به public semantics تبدیل شوند.
۱۰. تمرین هدایتشده و Transfer مستقل
در lab/WEB006-LAB1/learner قبل از تغییر کد، بخش predicted failure فایل evidence/HTTP_API_Contract_Decision_Record_v1.json را تکمیل کنید.
- public structural check را اجرا کنید. ۲. positional cursor و retry handler خراب را پیدا کنید. ۳. Contract Matrix را ابتدا با زبان طبیعی بنویسید. ۴. duplicate suppression مربوط به Retry را repair کنید. ۵. total order را مشخص کنید و Pagination را اصلاح کنید. ۶. اجازه ندهید GET side effect بسازد. ۷. مثال PUT را به شکل state-setting پیادهسازی کنید. ۸. observationها و residual limitation را ثبت کنید.
برای transfer از domain «Media Render Task» استفاده میشود. اسم Resource و Command عوض میشود اما روش ثابت است: Resourceها را مشخص کنید، Command را جدا کنید، repeat behavior را تعریف کنید، continuation فهرست را بنویسید، error عمومی را تعریف کنید، یک failure را پیشبینی و اجرا کنید و Evidence را ثبت کنید. Endpointهای Job را صرفاً کپی نکنید.
در transfer، تصمیم نهایی باید مستقل باشد. AI میتواند بعد از بیان Contract به شما check پیشنهاد کند، اما اجازه ندارد Evidence مشاهدهنشده یا judgment نهایی را بسازد.
۱۱. Verification: Evidence خوب چه شکلی است
Evidence قوی Observation را از Inference جدا میکند.
نمونه Observation:
- «دو Retry با key
demo-7هر دو Retry Request با شناسهR1را نشان دادند و side-effect count برابر ۱ ماند.» - «بعد از insert یک Job جدید بین دو page request، continuation با Cursor قبلی بدون تکرار IDهای page اول ادامه پیدا کرد.»
- «دو PUT یکسان
priority=trueرا حفظ کردند، ولیupdatedAtفرق داشت.»
نمونه Inference:
- «تا زمانی که رکورد key در حافظه وجود دارد، fixture برای همان operation/target duplicate retry creation را suppress میکند.»
- «Order و Cursor انتخابشده برای head-insert آزمایششده boundary traversal را جابهجا نمیکند.»
Residual limitationها باید صریح باشند: state مربوط به Idempotency در memory است؛ رفتار بعد از restart اثبات نشده؛ proxy/TLS/network retry خارج از Lab است؛ guarantee Cursor به immutable pair (createdAt,id) وابسته است؛ و چون fixture API-only است هیچ browser یا assistive-technology evidence ادعا نمیشود.
سبز شدن تست بهتنهایی Evidence نیست. Test زمانی از Claim پشتیبانی میکند که خود boundary Contract را تمرین کند و Mutation نشان دهد تست در برابر یک نقض واقعی حساس است.
۱۲. ارزیابی و Transfer
Retrieval: پنج claim family و یک non-goal را بیان کنید؛ تفاوت Method Idempotency و duplicate suppression را حتماً روشن کنید.
Application: Job API را طوری repair کنید که list/read، Retry Command، repeat behavior، Pagination و error با Decision Record همخوان باشند.
Diagnosis: یک Mutation را پیشبینی، اجرا و تحلیل کنید. توضیح دهید چرا failure از شکستن Contract میآید نه صرفاً از جزئیات تست.
Decision: یک trade-off را دفاع کنید: Idempotency Key در برابر client-generated resource، Offset در برابر Keyset یا Live در برابر Snapshot. ابتدا Guarantee هدف را بیان کنید.
Transfer: سناریوی Media Render Task را مستقل حل کنید. اگر استدلال شما هنوز به اسم Job وابسته است، abstraction هنوز پایدار نشده است.
Failure مسدودکننده زمانی رخ میدهد که Mutation بحرانی تشخیص داده نشود، success ظاهری تنها Evidence باشد، یا راهحل scope درس بعدی را بیصدا جذب کند.
۱۳. منابع، Freshness و مرز Claim
RFC 9110 (S-RFC9110) فقط برای claimهای محدود مربوط به semantics روش HTTP، از جمله safety و idempotency، استفاده میشود. از آن duplicate suppression سطح application نتیجهگیری نمیکنیم.
RFC 9457 (S-RFC9457) فقط برای representation استاندارد Problem Details استفاده میشود. taxonomy کامل خطای دامنه Job Service را تعیین نمیکند.
Research snapshot منجمد در 2026-09-02 دریافت شده و review due آن 2026-10-17 است. در Query 1 source boundary گسترش داده نمیشود. اگر استاندارد cited تغییر کند یا review date برسد، claim متأثر باید از مسیر governed freshness بازبینی شود.
Checklist نهایی Decision Record
رکورد باید این موارد را داشته باشد: Owned Contract؛ Resource/Command Matrix؛ Method و repeat semantics؛ order و Cursor guarantee؛ error shape؛ حداقل یک predicted mutation؛ observed failure؛ repair evidence؛ changed-context transfer مستقل؛ و residual limitation. همچنین باید صریحاً بگوید چه چیزی اثبات نشده است: قانون جهانی برای نامگذاری REST، non-idempotent بودن همیشگی POST، یکسان بودن responseهای درخواست idempotent، برتری همیشگی Cursor Pagination و exactly-once جهانی از روی 2xx.
ارزیابی
پاسخنامهی این درس در بستهی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار میفرستد.
WEB-006-S1 retrieval
پنج Claim Family درس WEB-006 را بیان کنید، Idempotency روش HTTP را از Duplicate Suppression سطح Application جدا کنید و یک Non-goal صریح نام ببرید.
WEB-006-S2 application
Job Fixture را طوری Repair کنید که Resource Identity، Retry Command، Repeat Behavior، Keyset Continuation و Public Errorها با Decision Record شما منطبق باشند.
WEB-006-S3 diagnosis
یک Mutation مربوط به Duplicate Replay، Pagination، Unsafe GET، PUT Effect یا Error Contract را پیشبینی، اجرا، Diagnose و Repair کنید.
WEB-006-S4 decision
یکی از انتخابهای Idempotency Key در برابر Client-generated Request Resource، Offset در برابر Keyset، یا Live Traversal در برابر Snapshot را دفاع کنید و ابتدا Guarantee را مشخص کنید.
WEB-006-S5 transfer
Case مربوط به Media-render Task را مستقل طراحی کنید، بدون کپیکردن نام Endpointها یا نتیجهگیریهای خاص Job Fixture.
ملاکهای ارزیابی (rubric)
Critical dimensions:
- RESOURCE_MODEL — Name stable resource identities and representations before choosing endpoint shapes.
- COMMAND_BOUNDARY — Model side-effecting commands explicitly when they are not naturally a simple resource-state replacement.
- IDEMPOTENCY — Distinguish HTTP method idempotency from application-level duplicate-suppression contracts.
- PAGINATION — Define ordering, continuation token/cursor semantics and behavior under concurrent data changes.
- ERROR_CONTRACT — Bind API errors to public semantics without using status codes as the entire domain model.
Blocking assessments: S2, S3 and S5. S1 and S4 are non-blocking but still require explicit scope discipline. Evidence must distinguish HTTP method semantics from application duplicate-suppression, prove deterministic continuation under the stated ordering contract, and keep public error semantics bounded. Publisher-runtime learner execution remains deferred to the pinned runtime. Internal synthetic oracle results are not represented as publisher-runtime observation. Browser/assistive-technology evidence is not claimed.
منابع و تازگی
مطالعهٔ موارد (case studies)
فایلهای آزمایشگاه
هدف: Contract یک Job API محلی را بدون وابستگی شبکه repair کنید. Starter عمداً در duplicate command replay، pagination مبتنی بر position، side effect در GET، state-setting و error shape خراب است.
- قبل از repair، Contract را بنویسید. ۲.
npm testرا برای سطح مشاهده عمومی اجرا کنید. ۳.src/job-api.mjsرا repair کنید. ۴. Observationها را درevidence/HTTP_API_Contract_Decision_Record_v1.jsonثبت کنید. ۵. Failure Probeها و Transfer مربوط به Media Render را کامل کنید.
Public testها hidden oracle نیستند. از این fixture رفتار شبکه، TLS، proxy، browser یا durability را ادعا نکنید.
رسانه و اسلایدهای درس
فایلهای آموزشی (دانلود)