Menu
CoddyTech

Lỗi xác thực JSON

Thuộc phần API JSON trong hành trình Django của Coddy. Bài học 7 trên 19.

Hiện tại, một yêu cầu POST không có tiêu đề sẽ gây ra KeyError, và Django phản hồi bằng 500 Server Error, khiến chương trình không biết cần sửa lỗi gì.

Khi dữ liệu có vấn đề, hãy phản hồi bằng 400 Bad Request và cho biết lỗi trong JSON, mỗi trường một thông báo, giống như cách biểu mẫu Django lưu các lỗi. Ví dụ, hiệu sách kiểm tra năm xuất bản của một cuốn sách:

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)

Vẫn còn hai tình huống dễ mắc lỗi. Tiêu đề chỉ gồm dấu cách không phải là chuỗi rỗng, nhưng " ".strip() là "". Phần nội dung không phải JSON sẽ khiến json.loads phát sinh json.JSONDecodeError. Hãy dùng try và except để bắt lỗi này, rồi phản hồi bằng mã 400 thay vì làm chương trình bị lỗi.

challenge icon

Thử thách

Trung bình

Yêu cầu POST /api/tasks/ từ chối dữ liệu không hợp lệ và trả về trạng thái 400.

  1. Trong task_list, bắt json.JSONDecodeError quanh json.loads và phản hồi bằng {"error": "The body is not valid JSON."}.
  2. Nếu tiêu đề bị thiếu hoặc để trống sau khi loại bỏ khoảng trắng, không lưu gì và phản hồi bằng {"errors": {"title": "This field is required."}}.
  3. Nếu không, hãy tạo mục đó bằng tiêu đề đã loại bỏ khoảng trắng.

Trong thẻ Shell, dòng bên dưới in ra This field is required.

from django.test import Client; print(Client().post("/api/tasks/", {"title": "  "}, content_type="application/json").json())

Tự làm thử

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))

Tất cả bài học trong API JSON

Tự luyện tập: Playground Django