Menu
CoddyTech

Erreurs de validation JSON

Fait partie de la section API JSON du Journey Django de Coddy. Leçon 7 sur 19.

Actuellement, une requête POST sans titre provoque une erreur KeyError, et Django répond Erreur serveur 500, ce qui n’indique pas au programme ce qu’il faut corriger.

Lorsque le problème vient des données, répondez 400 Requête incorrecte et indiquez ce qui ne va pas au format JSON, avec un message par champ, comme un formulaire Django conserve ses erreurs. Une librairie qui vérifie l’année d’un livre :

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)

Deux pièges subsistent. Un titre composé uniquement d’espaces n’est pas vide, mais " ".strip() vaut "". Et un corps qui n’est pas au format JSON fait lever à json.loads une exception json.JSONDecodeError, que try et except transforment en réponse 400. Un statut 4xx signifie que l’appelant a envoyé quelque chose d’incorrect ; un statut 5xx signifie que votre code a échoué.

challenge icon

Défi

Moyen

Faites en sorte que POST /api/tasks/ renvoie 400 lorsque les données sont incorrectes :

  • Aucun titre, ou uniquement des espaces : {"errors": {"title": "This field is required."}}, et rien n’est enregistré.
  • Un corps qui n’est pas du JSON : {"error": "The body is not valid JSON."}.
  • Un titre valide est enregistré sans les espaces qui l’entourent.

Appuyez sur Run, puis dans l’onglet Shell : from django.test import Client; print(Client().post("/api/tasks/", {"title": " "}, content_type="application/json").json())

Essayez vous-même

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

Toutes les leçons de API JSON

Entraînez-vous par vous-même : Playground Django