Ejercicio 1 — Serializer
class SeatRefSerializer(serializers.Serializer):
sector = serializers.CharField(max_length=50)
row = serializers.CharField(max_length=10)
number = serializers.IntegerField(min_value=1)
class ReserveInputSerializer(serializers.Serializer):
event = serializers.UUIDField()
seats = SeatRefSerializer(many=True, min_length=1, max_length=8) # límites
promo_code = serializers.CharField(max_length=32, required=False, write_only=True)
def validate_event(self, value):
if not Event.objects.filter(uuid=value).exists(): # referencia trivial
raise serializers.ValidationError("El evento no existe")
return value- Mensajes por caso: listas vacías/grade → "Este campo debe tener entre 1 y 8 elementos"; formato → error por índice con campo concreto; uuid → "El evento no existe" (mensaje de negocio, no "Invalid pk \"...\"").
- "Evento pasado" consulta estado mutable y podría cambiar entre validate y action (raza): lo decide el servicio con el evento bloqueado (10). El serializer es forma; el servicio, mundo.
Ejercicio 2 — Capas
- JSON roto → 400 (parser DRF, capa sintaxis); tipos mal → 400 con
errorspor campo (capa forma); asiento ocupado → 409 contype: seat-already-reserved(capa negocio, desde DomainError de la 10/13). - "Asiento libre" en el serializer reintroduce check-then-act sin bloqueo: dos requests validan ok y ambos crean — exactamente la carrera de la 03/10 que la constraint convierte en 409 tarde y con mala UX. La validación de negocio mutable va bajo bloqueo, en el servicio.
Ejercicio 3 — Contrato
- Lo típico que adivina mal: viewsets con múltiples serializers (list vs detail), FileField/binary, errores 4xx no documentados. El YAML te lo señala.
@extend_schema(request=ReserveInputSerializer, responses={201: ReservationOut, 409: ProblemDetail, 422: ProblemDetail}, summary="Crear reserva")— y el webhook conrequest=GatewayWebhookIn, responses={200: None}.--fail-on-warnobliga a documentar lo que el AutoSchema no deduce: cada warning arreglado es un endpoint que el frontend consume sin preguntarte.
Ejercicio 4 — Test de contrato
def test_reserva_cumple_contrato(self, client, ...):
resp = client.post("/api/reservations/", payload)
self.assertEqual(resp.status_code, 201)
self.assertEqual(set(resp.data), set(ReservationOut.Meta.fields)) # claves del schema- Con los examples extraídos y
jsonschema.validate(resp.data, example_schema): las docs mienten cuando el código evoluciona sin actualizarlas — el test hace que mentir rompa CI.
Resumen del profesor
- Capas: sintaxis → forma → negocio; el negocio bajo bloqueo, no en el serializer.
- Serializer con límites explícitos, fields explícitos y mensajes de dominio.
- OpenAPI generado del código + extend_schema donde adivina; --fail-on-warn en CI.
- Un test de contrato por endpoint crítico: las docs dejan de mentir.
Después: Lección 16 — gRPC, GraphQL, WebSockets/SSE.