Saltar al contenido
Inicio 100 Días de Código en Python — Día 37: Peticiones POST, PUT y DELETE, y encabezados — el Rastreador de Hábitos

100 Días de Código en Python — Día 37: Peticiones POST, PUT y DELETE, y encabezados — el Rastreador de Hábitos

Nivel: Grado décimo Área: Tecnología e Informática Modalidad: Tutorial práctico Fuente: Curso "100 Days of Code: The Complete Python Pro Bootcamp" (Angela Yu, App Brewery). Contenido del Día 37 (nivel intermedio+).

Este tutorial adapta pedagógicamente el Día 37. Las secciones 📝 Ejercicio original del curso provienen de los archivos del curso. Los retos 🟢🟡🟠🔴, el proyecto extra y el proyecto integrador son creaciones de esta adaptación. Las correcciones al material original aparecen como 🛠️ Nota técnica.

Nota sobre las verificaciones: con Python 3.14 y requests 2.34 se consultó, el 26 de septiembre de 2026, la documentación oficial de Pixela y se probaron peticiones POST, PUT y DELETE con encabezados en los servicios de prueba httpbin.org y postman-echo.com. No se creó ninguna cuenta en Pixela.

🔐 Nota importante para el aula (menores de edad): para registrarse en Pixela hay que enviar "notMinor": "yes". Según la documentación oficial, eso significa "no soy menor de edad, o soy menor y tengo el consentimiento de mis padres para usar el servicio" (verificado). La mayoría de estudiantes de décimo son menores de edad. Por eso:

  • No respondas "yes" sin ese consentimiento: sería declarar algo falso.
  • Todo el grupo puede aprender los conceptos del día con httpbin.org (sección 1), que no pide cuenta.
  • Quien quiera usar Pixela, debe hacerlo con autorización de su acudiente, o el docente hace la demostración con su cuenta.

Tabla de contenidos

  1. Antes de empezar: el rastreador de hábitos
  2. Los métodos HTTP: GET, POST, PUT y DELETE
  3. Paso 1: crear un usuario con POST
  4. Paso 2: autenticación con un encabezado y crear el gráfico
  5. Paso 3: agregar un píxel
  6. La fecha automática con strftime
  7. Actualizar y borrar con PUT y DELETE
  8. 🚀 Proyecto del día: el Rastreador de Hábitos
  9. 🌟 Proyecto extra: el Rastreador de Hábitos con ventana
  10. 🏆 Proyecto integrador de los Días 35 a 37: el Reto de Hábitos Saludables del Curso
  11. 🧩 Comprueba lo aprendido
  12. 🤖 Programar con apoyo de IA
  13. 🛠️ Correcciones técnicas al material original
  14. 📋 Matriz de trazabilidad
  15. 📦 Evidencias de aprendizaje del Día 37

0. Antes de empezar: el rastreador de hábitos

(Fuente: 282 - Day 37 Goals- what you will make by the end of the day.md)

La profesora cuenta que admira a Simone Giertz, una inventora que presentó un calendario de hábitos: cada día que cumples tu hábito, marcas la fecha. Como las marcas forman una línea continua, dan ganas de no romper la racha.

Hoy construiremos una versión digital con la API Pixela, creada por un desarrollador japonés. Pixela no solo marca qué días cumpliste tu hábito: también muestra la intensidad con colores más oscuros o más claros (por ejemplo, cuántas páginas leíste o cuántos kilómetros recorriste en bicicleta, que es el ejemplo de la profesora).

Hasta ahora solo pedíamos datos a las APIs (GET). Hoy aprenderemos a enviar, actualizar y borrar datos, y una forma más segura de autenticarse: el encabezado (header).

Prerequisito general: requests y JSON (Días 33 y 34); claves y variables de entorno (Día 35); cadenas f; datetime (Día 32); input() y conversión de tipos.


1. Los métodos HTTP: GET, POST, PUT y DELETE

(Fuente: 283 - HTTP Post Requests.md, primera parte)

🎯 Objetivo de aprendizaje

Distinguir los cuatro métodos HTTP más comunes y usarlos con requests.

📖 Explicación conceptual

Método Qué hace En requests Ejemplo del curso
GET Pedir datos a un sistema externo requests.get() La posición de la ISS
POST Enviar datos nuevos; solo nos interesa saber si funcionó requests.post() Guardar una fila en Google Sheets, publicar un trino
PUT Actualizar un dato que ya existe requests.put() Cambiar un valor de una hoja de cálculo
DELETE Borrar un dato requests.delete() Borrar una publicación

