Contrato de la API
Las cuatro rutas que expone tu backend, para cuando quieras construirle algo
encima. Todas cuelgan de la URL que te imprime npm run deploy.
Esto describe el contrato que exige la spec y que revisa npm run verify 3. Si
tu agente escribió algo distinto, compáralo contra esta página antes de
desplegar.
Cómo se ve un elemento guardado
{
"altarId": "mi-altar",
"id": "9f0c1e7a-...",
"tipo": "vela",
"nivel": 1,
"posicion": 0,
"texto": "Para mi abuela",
"link": null,
"imageKey": null,
"puestoPor": "Axel",
"creadoEn": "2026-10-29T03:14:07.000Z"
}
Tres campos los pone el servidor, no tú
ides un UUID que genera la Lambda.creadoEnes la fecha del servidor, en ISO.posiciones el orden dentro de su grada, y sale de contar cuántos hay ya en ese nivel. Si lo mandas en el cuerpo, se ignora.
Eso es a propósito: son los tres campos donde un cliente mentiroso haría daño.
GET /elements
Lista los elementos de un altar. Recibe altarId como parámetro de query.
Por dentro es un Query de DynamoDB con Limit, no un Scan. La diferencia
importa: Scan lee la tabla entera y te cobra por todo, Query lee solo las
filas de tu altar.
POST /elements
Hace dos cosas, según lo que le mandes.
- Para agregar, el cuerpo lleva al menos
altarIdytipo. Responde201con el elemento guardado. - Para quitar, el cuerpo lleva
altarId,borrar: truey elid. Como la sort key es<creadoEn>#<id>, la Lambda primero encuentra la fila con unQueryporaltarIdy luego la borra. Responde404si eseidno existe en el altar.
💡 Solo seis campos del cuerpo pueden entrar a la tabla
tipo,nivel,texto,link,puestoPoreimageKey.Lo que no esté en esa lista se descarta, aunque lo mandes.
posiciontambién se ignora porque la Lambda la calcula contando lo que ya existe en esa grada.
Responde 400 si el cuerpo no es JSON válido, si falta altarId, o si falta
tipo al agregar.
⚠️ Esta ruta está abierta
No tiene autenticación. Cualquiera con la URL de tu API puede escribir en tu altar.
Lo que hace la Lambda para limitar el daño es copiar solo seis campos conocidos;
id,creadoEnyposicionlos calcula el servidor. Cerrarla de verdad pide un autorizador de Cognito en esta ruta, y eso ya no cabe en el taller.
POST /uploads
Pide una URL firmada para subir una imagen a S3. Recibe altarId y el
contentType.
La URL sirve para un PUT y vive cinco minutos. Responde 400 si el
contentType no es de imagen.
Tu navegador sube el archivo directo a S3 con esa URL. La imagen no pasa por la Lambda, y por eso puedes subir fotos grandes sin que se quede sin memoria.
GET /uploads/{proxy+}
Pide una URL firmada para leer una imagen. Vive hasta una hora; puede expirar antes si terminan primero las credenciales temporales que la firmaron.
Esta ruta existe porque el bucket es privado. En vez de abrir el bucket al mundo, se firma cada lectura. Es la forma que recomienda AWS para objetos privados.
La misma Lambda atiende esta ruta y la de arriba: una firma para escribir, la otra para leer.
La llave de la tabla
Partition key altarId. Sort key sk, con la forma <creadoEn>#<id>.
La fecha va primero porque en ISO ordena como texto, así que un Query te
devuelve el altar en orden de creación sin ordenar nada después. El id va al
final para desempatar dos elementos del mismo milisegundo.
sk no le sirve de nada al frontend, así que la respuesta del POST la quita
antes de contestar.
⚠️ Si cambias la llave, se rompe el listado
Es la única decisión del backend que no se puede cambiar sin rehacer la tabla. La steering del starter se lo prohíbe al agente por eso.