בפרוייקט חדש, בקובץ program.cs יש לנו את השורה:
app.MapControllers();
כדי שנוכל לגשת ל-controllers, ניגש לתיקיית ה-controllers ונייצר בה controller חדש. נבחר API Controller Empty.
נקרא לקובץ ProductsController.cs.
namespace FirstWebApp.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
}
Controller בא לתת מענה ל-Restful service, שזה אומר שמבצעים בקשות באמצעות get, post, delete, put.
get – לקבל מידע, post – ליצור מידע, להכניס נתונים, put – עדכון מלא, patch – עדכון חלקי, delete – הסרת נתונים.
פונים לאותו ה-Url ועליו מבצעים פעולות שונות.
נגדיר פונקציה פשוטה ב-Controller. את הפונקציה נגדיר כפונקציית get.
[HttpGet]
public string GetString() {
return DateTime.Now.ToLongTimeString();
}
מכיוון שלא הוספנו שום דבר ל-url הפנייה אליו תהיה על ידי:
/api/products
אם נריץ את הפרוייקט נקבל דף swagger. הוא מזהה את ה-url שלנו ואת בקשת ה-get שיש בתוכו.
בגלל שבקובץ ה-program יש את השורה של:
builder.Services.AddSwaggerGen();
יש סריקה של כל ה-controllers והחזרה של הנתונים הרלוונטים.
אם נכתוב ב-url:
https://localhost:7088/api/products
נקבל הדפסה של מה שביקשנו, את השעה הנוכחית.
אפשר להעביר פרמטרים לפונקציה:
public string GetString(string? name, int? number) {
return DateTime.Now.ToLongTimeString();
}
עכשיו אם נריץ את הפרוייקט, ה-swagger יתן לנו את המקום להכניס את הערכים של הפרמטרים האלה. הם אופציונלים כי הם מסומנים עם ?
את הערכים אפשר לקבל עם query string. הם יופיעו ב-url.
'https://localhost:7088/api/Products?name=Keren&number=2023'
שליחת משתנים דרך query string משמשת לקבלת משתנים אופציונלים. כלומר ה-url יעבוד גם אם הם לא יהיו.
לעומת זאת, אם אני אכתוב שאני מצפה לקבל id:
[HttpGet("{id}")]
public string GetString(int id, string? name, int? number) {
return DateTime.Now.ToLongTimeString();
}
עכשיו ה-id יהיה חובה כדי לגשת ל-url. ה-id ישורשר לכתובת ולא יופיע כפרמטר.
'https://localhost:7088/api/Products/34?name=Keren&number=2023'
אחרי שאנחנו מבצעים את בקשת ה-http יש לנו ססטוס קוד שחוזר מהבקשה. כל ה-200 מסמנים הצלחה. משפחת ה-400 מסמנים שגיאה של צד משתמש, כלומר משהו בבקשה של המשתמש לא היה תקין. משפחת ה-500 אלו שגיאות צד שרת, כלומר קישור ל-DB או שגיאות שרת אחרות.
אנחנו רוצים להחזיר את השגיאה עם הפונקציה, ומכיוון שהיא מחזירה כרגע string אי אפשר לעשות את זה. נשנה את ערך ההחזרה של הפונקציה ויש כמה אפשרויות לזה, למשל IActionResult, אבל נשתמש ב-ActionResult שמאפשר גם להחזיר את הערך שבאמת חוזר לי מה-controller.
[HttpGet("{id}")]
public ActionResult<string> GetString(int id, string? name, int? number) {
return DateTime.Now.ToLongTimeString();
}
נשתמש בפונקציה OK כדי להחזיר את הערך התקין שהפונקציה אמורה להחזיר. במקרה של שגיאה נוכל להחזיר אותה, למשל NotFound.
public ActionResult<string> GetString(int id, string? name, int? number) {
if(id > 100) {
return NotFound();
}
return Ok(DateTime.Now.ToLongTimeString());
}
החסרון במה שכתוב פה הוא שהפונקציה חושבת שהיא מחזירה string ואני לא רואה את הסטטוסים שיכולים לחזור. אפשר להכניס את זה להגדרות של הפונקציה.
[HttpGet("{id}")]
[ProducesResponseType(404)]
[ProducesResponseType(200)]
public ActionResult<string> GetString(int id, string? name, int? number) {
if(id > 100) {
return NotFound();
}
return Ok(DateTime.Now.ToLongTimeString());
}
המשמעות של ProducesResponseType היא רק הצהרתית, היא לא עושה כלום בפועל, אבל יש לה משמעות מבחינת תיעוד ומי שעובד עם הפונקציה יכול לראות מה האפשרויות שבה.
עכשיו אפשר לראות ב-swagger את כל מה שיכול לחזור מהפונקציה.