El código se escribe casi igual para los cuatro: solo cambia el método.

🏫 Practicar sin cuenta: httpbin.org (adaptación)

httpbin.org es un servicio de prueba que te devuelve lo que le enviaste. Es ideal para ver qué viaja en una petición:

Python
import requests

response = requests.post(
    "https://httpbin.org/post",
    json={"date": "20260926", "quantity": "9.74"},
    headers={"X-USER-TOKEN": "secreto123"},
)
data = response.json()
print(data["json"])       # {'date': '20260926', 'quantity': '9.74'}
print(data["headers"]["X-User-Token"])   # secreto123

(Verificado. También funcionan https://httpbin.org/put con requests.put y https://httpbin.org/delete con requests.delete. Un servicio similar es https://postman-echo.com/post.)

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: envía a httpbin un POST con tu nombre y tu hábito favorito, e imprime lo que te devuelve.
  • 🟡 Reto 2: haz un PUT y un DELETE a httpbin e imprime el código de estado de cada uno.
  • 🟠 Reto 3: envía el mismo diccionario con json= y con data=. Compara, en la respuesta de httpbin, dónde aparece cada uno. ¿Qué diferencia hay?
  • 🔴 Reto 4: para cada una de estas acciones, di qué método HTTP usarías y por qué: consultar tu horario, inscribirte en un club, cambiar tu correo en la plataforma del colegio, cancelar tu inscripción.

2. Paso 1: crear un usuario con POST

(Fuente: 283 - HTTP Post Requests.md)

🎯 Objetivo de aprendizaje

Enviar datos con requests.post(url, json=...) siguiendo la documentación.

📝 Contenido original del curso

La página de Pixela tiene una guía de inicio en seis pasos; el curso la sigue junto con la documentación. Paso 1: crear un usuario con un POST a https://pixe.la/v1/users.

Parámetros obligatorios del cuerpo:

Parámetro Valor Nota
token Una cadena secreta inventada por ti Entre 8 y 128 caracteres. Funciona como una contraseña: guárdala
username Tu nombre de usuario Único en todo Pixela
agreeTermsOfService "yes" o "no" Aceptar las condiciones de uso
notMinor "yes" o "no" Ver la nota para el aula al inicio
Python
import requests

pixela_endpoint = "https://pixe.la/v1/users"

user_params = {
    "token": TOKEN,
    "username": USERNAME,
    "agreeTermsOfService": "yes",
    "notMinor": "yes",     # solo si es verdad (ver nota inicial)
}

response = requests.post(url=pixela_endpoint, json=user_params)
print(response.text)
  • json= envía el diccionario como JSON en el cuerpo de la petición.
  • response.text muestra la respuesta como texto. Con un POST casi solo nos interesa saber si funcionó y, si no, por qué.
  • La profesora obtuvo un mensaje de éxito. Al ejecutar otra vez el mismo código, la respuesta dijo que el usuario ya existe. Por eso, después de crear el usuario, comenta esa línea.

💡 El curso copia los nombres de los parámetros de la documentación para no equivocarse: agreeTermsOfService tiene varias mayúsculas.

⚠️ Errores frecuentes

Error Qué ocurre Solución
params=user_params en vez de json= Los datos viajan en la URL, no en el cuerpo, y el servidor no los encuentra Usa json=
Un token de menos de 8 caracteres Error de validación Mínimo 8 caracteres
Ejecutar dos veces la creación "This user already exists" Comenta ese paso después de la primera vez
Escribir el token en el código y compartirlo Cualquiera puede modificar tus datos Variable de entorno (Día 35)

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: envía user_params a https://httpbin.org/post (sin crear cuenta real) y comprueba que el cuerpo llega completo.
  • 🟡 Reto 2: lee el TOKEN desde una variable de entorno y valida que tenga entre 8 y 128 caracteres antes de enviarlo.
  • 🟠 Reto 3: genera un token aleatorio seguro con el módulo secrets (investiga secrets.token_urlsafe).
  • 🔴 Reto 4: lee la lista de códigos de error de la documentación de Pixela (400, 404, 409, 503…) y escribe una función que traduzca cada código a un mensaje en español.

3. Paso 2: autenticación con un encabezado y crear el gráfico

(Fuente: 284 - Advanced Authentication using an HTTP Header.md)

🎯 Objetivo de aprendizaje

  • Enviar la autenticación en un encabezado HTTP.
  • Explicar por qué es más seguro que enviarla como parámetro.

📝 Contenido original del curso

Paso 2 de Pixela: crear un gráfico con un POST a /v1/users/<username>/graphs:

Python
graph_endpoint = f"{pixela_endpoint}/{USERNAME}/graphs"

graph_config = {
    "id": "graph1",
    "name": "Cycling Graph",
    "unit": "Km",
    "type": "float",
    "color": "ajisai",
}
Clave Regla
id Empieza con una letra (a-z), luego letras o números; de 1 a 16 caracteres. "1graph" no es válido
name Nombre del gráfico
unit Unidad de medida (km, páginas, minutos)
type "int" (enteros, como páginas) o "float" (decimales, como kilómetros)
color Nombres en japonés: por ejemplo shibafu (pasto, verde), momiji (hojas de otoño, rojo), sora (cielo, azul), ajisai (hortensia, morado). Cópialos de la documentación

El error: al enviar requests.post(url=graph_endpoint, json=graph_config), la respuesta dice que el usuario no existe o el token es incorrecto. ¿Por qué? ¡En ningún lado enviamos el token!

📖 Los encabezados (headers)

La analogía del curso: en una carta, el encabezado tiene la información fija del remitente (logo, teléfono, dirección) y el cuerpo es el mensaje que cambia de una carta a otra. Una petición HTTP también tiene encabezados (información sobre la petición, como la autenticación) y cuerpo (los datos).

Pixela pide el token en un encabezado llamado X-USER-TOKEN:

Python
headers = {
    "X-USER-TOKEN": TOKEN
}

response = requests.post(url=graph_endpoint, json=graph_config, headers=headers)
print(response.text)
  • headers= es un argumento con nombre: el editor no siempre lo sugiere, así que escríbelo bien (con s final).
  • Para ver el gráfico: https://pixe.la/v1/users/<tu_usuario>/graphs/<id_del_gráfico>.html.

📖 ¿Por qué un encabezado es más seguro?

En el Día 36, la clave de News API iba como parámetro, es decir, dentro de la URL:

Texto
https://newsapi.org/v2/everything?apiKey=TU_CLAVE&qInTitle=Tesla

Las URL quedan guardadas en muchos lugares: el historial del navegador, los registros (logs) de los servidores, extensiones que ven las peticiones. Con HTTPS la petición viaja cifrada, pero aun así la clave puede filtrarse por esos otros caminos. Por eso la documentación de News API recomienda usar un encabezado (X-Api-Key) en lugar del parámetro. Al verificar el Día 36 sin clave, su mensaje de error lo decía: "Append this to the URL with the apiKey param, or use the x-api-key HTTP header".

⚠️ Errores frecuentes

Error Qué ocurre Solución
No enviar headers "User does not exist or the token is wrong" headers={"X-USER-TOKEN": TOKEN}
header= (sin s) TypeError: ... unexpected keyword argument 'header' headers=
Color mal escrito ("sakura") Error de validación Copia el nombre de la documentación
id que empieza con número Error de validación Empieza con una letra

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: envía a httpbin un POST con y sin headers y compara qué aparece en data["headers"].
  • 🟡 Reto 2: en httpbin, envía una clave como parámetro con params= y como encabezado con headers=. Mira data["url"]: ¿en cuál de los dos casos aparece la clave?
  • 🟠 Reto 3: diseña (en papel) el graph_config de un hábito tuyo: nombre, unidad, tipo y color. Justifica si es int o float.
  • 🔴 Reto 4: investiga el encabezado User-Agent: envíalo a httpbin sin cambiar nada y luego con un valor propio. ¿Para qué crees que lo usan los servidores?

4. Paso 3: agregar un píxel

(Fuente: 285 - Challenge- Add a Pixel to the Habit Tracker using a Post Request.md)

📝 Ejercicio original del curso

Enunciado: leer en la documentación cómo publicar un píxel (descripción, encabezado y cuerpo) y hacerlo.

Pistas del curso:

  • El endpoint es otro; todo lo que va entre < y > se reemplaza por tus valores reales.
  • Es un POST con autenticación en el encabezado.
  • date: formato yyyyMMdd (cuatro dígitos del año, dos del mes y dos del día), como texto.
  • quantity: la cantidad del día, también como texto.

🔍 Antes de programar

  • ¿Cómo queda el endpoint con tu usuario y tu id de gráfico?
  • Si tu gráfico es de tipo int, ¿puedes enviar "9.74"?

🔎 La solución del curso

Python
GRAPH_ID = "graph1"
pixel_creation_endpoint = f"{pixela_endpoint}/{USERNAME}/graphs/{GRAPH_ID}"

pixel_data = {
    "date": "20200724",
    "quantity": "9.74",
}

response = requests.post(url=pixel_creation_endpoint, json=pixel_data, headers=headers)
print(response.text)

Al recargar la página del gráfico aparece el píxel con su color, y Pixela calcula estadísticas: total, máximo, mínimo, promedio y número de píxeles.

📖 El rechazo del 25 % (análisis de esta adaptación)

La documentación de Pixela (verificada) indica que, para usuarios que no son supporters (donantes), algunas peticiones se rechazan a propósito el 25 % de las veces. En ese caso la respuesta es 503 y el cuerpo contiene "isRejected": true. La documentación dice que basta con reintentar.

Esto explica por qué, a veces, el mismo código funciona en una ejecución y falla en la siguiente. Un programa robusto lo reintenta automáticamente:

Python
def post_con_reintentos(url, datos, headers, intentos=5):
    for intento in range(intentos):
        response = requests.post(url=url, json=datos, headers=headers)
        if response.status_code != 503:
            return response
        print(f"Rechazado, reintentando ({intento + 1})...")
    return response

⚠️ Errores frecuentes

Error Qué ocurre Solución
"date": 20200724 (número) Error: debe ser texto "20200724"
"date": "2020-07-24" Formato inválido yyyyMMdd, sin guiones
"quantity": 9.74 (número) Error: debe ser texto "9.74"
Decimales en un gráfico int Error de validación Envía enteros, o crea el gráfico como float
Dejar <username> literal en la URL 404 Reemplaza los marcadores

💡 La documentación define reglas de validación para quantity: en gráficos float, un número con punto decimal (por ejemplo "10.0"). Si envías "10" a un gráfico float y falla, esa es la razón probable. Compruébalo y anota el resultado.

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: con httpbin, envía el pixel_data y verifica que ambos valores llegan como texto.
  • 🟡 Reto 2: agrega a tu programa la función post_con_reintentos y haz que imprima cuántos intentos necesitó.
  • 🟠 Reto 3: convierte la cantidad que escribe el usuario (input) en un texto válido: acepta "10,5" (con coma, como se escribe en Colombia) y conviértelo a "10.5".
  • 🔴 Reto 4: Pixela permite un campo opcional optionalData (un texto JSON). Úsalo para guardar una nota del día, por ejemplo el nombre del libro que leíste.

5. La fecha automática con strftime

(Fuente: 286 - Autofilling today's date using strftime.md)

🎯 Objetivo de aprendizaje

Convertir un datetime en el texto exacto que pide una API.

📖 Explicación conceptual

Cada API pide la fecha en un formato distinto (el curso comenta que en Asia se suele escribir primero el año y en otros países al final). El método strftime ("string format time") convierte un datetime en texto usando códigos:

Código Significado Ejemplo (26/09/2026)
%Y Año con 4 dígitos 2026
%m Mes con 2 dígitos 09
%d Día con 2 dígitos 26
%a Día de la semana, abreviado Sat
%A Día de la semana, completo Saturday
%b Mes, abreviado Sep
%B Mes, completo September

(Resultados verificados.)

Python
from datetime import datetime

today = datetime.now()
print(today.strftime("%Y%m%d"))     # 20260926
print(today.strftime("%Y-%m-%d"))   # 2026-09-26: puedes agregar guiones o espacios

Para otro día: crea la fecha tú mismo, por ejemplo ayer: datetime(year=2026, month=9, day=25), y dale formato igual.

🛠️ Nota técnica: el video dice que %b da "el nombre completo del mes". En realidad da el nombre abreviado (Sep); el completo es %B (September), verificado. Además, los nombres salen en inglés por defecto.

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: imprime la fecha de hoy como 26/09/2026.
  • 🟡 Reto 2: imprime "Hoy es sábado 26 de septiembre de 2026" en español (usa listas con los nombres en español y los atributos del datetime).
  • 🟠 Reto 3: calcula la fecha de ayer automáticamente con timedelta(days=1) y dale el formato yyyyMMdd.
  • 🔴 Reto 4: el proceso inverso existe: datetime.strptime("20260926", "%Y%m%d"). Úsalo para validar que una fecha escrita por el usuario es real (por ejemplo, rechazar "20260231").

6. Actualizar y borrar con PUT y DELETE

(Fuente: 287 - How to use HTTP Put and Delete Requests.md)

📝 Ejercicio original del curso

Desafío 1 (PUT): la profesora "mintió": ayer no recorrió 15 km sino 4,5. Actualiza el píxel.

Desafío 2 (DELETE): borra un píxel.

🔍 Antes de programar

  • ¿Qué diferencia hay entre el endpoint para crear un píxel y el endpoint para actualizar un píxel concreto?
  • ¿DELETE necesita cuerpo? ¿Necesita autenticación?

🔎 La solución del curso

Python
update_endpoint = f"{pixela_endpoint}/{USERNAME}/graphs/{GRAPH_ID}/{today.strftime('%Y%m%d')}"

new_pixel_data = {
    "quantity": "4.5"
}

response = requests.put(url=update_endpoint, json=new_pixel_data, headers=headers)
print(response.text)

delete_endpoint = f"{pixela_endpoint}/{USERNAME}/graphs/{GRAPH_ID}/{today.strftime('%Y%m%d')}"

response = requests.delete(url=delete_endpoint, headers=headers)
print(response.text)
  • El endpoint termina en la fecha del píxel que quieres cambiar o borrar.
  • Comillas: dentro de la cadena f (con comillas dobles) el formato de strftime va entre comillas simples.
  • DELETE no lleva datos en el cuerpo, pero sí el encabezado de autenticación.

Versión final del curso: se comentan las demás peticiones, se deja la de crear el píxel con la fecha de hoy y la cantidad se pide al usuario:

Python
pixel_data = {
    "date": today.strftime("%Y%m%d"),
    "quantity": input("How many kilometers did you cycle today? "),
}

⚠️ Errores frecuentes

Error Qué ocurre Solución
Usar el endpoint de creación con PUT Error: falta la fecha en la URL Agrega /{fecha} al final
Olvidar headers en DELETE Error de autenticación DELETE también lleva el token
Comillas dobles dentro de la cadena f (antes de Python 3.12) SyntaxError Comillas simples adentro
Borrar sin confirmar Pierdes el dato sin querer Pide confirmación antes

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: con httpbin, haz un PUT y un DELETE con encabezado y muestra lo que devuelve cada uno.
  • 🟡 Reto 2: antes de borrar, pregunta: "¿Seguro que quieres borrar el registro del 25/09/2026? (s/n)".
  • 🟠 Reto 3: un menú de consola con las opciones: 1. Registrar hoy, 2. Corregir un día, 3. Borrar un día, 4. Salir.
  • 🔴 Reto 4: crea una clase ClienteHabitos con los métodos registrar(fecha, cantidad), corregir(fecha, cantidad) y borrar(fecha), que guarde internamente el endpoint y los encabezados. ¿Qué código repetido desaparece?

7. 🚀 Proyecto del día: el Rastreador de Hábitos

(Fuentes: 282 a 287)

Problema

Registrar cada día un hábito que quieras desarrollar y verlo como un gráfico que motive a no romper la racha.

Contexto

Elige un hábito tuyo: minutos de lectura del Plan Lector, minutos de práctica de un instrumento, vasos de agua, kilómetros en bicicleta, minutos programando…

Requisitos funcionales

  1. Registrar la cantidad de hoy (fecha automática con strftime).
  2. Corregir la cantidad de un día anterior (PUT).
  3. Borrar el registro de un día (DELETE), con confirmación.
  4. Mostrar al final el enlace del gráfico.

Restricciones técnicas

  • Modo aula: todas las peticiones a httpbin.org, que simula el servidor. Modo real: Pixela, solo con cuenta autorizada (ver nota inicial). Una constante MODO_REAL = False decide a dónde van las peticiones.
  • Token en variable de entorno.
  • Reintentos ante el 503 de Pixela.

Planificación

Entradas Proceso Salidas
Opción del menú, cantidad, fecha Construir endpoint, cuerpo y encabezado; enviar con el método correcto Mensaje de éxito o de error; gráfico actualizado

Pruebas

Caso Esperado
Registrar hoy con "30" en un gráfico int Éxito
Registrar "treinta" El programa rechaza el valor antes de enviar
Registrar con "10,5" Se convierte a "10.5" (si el gráfico es float)
Corregir una fecha inexistente (20260231) El programa la rechaza antes de enviar
Petición rechazada por Pixela (503) ⚠️ (ver 🧪)
Token sin configurar ⚠️ (ver 🧪)

🧪 Prueba y depuración

  1. El 503 aleatorio. Sin reintentos, el programa falla una de cada cuatro veces en promedio. Implementa los reintentos con un límite (sección 4) y registra cuántos intentos fueron necesarios en 10 ejecuciones.
  2. El token ausente. Sin la variable de entorno, el encabezado se envía con None y el error de la API no lo explica. Detéctalo al iniciar el programa.
  3. Registrar dos veces el mismo día. El curso comenta que ya no pudo publicar otro dato para hoy. Consulta la documentación de Pixela: ¿qué pasa al publicar un píxel en una fecha que ya tiene uno? Ofrece al usuario "corregir" en lugar de "registrar" si ya existe un dato de hoy.
  4. La fecha de hoy según la hora. Si el programa se ejecuta en un servidor en UTC (Día 32) a las 9:00 p. m. de Colombia, ¿qué fecha usa datetime.now()? ¿Cómo lo resolverías?

⭐ Extensión del proyecto

  • Guardar localmente, en un CSV, cada acción realizada (fecha, método, cantidad, resultado).
  • Calcular la racha actual de días seguidos con registro.
  • Programar un recordatorio por correo a las 8:00 p. m. si hoy no hay registro.

8. 🌟 Proyecto extra: el Rastreador de Hábitos con ventana

Situación

Tu familia quiere usar tu rastreador, pero no saben usar la consola. Construye una interfaz gráfica con Tkinter.

Requisitos

  1. Ventana con: una entrada para la cantidad, una entrada para la fecha (con la fecha de hoy ya escrita en formato dd/mm/aaaa) y tres botones: Registrar, Corregir y Borrar.
  2. Una clase ClienteHabitos (Reto 4 de la sección 6) que haga las peticiones; la interfaz no usa requests directamente.
  3. Validación: fecha real (strptime), cantidad numérica (acepta coma o punto).
  4. Mensajes con messagebox: éxito, error de validación, error del servidor.
  5. Borrar pide confirmación con messagebox.askyesno.
  6. Un botón Ver gráfico que abra el enlace en el navegador (investiga el módulo webbrowser).
  7. Modo aula (httpbin) y modo real (Pixela) con una constante.
  8. Los botones se desactivan mientras se hace una petición (recuerda el doble clic del Día 34).

Decisiones que debes tomar

  • Si el servidor tarda, la ventana se congela. ¿Es aceptable para este uso? (Investiga, sin implementarlo, qué son los hilos o threads.)
  • ¿Guardas el usuario y el id del gráfico en el código, en un JSON o los pides en la ventana?

Casos de prueba

Caso Esperado
Fecha 31/02/2026 Mensaje "Fecha no válida"; no se envía nada
Cantidad abc Mensaje "Cantidad no válida"
Borrar y responder "No" No se envía nada
Modo aula httpbin devuelve los datos; la ventana muestra "Éxito (simulado)"

9. 🏆 Proyecto integrador de los Días 35 a 37: el Reto de Hábitos Saludables del Curso

Proyecto integrador creado para esta adaptación. Reúne autenticación, variables de entorno y alertas (Día 35), combinación de varias APIs y caché (Día 36), y los métodos POST, PUT y DELETE con encabezados (Día 37).

Situación problema

El director de grupo propone un reto de 30 días de hábitos saludables (agua, actividad física, lectura, sueño). Cada participante registra su avance y el grupo recibe un resumen semanal. Para no depender de cuentas personales, el grupo construirá su propio servidor simulado.

Pregunta orientadora

¿Cómo diseñar un programa que hable con un servicio web usando los cuatro métodos HTTP, que funcione igual con un servicio real o simulado, y que proteja los datos de los participantes?

Objetivo

Construir el Reto de Hábitos Saludables: un cliente de consola (o Tkinter) que registra, corrige, borra y consulta hábitos, con dos "servidores" intercambiables.

Requerimientos

  1. Una clase abstracta o base ServidorHabitos con los métodos crear(usuario, fecha, cantidad), consultar(usuario, fecha_inicio, fecha_fin), actualizar(...) y borrar(...).
  2. Dos implementaciones:
    • ServidorLocal: guarda todo en un habitos.json (sin internet). Simula el 503 de Pixela con una probabilidad configurable, para practicar los reintentos.
    • ServidorEco: envía cada operación a httpbin.org con el método HTTP correcto (GET, POST, PUT, DELETE) y un encabezado de autenticación, y muestra qué se envió.
  3. participantes.csv con nombres ficticios y el hábito de cada uno (unidad y tipo int/float).
  4. Validaciones: fecha real, dentro de los 30 días del reto; cantidad del tipo correcto; no registrar dos veces el mismo día (ofrecer corregir).
  5. Reintentos con límite cuando el servidor responde "rechazado".
  6. Resumen semanal por correo (servidor local del Día 32): participantes con racha completa, promedio por hábito y quién no ha registrado en 3 días.
  7. Un "token" del grupo en variable de entorno; el programa no arranca si falta.
  8. Un archivo config.json que decide qué servidor usar.

Restricciones

  • Datos ficticios; nada de cuentas personales de estudiantes en servicios externos.
  • El código que usa el servidor no sabe cuál de los dos está usando.

Etapas de desarrollo

Etapa Entregable parcial
1. Diseño Diagrama de clases y tabla "operación → método HTTP"
2. ServidorLocal Las cuatro operaciones probadas con habitos.json
3. Reintentos Simulación del rechazo con 30 % de probabilidad
4. ServidorEco Las cuatro operaciones enviadas a httpbin con encabezado
5. Resumen Correo semanal al servidor local
6. Presentación Demostración cambiando de servidor solo con config.json

Entregables

  • Código en varios archivos, config.json, participantes.csv.
  • Diagrama de clases.
  • 12 casos de prueba con resultados.
  • Registro de errores con al menos 5 errores reales.
  • Un párrafo sobre por qué no se usaron cuentas personales de menores de edad en servicios externos.

Casos de prueba mínimos

Caso Esperado
Registrar dos veces el mismo día Se ofrece corregir
Rechazo simulado 3 veces seguidas y luego éxito Éxito tras 4 intentos
Rechazo simulado más veces que el límite Mensaje claro de fallo
Cambiar config.json de local a eco El resto del programa funciona sin cambios
Falta la variable de entorno del token El programa no arranca y dice por qué

Criterios técnicos de funcionamiento

  • Ninguna función fuera de las clases de servidor usa requests o json directamente.
  • Las validaciones están en funciones que se pueden probar sin servidor.
  • El resumen semanal se calcula correctamente con datos simulados de 30 días.

Posibles extensiones

Interfaz Tkinter para registrar; gráfico de barras del avance (lo aprenderás en días posteriores del curso); un tercer servidor que use Pixela real, solo para quien tenga autorización.


10. 🧩 Comprueba lo aprendido

Conceptuales

  1. ¿Qué método HTTP usarías para: pedir el clima, publicar una foto, cambiar tu foto de perfil, borrar un comentario?
  2. ¿Qué diferencia hay entre enviar datos con params= y con json=?
  3. ¿Qué es un encabezado HTTP? Explícalo con la analogía de la carta.
  4. ¿Por qué enviar una clave en un encabezado es más seguro que enviarla en la URL, aunque la conexión sea HTTPS?
  5. ¿Qué significa "notMinor": "yes" según la documentación de Pixela?

Análisis de código

Python
response = requests.post(url=graph_endpoint, json=graph_config, headers=headers)

Identifica qué parte de la petición es la URL, cuál el cuerpo y cuál el encabezado. ¿Cuál de ellas contiene el token?

Predicción

  1. ¿Qué imprime datetime(2026, 1, 5).strftime("%Y%m%d")? ¿Y con "%d/%m/%Y"?
  2. ¿Qué imprime datetime(2026, 9, 26).strftime("%b %B")?
  3. Si una petición se rechaza con probabilidad 25 %, ¿cuál es la probabilidad de que fallen dos intentos seguidos? ¿Y tres?

Depuración

Python
pixel_data = {
    "date": datetime.now().strftime("%Y-%m-%d"),
    "quantity": 12,
}
response = requests.post(url=f"{pixela_endpoint}/<username>/graphs/{GRAPH_ID}", json=pixel_data)

Encuentra cuatro errores.

Modificación

Cambia la versión final del curso para que, si el usuario escribe 0, se borre el píxel de hoy en lugar de registrar cero.

Creación

Escribe a_formato_pixela(texto_fecha: str) -> str que reciba una fecha como "26/09/2026" y devuelva "20260926", o lance ValueError si la fecha no es real. Pruébala con 4 casos.


11. 🤖 Programar con apoyo de IA

Actividad 1: leer los términos antes de aceptar. El curso responde "yes" a agreeTermsOfService y notMinor en segundos. Pide a una IA que te resuma los términos de servicio de Pixela y luego:

  1. Abre los términos originales y verifica dos afirmaciones del resumen.
  2. Busca qué dicen sobre los menores de edad y compáralo con la documentación del parámetro notMinor.
  3. Reflexiona: ¿cuántas veces has aceptado términos sin leerlos? ¿Qué podría salir mal?

Actividad 2: depurar con la IA sin compartir el token. Si una petición falla, copia la respuesta del servidor (no tu token) y tu código con el token reemplazado por "TOKEN". Pide a la IA una explicación. Comprueba la explicación con la documentación de códigos de error de Pixela.

Actividad 3: ¿conoce la IA el rechazo del 25 %? Pregunta: "¿Por qué mi petición a Pixela a veces devuelve 503 y a veces funciona?". Compara su respuesta con la documentación (sección 4). Si inventa otra causa, anota cómo lo descubriste.


12. 🛠️ Correcciones técnicas al material original

Archivo Afirmación o comportamiento del curso Observación Tratamiento
283 Responder "notMinor": "yes" sin más explicación Significa "no soy menor, o soy menor con consentimiento de mis padres" (verificado en la documentación); relevante para estudiantes de décimo Nota inicial; alternativa con httpbin
284 Color "sara es cielo" El nombre en la API es sora (cielo); copiarlo de la documentación Sección 3
285 Las peticiones funcionan siempre que el código sea correcto Pixela rechaza el 25 % de algunas peticiones de usuarios no supporters con 503 e "isRejected": true (verificado en la documentación) Sección 4; 🧪 del proyecto
286 %b da el nombre completo del mes %b es abreviado (Sep); el completo es %B (verificado) Nota técnica de la sección 5
287 input() para la cantidad, enviado sin validar Textos no numéricos, comas decimales o enteros en gráficos float pueden ser rechazados Pruebas y Reto 3 de la sección 4

13. 📋 Matriz de trazabilidad

Contenido original Archivo de origen Concepto desarrollado Ejercicio original Reto adicional Proyecto relacionado
Objetivos, calendario de hábitos, Pixela, intensidad 282 Sección 0 — — Sección 7
GET, POST, PUT, DELETE; crear usuario; json=; response.text 283 Secciones 1 y 2 Paso 1: crear usuario Retos 1–4 de las secciones 1 y 2; httpbin Secciones 7, 8 y 9
Crear gráfico, reglas de id, colores, encabezado X-USER-TOKEN, seguridad de encabezados 284 Sección 3 Paso 2: crear gráfico Retos 1–4 de la sección 3 Secciones 7, 8 y 9
Publicar un píxel, date y quantity como texto 285 Sección 4 Desafío: agregar un píxel Retos 1–4 de la sección 4; reintentos Secciones 7, 8 y 9
strftime, códigos de formato, fechas pasadas 286 Sección 5 Fecha automática Retos 1–4 de la sección 5 Secciones 7 y 8
PUT y DELETE, endpoint con fecha, input() 287 Sección 6 Desafíos PUT y DELETE Retos 1–4 de la sección 6 Secciones 7, 8 y 9
(No existe en el curso original) — — — Rastreador de Hábitos con ventana Sección 8
(No existe en el curso original) — — — Reto de Hábitos Saludables (Días 35–37) Sección 9

14. 📦 Evidencias de aprendizaje del Día 37

  • Las respuestas de httpbin a un GET, POST, PUT y DELETE, con tu explicación de dónde aparecen el cuerpo y el encabezado.
  • El experimento del Reto 2 de la sección 3: la clave en la URL frente a la clave en el encabezado.
  • Tu graph_config justificado (nombre, unidad, tipo, color).
  • El Rastreador de Hábitos funcionando en modo aula (y en modo real, si tienes autorización), con reintentos.
  • La tabla de códigos de strftime con ejemplos que tú ejecutaste.
  • El Rastreador con ventana (proyecto extra) o el Reto de Hábitos Saludables (proyecto integrador).
  • Cuaderno de errores: params en lugar de json, usuario ya existente, falta de encabezado, header sin s, color mal escrito, fecha con guiones, cantidad como número, marcadores <username> sin reemplazar, 503 aleatorio, %b frente a %B y comillas dentro de la cadena f.