Kodokon kodokon.com

بناء واجهة JSON برمجية بلغة PHP

ابنِ واجهة JSON برمجية صارمة عبر إتقان الترويسات، وقراءة المتن الخام، والدلالات الدقيقة لرموز الحالة.

9 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

الواجهة البرمجية بصيغة JSON عقد: فكل استجابة تعلن نوعها (Content-Type: application/json)، وتحمل رمز الحالة الصحيح وبنية ثابتة. ولا ترسل PHP أيًّا من هذا افتراضيًا - إذ تعلن text/html. اللبنة الأولى: دالة مساعدة واحدة للاستجابة، نوع إرجاعها never (PHP 8.1 فما فوق). يضمن نوع الإرجاع هذا، للمحرّك ولأدوات التحليل الساكن على حد سواء، أن الدالة لا تعيد التحكّم أبدًا: فأيّ كود يُكتب بعد الاستدعاء يكون - بشكل مُثبَت - غير قابل للوصول.

PHP
<?php
declare(strict_types=1);

function jsonResponse(
    mixed $data,
    int $status = 200
): never {
    http_response_code($status);
    header('Content-Type: application/json');
    echo json_encode(
        $data,
        JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE
    );
    exit;
}

jsonResponse(['status' => 'ok']);
نقطة خروج واحدة: الحالة والترويسة والمتن متّسقة دائمًا.

دقيقة ثانية، كثيرًا ما تُكتشَف بعد فوات الأوان: تبقى $_POST فارغة في مواجهة متن بصيغة JSON. فلا تملؤها PHP إلا في حالتَي application/x-www-form-urlencoded وmultipart/form-data. أما المتن الخام فيُقرأ من الدفق php://input. فُكَّ ترميزه باستخدام JSON_THROW_ON_ERROR: فبدون هذه الراية، تُرجِع json_decode القيمة null بصمت عند حدوث خطأ - وهي لا تُميَّز عن متن يحتوي حرفيًا على null. وبفضل النوع never، لا تحتاج switch أدناه إلى أيّ break على الإطلاق.

PHP
<?php
declare(strict_types=1);

switch ($_SERVER['REQUEST_METHOD']) {
    case 'GET':
        jsonResponse(['items' => []]);
    case 'POST':
        $raw = (string) file_get_contents(
            'php://input'
        );
        try {
            $payload = json_decode(
                $raw,
                true,
                512,
                JSON_THROW_ON_ERROR
            );
        } catch (JsonException) {
            jsonResponse(
                ['error' => 'Malformed JSON'],
                400
            );
        }
        header('Location: /items/42');
        jsonResponse(['created' => $payload], 201);
    default:
        header('Allow: GET, POST');
        jsonResponse(
            ['error' => 'Method not allowed'],
            405
        );
}
يفترض أن jsonResponse مُعرَّفة أعلاه؛ وصيغة catch دون متغير هي من PHP 8.

اختر الرموز بدقّة، لأن عملاءك سيبرمجون اعتمادًا عليها، لا اعتمادًا على رسائلك: 200 قراءة ناجحة، و201 إنشاء (مصحوبة بترويسة Location تشير إلى المورد)، و204 نجاح دون متن، و400 JSON مُشوَّه، و404 مورد غير موجود، و405 طريقة غير مُعالَجة (مع ترويسة Allow تسرد الطرق المسموح بها)، و422 لِـ JSON صحيح نحويًا لكنه غير صحيح دلاليًا. تحقّق من كل ذلك باستخدام curl -i، الذي يعرض الترويسات المُستقبَلة.

BASH
curl -i -X POST http://localhost:8000/items \
  -H 'Content-Type: application/json' \
  -d '{"name":"Widget"}'
يعرض الخيار -i الحالة والترويسات: الاختبار الحقيقي الوحيد للعقد.

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. تتلقّى واجهتك البرمجية طلب POST بمتن بصيغة JSON: لماذا تكون $_POST فارغة؟
    • لا تملأ PHP القيمة $_POST إلا لأجسام form-urlencoded وmultipart؛ أما متن JSON فيُقرأ من php://input
    • يتجاوز JSON الحدّ الافتراضي post_max_size
    • عليك أولًا استدعاء json_decode على $_POST لملئها
  2. أيّ رمز حالة ينبغي أن تُرجِعه بعد إنشاء ناجح عبر POST؟
    • 200
    • 201
    • 204
    • 302
  3. ماذا يضمن نوع الإرجاع never؟
    • أن الدالة تُرجِع null دائمًا
    • أن الدالة لا تعيد التحكّم أبدًا: فهي تنتهي بـ exit أو باستثناء، والمحرّك يتحقق من ذلك
    • أنه لا يمكن لصنف فرعي أن يتجاوز الدالة