Anophel-آنوفل کلاس های Response در لاراول

کلاس های Response در لاراول

تاریخ انتشار:
Laravel
زمان مطالعه: 6 دقیقه

پاسخ دادن (Responding ) از برنامه لاراول شما چیزی است که من آن را حیاتی می دانم ، به خصوص وقتی که در حال ساخت یک API هستیم. بیایید نگاهی بیندازیم که چگونه می

توانیم response های خود را تقویت کنیم.

 

بسیاری از ما معمولاً با استفاده از توابع کمکی(helper functions) در برنامه های خود استفاده می کنیم، زیرا داکیومنت ها و بسیاری از آموزش ها از آنها استفاده می کنند. شروع کردن با آنها آسان است و دقیقاً همان کاری را انجام می دهند که از آنها انتظار داریم.

بیایید نگاهی بیندازیم که اینها چگونه هستند:

 

return response()->json(
   data: [],
   status: 200,
);

 

این مثال کمی اغراق آمیز می باشد. معمولاً داده ها را از این طریق ارسال می کنیم و از کد وضعیت رد می شوید. با این حال، برای من نیز عادت ها سخت می میرند!

 

این کد یک JsonResponse جدید برای شما ایجاد می کند و داده ها و کد وضعیت را برای شما ارسال می کند که آماده بازگشت هستند. کد های بالا کار می کنند و هیچ مشکلی در استفاده از این روش وجود ندارد. اگر قبلاً از آن استفاده می کردید، یک راه برای تقویت API خود در اینجا این می باشد  که کد وضعیت را اضافه کنید تا توضیح بیشتری از آنچه برمی‌گردانید داشته باشید.

 

با حرکت به جلو، می‌توانیم از توابع کمکی صرف نظر کنیم و از کلاسی که توابع کمکی ایجاد می‌کنند استفاده کنیم:

 

return new JsonResponse(
   data: [],
   status: 200,
);

 

من این رویکرد را دوست دارم زیرا کمتر به توابع کمکی متکی است و بیشتر اظهاری است. با نگاه کردن به کدهای بالا، دقیقاً می‌دانید که چه چیزی برگشت داده می‌شود، زیرا به جای اینکه پشت یک تابع کمکی Abstraction شود، درست در مقابل شما قرار دارد. می‌توانید با استفاده از یک روش ثابت یا یک روش دیگر برای اعلام کد وضعیت ، سطح آن را افزایش دهید - خواندن و درک آن را برای توسعه‌دهندگانی که ممکن است همه کدهای وضعیت را نمی دانند، در دسترس قرار دهید. بیایید ببینیم که ممکن است چگونه به نظر می رسد:

 

return new JsonResponse(
   data: [],
   status: JsonResponse::HTTP_OK,
);

 

کلاس JsonResponse کلاس Symfony Response را از طریق چند لایه abstraction گسترش می دهد تا بتوانید مستقیماً آن را فراخوانی کنید - با این حال، تحلیلگر استاتیکی(static analyzer) شما ممکن است در این مورد شکایت کند.

 

شخصی یک پکیج به نام juststeveking/http-status-code ساخته است،که یک PHP Enum که یک چیزی مشابه را برمی گرداند، و تنها وظیفه آن بازگرداندن کدهای وضعیت است. من این رویکرد کاربردی و سبک‌تر را به مواردی مانند این ترجیح می‌دهم، زیرا شما می‌دانید دقیقاً چه اتفاقی می‌افتد و این کلاس یا پکیج چه کاری ممکن است انجام دهد. گاهی اوقات مشکل این است که کلاسی که از آن استفاده می‌کنید آنقدر کار می‌کند که باید این چیز بزرگ را در حافظه بارگذاری کنید تا بتوانید یک مقدار صحیح را برگردانید. این چندان منطقی نیست، بنابراین توصیه می‌کنم از یک پکیج یا کلاس اختصاصی برای مدیریت خودتان استفاده کنید. بیایید ببینیم وقتی این کار را انجام می دهید چگونه به نظر می رسد:

 

return new JsonResponse(
   data: [],
   status: Http::OK->value,
);

 

این یک گام مهم رو به جلو از نظر وضوح کد ما است. خواندن و درک اینکه دقیقاً چه اتفاقی می افتد آسان است. با این حال، ما متوجه می شویم که هر چند وقت یکبار همان بلوک کد را ایجاد می کنیم، بنابراین چگونه می توانیم این مشکل را حل کنیم؟

 

