Menu
CoddyTech

أخطاء التحقق من JSON

جزء من قسم واجهات API بصيغة JSON في رحلة Django على Coddy. الدرس 7 من 19.

حاليًا، يؤدي إرسال طلب POST من دون عنوان إلى حدوث خطأ KeyError، ويجيب Django بخطأ خطأ الخادم 500، وهذا لا يخبر البرنامج بما يجب إصلاحه.

عندما تكون البيانات هي المشكلة، أجب بـ طلب غير صالح 400 ووضّح الخطأ بتنسيق JSON، برسالة واحدة لكل حقل، كما يحتفظ نموذج Django بأخطائه. مثال لمتجر كتب يتحقق من سنة نشر كتاب:

errors = {}
year = data.get("year")
if not isinstance(year, int) or year < 0:
    errors["year"] = "Enter the year as a whole number."
if errors:
    return JsonResponse({"errors": errors}, status=400)

ما زال هناك فخّان. العنوان الذي يتكوّن من مسافات فقط ليس فارغًا، لكن " ".strip() نتيجته "". كما أن الجسم الذي لا يحتوي على JSON يجعل json.loads يرفع الاستثناء json.JSONDecodeError، ويحوّل try وexcept ذلك إلى استجابة 400. تعني حالة 4xx أن المستدعي أرسل شيئًا غير صحيح؛ أما حالة 5xx فتعني أن في شفرتك خطأ.

challenge icon

التحدي

متوسط

اجعل POST /api/tasks/ يعيد 400 عند وجود بيانات غير صالحة:

  • عدم وجود عنوان، أو وجود مسافات فقط: {"errors": {"title": "This field is required."}}، وألا يُحفَظ أي شيء.
  • أن يكون المحتوى ليس بصيغة JSON: {"error": "The body is not valid JSON."}.
  • يُحفَظ العنوان الصحيح من دون المسافات المحيطة به.

اضغط على Run، ثم في علامة تبويب Shell: from django.test import Client; print(Client().post("/api/tasks/", {"title": " "}, content_type="application/json").json())

جرّب بنفسك

import json

from django.http import JsonResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt

from .models import Task


def task_to_dict(task):
    return {
        "id": task.id,
        "title": task.title,
        "done": task.done,
        "priority": task.priority,
    }


def home(request):
    return render(request, "tasks/home.html", {"tasks": Task.objects.all()})


def stats(request):
    data = {
        "total": Task.objects.count(),
        "done": Task.objects.filter(done=True).count(),
    }
    return JsonResponse(data)


@csrf_exempt
def task_list(request):
    if request.method == "POST":
        data = json.loads(request.body)
        task = Task.objects.create(
            title=data["title"],
            priority=data.get("priority", "normal"),
        )
        return JsonResponse(task_to_dict(task), status=201)
    tasks = Task.objects.all()
    done = request.GET.get("done")
    if done == "true":
        tasks = tasks.filter(done=True)
    elif done == "false":
        tasks = tasks.filter(done=False)
    return JsonResponse([task_to_dict(task) for task in tasks], safe=False)


def task_detail(request, pk):
    task = Task.objects.filter(pk=pk).first()
    if task is None:
        return JsonResponse({"error": "Task not found"}, status=404)
    return JsonResponse(task_to_dict(task))

جميع دروس واجهات API بصيغة JSON

تدرّب بنفسك: Playground لـ Django