Módulo gratuito 2h

F04 — Sua primeira API com DRF: serializer, viewset, router e status HTTP

Monte o delivery em JSON com Django REST Framework, proteja campos read-only e provoque os códigos 200, 201, 400, 404, 405 e 409.

Em uma frase: Até agora a cozinha servia só no salão (admin); agora montamos o delivery em JSON para qualquer site ou app pedir.
Pergunta guia: Como o catálogo vira um serviço que qualquer tela chama e como a API se defende de pedido ruim?

Slides visuais da lição F04 · NotebookLM

Material multimídia da lição

APIs com Django REST Framework (DRF)

Deck visual cobrindo Serializer, ViewSet, Router e os status HTTP (200, 201, 400, 404, 405, 409).

Slides visuais gerados para fixação. O texto pesquisável e os comandos completos permanecem logo abaixo na lição.

Slides PDF
Passo 1 · Antes de ler: preveja

Tente responder antes de abrir o gabarito

Errar uma previsão mostra exatamente onde está a lacuna. Chute mentalmente ou no papel antes de revelar a resposta do professor.

1. Um cliente envia {'nome': '', 'preco': 'abc'} para criar um produto. O que o servidor responde?

2. Um pedido deve aceitar {'status': 'confirmado'} vindo do navegador na criação?

1. O trio do DRF: Serializer, ViewSet e Router

No Django REST Framework, três peças trabalham juntas: o Serializer (conferente que valida e converte para JSON), o ViewSet (cozinheiro com as ações prontas de listar, criar, detalhar, editar e apagar) e o Router (garçom que gera todas as URLs automaticamente).

Ação de compra com baixa condicional de estoque (views.py)

@action(detail=True, methods=["post"])
def comprar(self, request, pk=None):
    qtd = int(request.data.get("quantidade", 1))
    if qtd <= 0:
        return Response({"erro": "Quantidade deve ser maior que zero."}, status=400)
    atualizados = Produto.objects.filter(
        pk=pk, estoque__gte=qtd
    ).update(estoque=F("estoque") - qtd)
    if atualizados == 0:
        return Response({"erro": "Estoque insuficiente."}, status=409)
    return Response({"ok": True}, status=200)
  • estoque__gte=qtd — A verificação e a subtração acontecem juntas em um único UPDATE no banco
  • status=409 — Conflict: o formato do pedido estava certo (não é 400), mas conflita com o estoque atual
Laboratório · Status HTTP na prática

Provoque cada código de resposta da API (200, 201, 400, 404, 405, 409)

200 OKGET /api/produtos/

Resposta do servidor (Response JSON):

[
  { "id": 1, "nome": "Bolsa Macramê", "preco": "149.90", "estoque": 3 }
]

O que o professor destaca: Consulta bem-sucedida. O servidor entregou a lista em JSON sem alterar nada na despensa.

Quebre de propósito

Remover o filtro estoque__gte=qtd do UPDATE

Experimento: Trocar Produto.objects.filter(pk=pk, estoque__gte=qtd).update(...) por uma leitura seguida de save().

O que falha: Se duas requisições chegarem juntas para a última unidade, ambas leem estoque = 1 e ambas vendem! Ou o CheckConstraint do banco estoura erro 500.

Por que a regra existe: Baixa de estoque em marketplace precisa de atualização condicional atômica no banco, retornando 409 Conflict quando não há saldo.

Armadilhas comuns (errado × certo)

ErradoCertoPor quê
Retornar 200 OK com { 'erro': '...' } no corpoUsar o código de status HTTP adequado (400, 404, 409)Clientes e ferramentas de monitoramento olham primeiro o status HTTP.
Deixar campos de status ou total editáveis pelo clienteDeclarar read_only_fields no Serializer e calcular no servidorEvita fraude de preço e de pagamento.
Mão na massa

Exercício com pista e gabarito

Qual é a diferença prática entre receber um 400 Bad Request e um 409 Conflict ao tentar comprar?

Ver pista

Um diz respeito ao formato/validade dos dados; o outro ao estado atual do recurso no banco.

Ver gabarito

400 significa que o cliente mandou dados malformados ou inválidos (ex.: quantidade = -2 ou texto no lugar de número). 409 significa que os dados são válidos, mas conflitam com o estado atual (ex.: estoque insuficiente).

Quiz da lição

Quiz com explicação de cada erro

Um cliente envia DELETE para /api/produtos/ (sem ID). Qual código HTTP o DRF retorna?
Para que serve 'read_only_fields' em um ModelSerializer?
Revisão espaçada · 1, 3 e 7 dias

Fichas de revisão (clique para virar)

Se você só lembrar de 3 coisas desta lição:
  • Serializer valida a entrada e embala a saída; ViewSet executa; Router cria os endereços.
  • Use códigos HTTP honestos: 200, 201, 400, 404, 405 e 409 contam exatamente o que aconteceu.
  • Nunca confie em preço ou status vindo do cliente: use read_only_fields e recalcule no servidor.
Apoio rápido · 44 termos

Glossário de Fundamentos (A–Z)