HATEOAS ও API ডকুমেন্টেশন (OpenAPI/Swagger)
এই পাঠে যা শিখবেন
- HATEOAS কী এবং কেন এটি "কাঁচা ডেটা API"-র চেয়ে বেশি self-descriptive
- একটি রিসোর্সের অবস্থা অনুযায়ী গণনা-করা
_linksডিকশনারি বাস্তবে যুক্ত করা - দুটো ভিন্ন-অবস্থার রিসোর্সে সঠিকভাবে ভিন্ন লিংক-সেট দেখানো, যাচাইসহ
- OpenAPI/Swagger মেশিন-পাঠযোগ্য ডকুমেন্টেশন হিসেবে কী ভূমিকা রাখে
১ · HATEOAS — লিংকসহ রেসপন্স
একটি সাধারণ (non-HATEOAS) API রেসপন্স শুধু ডেটা ফেরত দেয়:
{"id": 1, "status": "pending", "total": 1200}। ক্লায়েন্টকে তখন আগে থেকেই জানতে হয়
এই অর্ডার বাতিল করতে কোন URL-এ, কোন মেথডে কল করতে হবে — এই তথ্য ক্লায়েন্টের কোডে হার্ডকোড করা থাকে।
HATEOAS এই সমস্যার সমাধান করে: রেসপন্সেই একটি _links অংশ যুক্ত থাকে যা বলে দেয় এই মুহূর্তে
এই রিসোর্সে কী কী কাজ সম্ভব এবং কোন URL/মেথডে — ক্লায়েন্টকে আর URL হার্ডকোড করতে হয় না, শুধু লিংক
অনুসরণ করলেই চলে।
ক্লায়েন্ট নিজে জানে/অনুমান করে যে cancel করতে হলে
POST /orders/1/cancel কল করতে হবে — এই যুক্তি ক্লায়েন্ট কোডে হার্ডকোড করা।রেসপন্সের
_links.cancel.href সরাসরি সঠিক URL বলে দেয় — এবং এই লিংক তখনই থাকে যখন cancel করা বাস্তবিক সম্ভব।২ · অবস্থা অনুযায়ী লিংক গণনা করা
নিচের কোড সেলে attach_links() ফাংশন একটি অর্ডার dict নিয়ে তার status পরীক্ষা করে
নির্ধারণ করে কোন কোন লিংক প্রাসঙ্গিক। pending অর্ডারে বাতিল (cancel) ও আপডেট
(update) সম্ভব, কিন্তু shipped অর্ডারে সেগুলো আর সম্ভব নয় — বরং একটি
ট্র্যাকিং (track) লিংক প্রাসঙ্গিক হয়ে ওঠে।
orders = {
1: {"id": 1, "status": "pending", "total": 1200},
2: {"id": 2, "status": "shipped", "total": 850},
}
def attach_links(order):
"""অর্ডারের বর্তমান অবস্থা দেখে প্রাসঙ্গিক হাইপারলিংক গণনা করে যুক্ত করে"""
base = f"/orders/{order['id']}"
links = {
"self": {"href": base, "method": "GET"},
"items": {"href": f"{base}/items", "method": "GET"},
}
if order["status"] == "pending":
links["cancel"] = {"href": f"{base}/cancel", "method": "POST"}
links["update"] = {"href": base, "method": "PATCH"}
elif order["status"] == "shipped":
links["track"] = {"href": f"{base}/tracking", "method": "GET"}
order_with_links = dict(order)
order_with_links["_links"] = links
return order_with_links
order1 = attach_links(orders[1])
order2 = attach_links(orders[2])
print("== অর্ডার ১ (pending) ==")
print(order1)
print("\n== অর্ডার ২ (shipped) ==")
print(order2)
print("\n== যাচাই ==")
print(f"pending অর্ডারে 'cancel' লিংক আছে: {'cancel' in order1['_links']}")
print(f"shipped অর্ডারে 'cancel' লিংক নেই: {'cancel' not in order2['_links']}")
print(f"shipped অর্ডারে 'track' লিংক আছে: {'track' in order2['_links']}")
print(f"pending অর্ডারে 'track' লিংক নেই: {'track' not in order1['_links']}")
print(f"দুই অর্ডারেই 'self' ও 'items' লিংক আছে: "
f"{all(k in order1['_links'] for k in ('self', 'items')) and all(k in order2['_links'] for k in ('self', 'items'))}")
order1["_links"]-এ চারটি লিংক থাকে — self, items, cancel,
update — কারণ status "pending"। order2["_links"]-এ থাকে
self, items, track — cancel/update নেই,
কারণ একটি শিপড অর্ডার আর বাতিল বা আপডেট করা যায় না। এই লিংক-সেট গণনা করা হয়েছে
order["status"] পরীক্ষা করে — হার্ডকোড করা কোনো ফিক্সড তালিকা নয়।
৩ · OpenAPI/Swagger — মেশিন-পাঠযোগ্য ডকুমেন্টেশন
OpenAPI (আগে Swagger নামে পরিচিত ছিল) একটি স্ট্যান্ডার্ড, YAML বা JSON ফরম্যাটে লেখা স্পেসিফিকেশন যা একটি API-র প্রতিটি endpoint, তার parameter, request body শেপ, এবং সম্ভাব্য response শেপ/status code বর্ণনা করে — মানুষের পড়ার জন্য প্রোজ ডকুমেন্টেশনের বদলে, এটি এমন একটি কাঠামোবদ্ধ ফাইল যা টুল দিয়ে পার্স করা যায়। এই একটি ফাইল থেকে স্বয়ংক্রিয়ভাবে তৈরি করা যায়:
- ইন্টারঅ্যাক্টিভ ডকুমেন্টেশন (Swagger UI) — ব্রাউজারে সরাসরি API টেস্ট করার UI
- ক্লায়েন্ট SDK — বিভিন্ন ভাষার জন্য টাইপ-সচেতন API ক্লায়েন্ট কোড
- রিকোয়েস্ট ভ্যালিডেশন — ইনকামিং রিকোয়েস্ট স্পেসিফিকেশনের সাথে না মিললে আগেভাগেই ধরা
এই পাঠের সুযোগের বাইরে বাস্তব OpenAPI YAML তৈরি করা, কিন্তু মূল ধারণাটি বোঝা জরুরি — HATEOAS রানটাইমে "এই মুহূর্তে কী করা যায়" জানায়, আর OpenAPI ডিজাইন-টাইমে/ডকুমেন্টেশনে "এই API সামগ্রিকভাবে কী কী করতে পারে" জানায় — দুটো ভিন্ন স্তরে একে অপরের পরিপূরক।
HATEOAS মানে প্রতিটি রেসপন্স নিজেই বলে দেয় এই মুহূর্তে কোন কাজ সম্ভব, রিসোর্সের বর্তমান অবস্থা অনুযায়ী গণনা করে — ক্লায়েন্টকে URL হার্ডকোড করতে হয় না। OpenAPI/Swagger এর পরিপূরক একটি ভিন্ন স্তরের টুল — পুরো API-র কাঠামো ডিজাইন-টাইমে বর্ণনা করে মেশিন-পাঠযোগ্যভাবে, যাতে ডকুমেন্টেশন, SDK ও ভ্যালিডেশন স্বয়ংক্রিয়ভাবে তৈরি করা যায়। M6-এর পাঁচটি পাঠ (L23-L27) একসাথে একটি সম্পূর্ণ, ভালোভাবে-ডিজাইন করা REST API-র মূল ভিত্তি তৈরি করল — এবার M7-এ আমরা এই API-র পেছনে থাকা ডেটা ORM দিয়ে কীভাবে মডেল করা হয় তা শিখব।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
একটি অর্ডার যদি "delivered" অবস্থায় থাকে (উপরের কোডে নেই), তাহলে attach_links()-এ সেটি কী কী লিংক পাবে?
বর্তমান কোড অনুযায়ী "delivered" স্ট্যাটাসের জন্য if/elif-এর
কোনো শাখা মেলে না (শুধু "pending" ও "shipped" পরীক্ষা করা হয়েছে), তাই
সেই অর্ডার শুধু ডিফল্ট লিংক দুটো পাবে — self ও items, কোনো action-লিংক
(cancel/update/track) ছাড়াই। বাস্তব সিস্টেমে সাধারণত এখানে
আরেকটি elif order["status"] == "delivered": শাখা যোগ করে হয়তো একটি review
বা return (ফেরত পাঠানো) লিংক দেওয়া হতো।
প্র ০২
HATEOAS ব্যবহার করলে ক্লায়েন্ট কোডে কী সুবিধা হয় যদি ভবিষ্যতে সার্ভার /orders/1/cancel URL পাল্টে /orders/1/void করে দেয়?
যদি ক্লায়েন্ট URL হার্ডকোড না করে বরং সবসময় response["_links"]["cancel"]["href"] থেকে
URL নিয়ে কল করে, তাহলে সার্ভার URL পাল্টালেও ক্লায়েন্টের কোনো কোড পরিবর্তন লাগে না — পরের বার
রেসপন্স আসার সাথে সাথেই নতুন href পাওয়া যাবে এবং ক্লায়েন্ট স্বয়ংক্রিয়ভাবে সঠিক নতুন
URL ব্যবহার করবে। এটিই HATEOAS-এর মূল প্রতিশ্রুতি — URL গঠন ক্লায়েন্ট ও সার্ভারের মধ্যে একটি
"চুক্তি" না হয়ে, রানটাইমে আবিষ্কারযোগ্য (discoverable) হয়ে যায়।
প্র ০৩ OpenAPI স্পেসিফিকেশন কি HATEOAS-এর "রিপ্লেসমেন্ট" — একটি থাকলে অন্যটি লাগে না?
না, দুটো ভিন্ন স্তরে কাজ করে। OpenAPI ডিজাইন-টাইম/ডকুমেন্টেশন টুল — এটি বলে "এই API-তে এই endpoint-গুলো থাকতে পারে", কিন্তু এটি জানে না কোনো নির্দিষ্ট মুহূর্তে কোনো নির্দিষ্ট রিসোর্সের জন্য কোন কাজ বাস্তবে সম্ভব। HATEOAS রানটাইম আচরণ — প্রতিটি রেসপন্সে এই মুহূর্তে, এই রিসোর্সের জন্য ঠিক কী সম্ভব তা বলে দেয় (যেমন এই পাঠের pending/shipped উদাহরণ)। বাস্তবে অনেক API দুটোই ব্যবহার করে — OpenAPI দিয়ে সামগ্রিক ডকুমেন্টেশন, আর প্রয়োজনে HATEOAS দিয়ে রানটাইম discoverability।
অনুশীলন
-
চিন্তা করুন: একটি ব্লগ পোস্ট রিসোর্সে (
draftবনামpublishedঅবস্থা) HATEOAS লিংক কীভাবে অবস্থাভেদে ভিন্ন হতে পারে?একটি
draftপোস্টে হয়তোpublishলিংক (POST) এবংeditলিংক (PATCH) থাকবে, কিন্তু একটিpublishedপোস্টেpublishলিংক থাকবে না (এটি ইতিমধ্যে প্রকাশিত), বরং হয়তোunpublishবাviewলিংক থাকবে — ঠিক যেমন এই পাঠে pending অর্ডারেcancelছিল কিন্তু shipped অর্ডারে ছিল না। -
পরীক্ষা করুন: উপরের কোড সেলে
orders-এ একটি তৃতীয় অর্ডার3: {"id": 3, "status": "cancelled", "total": 500}যোগ করুন, তারপরattach_links(orders[3])কল করে দেখুন এটি কোন কোন লিংক পায়।যেহেতু
"cancelled"status-এর জন্য কোনোif/elifশাখা মেলে না, এই অর্ডারও শুধু ডিফল্টselfওitemsলিংক পাবে —cancel,update, বাtrackকোনোটিই না, যা যুক্তিসঙ্গত (ইতিমধ্যে বাতিল হওয়া অর্ডার আবার বাতিল বা আপডেট করা যায় না)।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৮টি পাঠ আর্কিটেকচার প্যাটার্ন, ফ্রন্ট-এন্ড/ব্যাক-এন্ড ফ্রেমওয়ার্ক ফান্ডামেন্টাল, স্টেট ম্যানেজমেন্ট, REST API, ORM, অথেন্টিকেশন, রেন্ডারিং স্ট্র্যাটেজি ও ডিপ্লয়মেন্ট — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
- পূর্ববর্তী পাঠ: API ভার্সনিং স্ট্র্যাটেজি L26 ভার্সনিং ও HATEOAS দুটোই backward compatibility ও discoverability-কে কেন্দ্র করে — একসাথে একটি টেকসই REST API ডিজাইনের ভিত্তি তৈরি করে।
- Database Management Systems কোর্স সহোদর কোর্স M7-এ শুরু হওয়া ORM ও ডেটাবেস ইন্টিগ্রেশনের SQL ভিত্তি সেই কোর্সে তৈরি হয়েছে।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Programming Languages & Compiler Design, Software Engineering & Git, Theory of Computation, Engineering Economics ও Full-Stack Web Frameworks — সব এক জায়গায়।