Menu
CoddyTech

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

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

في الوقت الحالي، يؤدي طلب POST من دون عنوان إلى حدوث KeyError، ويرد Django بالاستجابة 500 Server Error، التي لا تخبر البرنامج بما ينبغي إصلاحه.

عندما تكون البيانات هي المشكلة، أرسل استجابة 400 Bad Request واذكر الخطأ بصيغة 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 بدلًا من حدوث عطل.

challenge icon

التحدي

متوسط

اجعل POST /api/tasks/ يرفض البيانات غير الصالحة برمز الحالة 400.

  1. في task_list، التقط json.JSONDecodeError حول json.loads وأعِد الاستجابة {"error": "The body is not valid JSON."}.
  2. إذا كان العنوان مفقودًا أو فارغًا بعد إزالة المسافات، فلا تحفظ شيئًا وأعِد الاستجابة {"errors": {"title": "This field is required."}}.
  3. وإلا، فأنشئه باستخدام العنوان بعد إزالة المسافات.

في علامة تبويب Shell، يطبع السطر أدناه This field is required.

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