চমৎকার! আপনি এখন কোর্সের Lecture 362: ProblemDetails-এ আছেন। এতোদিন আমরা Error হলে শুধু BadRequest() বা NotFound() রিটার্ন করতাম। কিন্তু আজ আমরা শিখবো প্রফেশনাল লেভেলে কীভাবে একটি স্ট্যান্ডার্ড এবং সুন্দর স্ট্রাকচারড Error ক্লায়েন্টকে (যেমন: Angular বা React) পাঠাতে হয়। এটি API ডেভেলপমেন্টের একটি অত্যন্ত গুরুত্বপূর্ণ অংশ।
চলুন শুরু করা যাক!
📝 Lecture Summary
ভবিষ্যতে দ্রুত রিভিশন দেওয়ার জন্য পুরো লেকচারের মূল বিষয়গুলো নিচে তালিকাভুক্ত করা হলো:
- Preferred Error Method:
BadRequest()-এর বদলেProblem()মেথড ব্যবহার করা মাইক্রোসফটের রেকমেন্ডেশন। - ProblemDetails Class:
Problem()মেথড কল করলে এটি ইন্টারনালিProblemDetailsঅবজেক্ট তৈরি করে, যা JSON ফরম্যাটে ক্লায়েন্টের কাছে যায়। - Standard Properties: এই JSON অবজেক্টে Type, Title, Status, Detail এবং TraceID প্রপার্টি থাকে (IETF স্ট্যান্ডার্ড অনুযায়ী)।
- ValidationProblem: শুধুমাত্র Model Validation Error-এর জন্য
ValidationProblemDetailsক্লাস ব্যবহার করা হয়, যেখানে অতিরিক্ত একটিerrorsপ্রপার্টি থাকে। - Automatic Validation:
[ApiController]অ্যাট্রিবিউটটি ব্যাকগ্রাউন্ডে স্বয়ংক্রিয়ভাবে Model Validation করে এবং ভুল পেলে নিজে থেকেইValidationProblemDetailsরিটার্ন করে। - Frontend Benefit: একটি নির্দিষ্ট স্ট্রাকচার থাকার কারণে Frontend ডেভেলপারদের (Angular/React) Error মেসেজ পার্স করা অনেক সহজ হয়।
🧠 Comprehensive Breakdown
নিচে লেকচারের প্রতিটি কনসেপ্ট বিস্তারিত এবং সহজভাবে ব্যাখ্যা করা হলো।
১. Web API-তে Error Reporting: Problem() (Importance: 10/10)
যখন ক্লায়েন্ট কোনো ভুল ডেটা পাঠায় (যেমন: ডাটাবেজে নেই এমন একটি CityID), তখন তাকে শুধু 400 Bad Request পাঠানো প্রফেশনাল নয়। এর বদলে ControllerBase ক্লাসের Problem() মেথডটি ব্যবহার করা উচিত।
Why? Problem() মেথডটি ক্লায়েন্টকে একটি বিস্তারিত Error অবজেক্ট পাঠায়। আপনি এতে Detail, StatusCode এবং Title প্যারামিটার হিসেবে পাস করতে পারেন।
২. Inside the ProblemDetails Object (Importance: 9/10)
আপনি যখন Problem() রিটার্ন করেন, তখন এটি ইন্টারনালি ProblemDetails ক্লাসের একটি অবজেক্ট তৈরি করে এবং সেটিকে JSON-এ কনভার্ট করে। এই JSON-এ নিচের প্রপার্টিগুলো থাকে:
- type: এটি একটি স্ট্যান্ডার্ডাইজড নাম বা লিংক (IETF রেকমেন্ডেড) যা Error-এর ধরন বোঝায়।
- title: Error-এর একটি সংক্ষিপ্ত নাম (যেমন: “CitySearch”)।
- status: HTTP Status Code (যেমন: 400 বা 500)।
- detail: Error-এর বিস্তারিত বিবরণ (যেমন: “InvalidCityID”)।
- traceId: এটি অটোমেটিক জেনারেট হয়। সার্ভারে হাজার হাজার রিকোয়েস্টের মধ্যে ঠিক কোন রিকোয়েস্টে Error হয়েছিল, তা ট্র্যাক করার জন্য এটি ব্যবহৃত হয়।
৩. ValidationProblemDetails for Model Validation (Importance: 10/10)
ProblemDetails ব্যবহার করা হয় সাধারণ Error-এর জন্য। কিন্তু Model Binding-এর সময় যদি কোনো Validation Error হয় (যেমন: কোনো Required ফিল্ড ফাঁকা থাকলে), তখন ValidationProblemDetails ক্লাস কাজ করে। এটি ProblemDetails থেকেই ইনহেরিট করা।
The Extra errors Property:
এর সবচেয়ে বড় বৈশিষ্ট্য হলো এতে errors নামের একটি অতিরিক্ত Array থাকে। যদি ইউজার একাধিক ভুল করে (যেমন: CityName ফাঁকা এবং CityID ভুল ফরম্যাটে), তবে সবগুলো Error মেসেজ এই Array-তে সুন্দরভাবে লিস্ট করা থাকে।
🖥️ CLI Commands for VS Code: ভিডিওতে Entity Framework-এ Model আপডেট করার জন্য Package Manager Console ব্যবহার করা হয়েছে। আপনি VS Code বা Terminal ব্যবহার করলে নিচের কমান্ডগুলো দেবেন:
Migration অ্যাড করতে:
dotnet ef migrations add CityNameRequiredDatabase আপডেট করতে:
dotnet ef database update
৪. The Magic of [ApiController] (Importance: 10/10)
আপনাকে Model Validation-এর জন্য ম্যানুয়ালি কোনো কোড লিখতে হবে না।
Why? Controller-এর ওপরে [ApiController] থাকলে, এটি স্বয়ংক্রিয়ভাবে ModelState চেক করে। যদি কোনো Validation ফেইল করে, তবে এটি ইন্টারনালি return ValidationProblem(ModelState); এক্সিকিউট করে দেয়। ফলে ডেভেলপার হিসেবে আপনার অনেক সময় বেঁচে যায়!
৫. Why this consistent structure is important? (Importance: 8/10)
ধরে নিন, আপনার API-টি একটি Angular বা React অ্যাপ্লিকেশনে ব্যবহৃত হচ্ছে। যদি আপনি বিভিন্ন সময় বিভিন্ন ফরম্যাটে Error পাঠান, তবে Frontend ডেভেলপারের জন্য সেই Error ধরে UI-তে দেখানো খুব কঠিন হবে। কিন্তু ProblemDetails ব্যবহার করলে তারা নিশ্চিত থাকে যে Error মেসেজটি সবসময় response.errors.cityName বা response.detail ফরম্যাটেই আসবে।
💻 Code Implementation (.NET 8/10 Controller Approach)
নিচে Problem() মেথডের কাস্টম ব্যবহার এবং অটোমেটিক ValidationProblem এর একটি সম্পূর্ণ উদাহরণ দেওয়া হলো:
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
namespace CitiesManager.WebApi.Controllers
{
// ১. Model with Validation
public class City
{
public Guid CityID { get; set; }
[Required(ErrorMessage = "City Name cannot be blank")]
public string? CityName { get; set; }
}
[Route("api/[controller]")]
[ApiController]
public class CitiesController : ControllerBase
{
// ২. Automatic ValidationProblem (No extra code needed!)
[HttpPost]
public IActionResult CreateCity(City city)
{
// যদি CityName ফাঁকা থাকে, [ApiController] অটোমেটিক 400 Bad Request
// এবং ValidationProblemDetails JSON রিটার্ন করবে।
// আপনাকে if (!ModelState.IsValid) লিখতে হবে না।
return Ok("City Created!");
}
// ৩. Custom ProblemDetails Return
[HttpGet("{cityId}")]
public IActionResult GetCity(Guid cityId)
{
bool cityExists = false; // ধরি, ডাটাবেজে City পাওয়া যায়নি
if (!cityExists)
{
// BadRequest() এর বদলে Problem() ব্যবহার করা হচ্ছে
return Problem(
detail: "There is no city record with this given City ID.",
statusCode: 400,
title: "CitySearch Failed"
);
}
return Ok("City Data");
}
}
}
🏆 Best Practices for Web API Error Handling
- Use Standard
Problem(): কাস্টম Error মেসেজ পাঠানোর জন্য সবসময়Problem()রিটার্ন করুন। - Let Framework Handle Validations: Model Validation-এর কাজ
[ApiController]-এর ওপর ছেড়ে দিন। ম্যানুয়ালিModelState.IsValidচেক করে কোড বড় করার দরকার নেই। - Don’t Leak Sensitive Info:
Problem()-এরdetailপ্যারামিটারে কখনোই ডাটাবেজের আসল Exception Message বা Stack Trace সরাসরি পাঠাবেন না। এটি হ্যাকারদের জন্য সুবিধাজনক হতে পারে। শুধু ইউজার-ফ্রেন্ডলি মেসেজ দিন।
আপনি কি এখন দেখতে চান কীভাবে একটি Frontend ফ্রেমওয়ার্ক (যেমন: JavaScript বা Angular) থেকে এই ProblemDetails-এর স্ট্রাকচারড Error গুলো রিড করে ইউজারের স্ক্রিনে দেখাতে হয়, নাকি আমরা পরবর্তী Web API টপিকে চলে যাবো?