پاسخ این سوال کاملاً ساده است : Response classes. در لاراول، قراردادی وجود دارد که می‌توانیم از آن به نام Responsable استفاده کنیم که به ما می‌گوید کلاس ما باید یک متد toResponse روی آن داشته باشد. ما می‌توانیم این را مستقیماً از کنترلرهای خود برگردانیم، زیرا لاراول این کلاس‌ها را بدون هیچ مشکلی تجزیه و درک می‌کند. بیایید به یک مثال اولیه ساده از شکل ظاهری این کلاس ها نگاه کنیم:

 

class MyJsonResponse implements Responsable
{
   public function __construct(
       public readonly array $data,
       public readonly Http $status = Http::OK,
  ) {}

   public function toResponse($request): Response
   {
       return new JsonResponse(
           data: $this->data,
           status: $this->status->value,
       );
   }
}

 

این چیزی ساده برای استفاده است. با این حال، هیچ ارزشی به برنامه ما اضافه نمی کند. این فقط یک abstraction در اطراف چیزی است که از قبل وجود دارد. بیایید به چیزی نگاه کنیم که ممکن است ارزش بیشتری به برنامه ما بیافزاید.

 

class CollectionResponse implements Responsable
{
   public function __construct(
       public readonly JsonResourceCollection $data,
       public readonly Http $status = Http::OK,
   ) {}

   public function toResponse($request): Response
   {
       return new JsonResponse(
           data: $this->data,
           status: $this->status->value,
       );
   }
}

 

 

اکنون ما یک کلاس response داریم که هر مجموعه منبعی را که از آن عبور می کنیم را مدیریت می کند و آن را برای برنامه ما بسیار قابل استفاده مجدد می کند. بیایید ببینیم چگونه ممکن است این را در کنترلر خود برگردانیم:

 

return new CollectionResponse(
   data: UserResource::collection(
       resource: User::query()->get(),
   ),
);

 

کد های ما اکنون تمیز تر است، کدهای تکراری کمتری دارد و در صورت نیاز به راحتی می‌توان وضعیت پیش‌فرض را نادیده گرفت. این مزیتی را به ما می دهد که متدهای کمکی(helper methods) و کلاس Json Response به ما دادند ، اما زمینه و قابلیت پیش بینی بیشتری را به ما می دهد.

 

با این حال، در حال حاضر با مشکل تکرار کد در یک سری جای دیگر مواجه هستیم. در خود کلاس های response ما. بسیاری از اینها شبیه به هم به نظر می رسند، تنها تفاوت این است که ویژگی های سازنده(constructor ) انواع مختلفی دارند. ما می‌خواهیم زمینه استفاده از کلاس‌های response سفارشی را حفظ کنیم، اما می‌خواهیم از ایجاد چیزی با یک آرگومان گسترده از union-type برای یک ویژگی اجتناب کنیم - زمانی که ممکن است mixed را اضافه کنیم و با آن تمام شود.

 

در این شرایط، می‌توانید به یک کلاس abstract برای گسترش یا یک ویژگی برای اضافه کردن رفتار به کلاس‌هایی که به آن نیاز دارند دسترسی داشته باشید. من ترجیح می دهم که از composition over inheritance استفاده کنم، بنابراین استفاده از یک صفت برای من منطقی تر است.

 

trait SendsResponse
{
   public function toResponse($request): Response
   {
       return new JsonResponse(
           data: $this->data,
           status: $this->status->value,
       );
   }
}

 

بزرگترین مشکل این رویکرد این است که تجزیه و تحلیل استاتیکی از این کد شکایت می کند زیرا این صفت باید ویژگی های کلاس را داشته باشد یا درباره آن بداند. هر چند این یک راه حل آسان است.

 

/**
* @property-read mixed $data
* @property-read Http $status
*/

 

می‌توانیم این بلوک سند را به صفت اضافه کنیم تا از ویژگی‌هایی که به آنها دسترسی دارد آگاه شود.

اکنون کلاس‌های Response ما برای استفاده و ساخت بسیار ساده‌تر خواهند بود، با تکرار کمتر در کد ما.

 

class MessageResponse implements Responsable
{
   use SendsResponse;

   public function __construct(
       public readonly array $data,
       public readonly Http $status = Http::OK,
   ) {}
}

 

اکنون می‌توانیم تمام پاسخ‌های بالقوه‌ای را که باید به راحتی ارسال کنیم، با حفظ ایمنی type و پایین نگه داشتن کدهای تکراری ایجاد کنیم.

 

 

#response #لاراول_response