0Pricing
Scala for Backend Engineering & Functional Programming · درس

الطلبات والاستجابات

اقرأ الإدخال وأعد المخرجات

الطلبات والاستجابات درس مجاني في Scala for Backend Engineering & Functional Programming على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Scala for Backend Engineering & Functional Programming، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

الطلب بوصفه قيمة

في http4s، يمثل Request[F] قيمة غير قابلة للتغيير تحمل الطريقة وURI والترويسات وإصدار HTTP وجسمًا متدفقًا. تفحصه باستخدام موصلات نقية، ولا تعدّله في مكانه أبدًا.

ولتغيير طلب، أنشئ نسخة منه عبر withHeaders أو withUri أو موصلات مشابهة.

val r: Request[IO] = Request[IO](
  method = Method.GET,
  uri = uri"/health"
)

الجسم المتدفق

جسم الطلب أو الاستجابة هو fs2.Stream[F, Byte]. ويُستهلك بكسل وتأثير، لذلك لا يلزم أن تبقى الحمولات الكبيرة كاملةً في الذاكرة.

لا تتعامل عادةً مع البايتات الخام؛ إذ تتولى EntityDecoder فك الترميز نيابةً عنك.

// raw access (rarely needed)
val bytes: fs2.Stream[IO, Byte] = request.body

فك ترميز الجسم

تعرف EntityDecoder[F, A] كيفية تحويل تدفق الجسم إلى قيمة A. استدعِ req.as[A] لفك الترميز، إذ يعيد F[A] ويفشل التأثير عند وجود جسم غير صالح.

يتوفر مُفك ترميز مضمّن لـ String، بينما تأتي أدوات فك الترميز الأكثر تخصصًا من وحدات JSON.

HttpRoutes.of[IO] {
  case req @ POST -> Root / "echo" =>
    req.as[String].flatMap(body => Ok(body))
}

ربط الطلب

للوصول إلى كائن الطلب داخل الحالة، اربطه باستخدام @. وهنا يطلق req اسمًا على الطلب بأكمله، مع استمرار النمط في مطابقة الطريقة والمسار.

من دون هذا الرابط، لا تملك إلا الأجزاء المفككة، ولا يمكنك قراءة الجسم أو الترويسات.

HttpRoutes.of[IO] {
  case req @ PUT -> Root / "name" =>
    req.as[String].flatMap(n => Ok(s"set $n"))
}

قراءة الترويسات

توجد الترويسات في request.headers. استخدم headers.get[H] مع نموذج ترويسة معيّن النوع، أو headers.get(CIString("X-Custom")) للأسماء العشوائية.

تحلل الترويسات المعيّنة النوع مثل Authorization وContent-Type قيمها وتتحقق منها نيابةً عنك.

import org.http4s.headers.Authorization

val auth: Option[Authorization] =
  request.headers.get[Authorization]

إنشاء الاستجابات

إن منشئات الاستجابة في DSL، مثل Ok وCreated وNotFound، هي دوال تعيد F[Response[F]]. ويؤدي تمرير وسيط إلى ضبط الجسم عبر EntityEncoder.

يقابل كل منشئ رمز حالة، ولذلك تعيد Created(...) الرمز 201.

Ok("all good")          // 200
Created("made it")      // 201
NotFound("missing")     // 404

رموز الحالة مباشرةً

عند عدم توفر منشئ مريح لحالة ما، أو عند الحاجة إلى تخصيصها، أنشئ Response[F] باستخدام Status صريح، ثم اربط withEntity.

يمنحك ذلك تحكمًا كاملًا في الحالة والترويسات والجسم ضمن تعبير واحد.

import org.http4s.{Response, Status}

Response[IO](Status.Accepted)
  .withEntity("queued")
  .pure[IO]

ترميز الأجسام

تسلسل EntityEncoder[F, A] قيمةً إلى جسم الاستجابة، ويضبط Content-Type. وتتوافر أدوات ترميز String والبايتات مضمّنة، بينما تأتي أدوات ترميز JSON من circe.

عند تمرير قيمة إلى Ok(value)، تبحث http4s ضمنيًا عن أداة الترميز المناسبة.

// String encoder is implicit; sets text/plain
val resp: IO[Response[IO]] = Ok("plain text body")

ضبط ترويسات الاستجابة

أضف الترويسات بتمريرها كوسائط إضافية إلى المنشئ، أو اربط .map(_.putHeaders(...)) بتأثير الاستجابة.

تضمن نماذج الترويسات المعيّنة النوع تنسيق القيم تنسيقًا صحيحًا، مثل ترويسة Location في استجابة 201 Created.

import org.http4s.headers.Location

Created("ok").map(_.putHeaders(
  Location(uri"/items/42")
))

معالجة حالات فشل فك الترميز

يفشل تأثير F الذي يعيده req.as[A] عندما يتعذر فك ترميز الجسم. استخدم req.attemptAs[A].value للحصول على F[Either[DecodeFailure, A]]، وأعد 400 عند وجود قيمة في الطرف الأيسر.

يحافظ ذلك على وضوح معالجة الإدخال غير الصالح واكتمالها.

req.attemptAs[String].value.flatMap {
  case Right(b) => Ok(b)
  case Left(_)  => BadRequest("bad body")
}

ملفات تعريف الارتباط وإعادة التوجيه

اضبط ملفات تعريف الارتباط باستخدام response.addCookie(ResponseCookie(name, value)). ولإعادة التوجيه، استخدم منشئًا من فئة 3xx مع ترويسة Location.

تنفذ SeeOther(Location(uri)) استجابة 303، وهي الاستجابة الاصطلاحية لنمط post-redirect-get.

import org.http4s.headers.Location

SeeOther(Location(uri"/login"))
  .map(_.addCookie("sid", "abc123"))

تحقق سريع

فكّر في فك ترميز الجسم بأمان.

مراجعة

الطلبات والاستجابات قيم غير قابلة للتغيير، وتحتوي على أجسام متدفقة باستخدام fs2. تفكّك الترميز باستخدام as/attemptAs عبر EntityDecoder، وتشفّر باستخدام EntityEncoder.

تضبط البُناة رموز الحالة، وتحافظ الرؤوس ذات الأنواع على الأمان، بينما لا تتجاوز ملفات تعريف الارتباط وإعادات التوجيه كونها تحويلات للاستجابة.

الأسئلة الشائعة

هل درس «الطلبات والاستجابات» مجاني؟

نعم — نص درس «الطلبات والاستجابات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Scala for Backend Engineering & Functional Programming، انتقل إلى CoddyKit PRO. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

ماذا ستتعلم في «الطلبات والاستجابات»؟

اقرأ الإدخال وأعد المخرجات تتمرن على Scala for Backend Engineering & Functional Programming مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Scala for Backend Engineering & Functional Programming؟

لا تُشترط خبرة سابقة. Scala for Backend Engineering & Functional Programming على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «الطلبات والاستجابات»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Scala for Backend Engineering & Functional Programming هذا؟

نعم. كل درس في Scala for Backend Engineering & Functional Programming يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. المسارات وHttpRoutes
  2. الطلبات والاستجابات
  3. نقاط نهاية JSON
  4. تقديم التطبيق
← العودة إلى Scala for Backend Engineering & Functional Programming