Introducción
Un equipo de pedidos necesita aceptar pedidos JSON y devolver totales calculados. Conectarás rutas de salud, escritura y lectura a una aplicación Lambda suministrada, probarás solicitudes válidas y rechazadas y comprobarás los registros almacenados en DynamoDB antes de la limpieza.
Completa primero Exponer una función Lambda mediante una API HTTP y Leer y escribir en DynamoDB desde Lambda. Este entorno nuevo proporciona la aplicación, el rol y tablas independientes.
Relación con las certificaciones
| Certificación | Tarea del examen | Práctica |
|---|---|---|
| Solutions Architect – Associate (SAA-C03) | Tarea 2.1 | Validación de solicitudes API, respuestas y datos de negocio persistidos. |
| Developer – Associate (DVA-C02) | Tarea 1.1, Tarea 3.2 | Validación de solicitudes API, respuestas y datos de negocio persistidos. |
| DevOps Engineer – Professional (DOP-C02) | Tarea 3.2 | Práctica de fundamentos: Validación de solicitudes API, respuestas y datos de negocio persistidos. |
Vista general del laboratorio

Preparar el backend de pedidos
En este paso, inspeccionarás el contrato de solicitudes suministrado, concederás a la función acceso a su tabla de pedidos y desplegarás el backend. La aplicación calcula céntimos enteros: cantidad × 250 + una tarifa de gestión de 100 céntimos. Usa AWS View en la parte superior para comparar las solicitudes con los datos almacenados.
Entra en el espacio de trabajo y lee la aplicación:
cd /home/labex/project
cat app.py
handler recibe el formato de carga útil HTTP 2.0. POST /orders espera exactamente dos campos JSON: un id en minúsculas de 2–40 caracteres que empieza con una letra y utiliza letras, dígitos o guiones, y un entero quantity de 1 a 10. El código rechaza otras estructuras antes de PutItem. GET /orders?id=... lee el registro almacenado con GetItem. Cada respuesta contiene un estado HTTP y un cuerpo JSON. No necesitas reescribir esta aplicación suministrada.
Lee el inventario de tablas preparado:
aws dynamodb list-tables --query TableNames
Espera labex-a02-orders y labex-a02-reference. Solo la tabla de pedidos pertenece al trabajo de negocio de esta API. Lee su ARN en una variable del shell:
TABLE_ARN=$(aws dynamodb describe-table \
--table-name labex-a02-orders \
--query Table.TableArn \
--output text)
echo "$TABLE_ARN"
El rol de ejecución controla el acceso saliente a la base de datos. Usa un here-document para crear un archivo de política. El marcador JSON sin comillas permite expandir $TABLE_ARN al ARN que acabas de leer; no contiene credenciales:
cat > orders-policy.json <<JSON
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["dynamodb:PutItem", "dynamodb:GetItem"],
"Resource": "$TABLE_ARN"
}]
}
JSON
Adjunta esta política insertada con nombre al rol de ejecución preparado:
aws iam put-role-policy \
--role-name labex-a02-execution \
--policy-name OrdersData \
--policy-document file://orders-policy.json
Empaqueta el código suministrado con app.py en la raíz del archivo:
zip orders.zip app.py
Lee el ARN del rol preparado:
ROLE_ARN=$(aws iam get-role \
--role-name labex-a02-execution \
--query Role.Arn \
--output text)
echo "$ROLE_ARN"
Despliega la función con un tiempo de espera de diez segundos. La aplicación lee TABLE_NAME de su entorno, manteniendo la selección de tabla separada del código fuente:
aws lambda create-function \
--function-name labex-a02-orders-api \
--runtime python3.12 \
--handler app.handler \
--role "$ROLE_ARN" \
--timeout 10 \
--environment '{"Variables":{"TABLE_NAME":"labex-a02-orders"}}' \
--zip-file fileb://orders.zip \
--query '{Name:FunctionName,Handler:Handler,Table:Environment.Variables.TABLE_NAME}'
Espera el nombre de función, app.handler y labex-a02-orders. En AWS View, inspecciona la tarjeta Function y confirma que la tabla de pedidos sigue teniendo cero elementos. Desplegar código y conceder acceso a datos no crea un pedido.
Asociar las rutas de salud y pedidos
En este paso, configurarás una integración para tres rutas y concederás a cada ruta permiso para invocar la función.
Crea una API HTTP y guarda su ID:
API_ID=$(aws apigatewayv2 create-api \
--name labex-a02 \
--protocol-type HTTP \
--query ApiId \
--output text)
echo "$API_ID"
printf '%s\n' "$API_ID" > api-id.txt
Crea la etapa literal $default con despliegue automático:
aws apigatewayv2 create-stage \
--api-id "$API_ID" \
--stage-name '$default' \
--auto-deploy \
--query '{Stage:StageName,AutoDeploy:AutoDeploy}'
Lee el ARN del backend y crea la integración de carga útil 2.0. Su método POST invoca Lambda; cada ruta del cliente sigue teniendo su propio método HTTP:
FUNCTION_ARN=$(aws lambda get-function-configuration \
--function-name labex-a02-orders-api \
--query FunctionArn \
--output text)
echo "$FUNCTION_ARN"
INTEGRATION_ID=$(aws apigatewayv2 create-integration \
--api-id "$API_ID" \
--integration-type AWS_PROXY \
--integration-method POST \
--integration-uri "$FUNCTION_ARN" \
--payload-format-version 2.0 \
--query IntegrationId \
--output text)
echo "$INTEGRATION_ID"
Asocia el endpoint público de salud a esta integración:
aws apigatewayv2 create-route \
--api-id "$API_ID" \
--route-key 'GET /health' \
--target "integrations/$INTEGRATION_ID" \
--authorization-type NONE \
--query RouteKey \
--output text
Asocia la ruta de escritura JSON:
aws apigatewayv2 create-route \
--api-id "$API_ID" \
--route-key 'POST /orders' \
--target "integrations/$INTEGRATION_ID" \
--authorization-type NONE \
--query RouteKey \
--output text
Asocia la ruta de lectura de pedidos almacenados:
aws apigatewayv2 create-route \
--api-id "$API_ID" \
--route-key 'GET /orders' \
--target "integrations/$INTEGRATION_ID" \
--authorization-type NONE \
--query RouteKey \
--output text
La política de base de datos del rol de ejecución no permite a API Gateway invocar la función. Lee el ID de cuenta y después añade tres concesiones precisas de invocación. Cada instrucción usa el ID de API, $default literal, el método del cliente y la ruta; \$ conserva el signo de dólar en una cadena expandida del shell:
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
echo "$ACCOUNT_ID"
aws lambda add-permission \
--function-name labex-a02-orders-api \
--statement-id ApiHealth \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-account "$ACCOUNT_ID" \
--source-arn "arn:aws:execute-api:us-east-1:$ACCOUNT_ID:$API_ID/\$default/GET/health" \
--query Statement \
--output text
aws lambda add-permission \
--function-name labex-a02-orders-api \
--statement-id ApiWriteOrder \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-account "$ACCOUNT_ID" \
--source-arn "arn:aws:execute-api:us-east-1:$ACCOUNT_ID:$API_ID/\$default/POST/orders" \
--query Statement \
--output text
aws lambda add-permission \
--function-name labex-a02-orders-api \
--statement-id ApiReadOrder \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-account "$ACCOUNT_ID" \
--source-arn "arn:aws:execute-api:us-east-1:$ACCOUNT_ID:$API_ID/\$default/GET/orders" \
--query Statement \
--output text
Construye la dirección de API preparada del espacio de trabajo con tu ID generado. Esta dirección atiende solicitudes dentro del espacio de trabajo y no es un nombre de host público de AWS:
API_URL="http://127.0.0.1:8081/api/$API_ID"
echo "$API_URL"
Prueba la ruta de salud. curl -i incluye las cabeceras de respuesta HTTP:
curl -i "$API_URL/health"
Espera HTTP 200 y {"healthy": true}. En AWS View, confirma que las tres claves de ruta tienen NONE, que la etapa tiene AutoDeploy habilitado y que la invocación de salud devolvió 200. La tabla de pedidos debe seguir vacía porque esta solicitud comprueba la salud en lugar de almacenar un pedido.

Probar pedidos válidos y solicitudes rechazadas
En este paso, crearás dos pedidos, leerás sus resultados almacenados y comprobarás los fallos antes de que puedan afectar a los datos de negocio.
Una solicitud HTTP consta de un método, una ruta, cabeceras y un cuerpo opcional. -X POST elige el método de escritura, -H proporciona Content-Type: application/json y --data envía la cadena JSON. Crea un pedido con cantidad 2:
curl -i -X POST "$API_URL/orders" -H 'Content-Type: application/json' --data '{"id":"order-one","quantity":2}'
Espera HTTP 201 Created y un cuerpo con order-one, cantidad 2 y total_cents: 600 (2 × 250 + 100). El estado indica al cliente que se almacenó un pedido; el cuerpo comunica el resultado calculado.
Crea un segundo pedido con una cantidad diferente:
curl -i -X POST "$API_URL/orders" -H 'Content-Type: application/json' --data '{"id":"order-two","quantity":5}'
Espera HTTP 201 y total_cents: 1350. Lee ambos pedidos mediante la API usando su parámetro de consulta:
curl -i "$API_URL/orders?id=order-one"
curl -i "$API_URL/orders?id=order-two"
Ambas respuestas deben ser HTTP 200 con el mismo ID, cantidad y total que la respuesta de creación correspondiente. El controlador de lectura recupera el estado de DynamoDB en lugar de recalcular el total a partir de una nueva cantidad del cliente.
Inspecciona de forma independiente el primer elemento almacenado con la CLI:
aws dynamodb get-item \
--table-name labex-a02-orders \
--key '{"id":{"S":"order-one"}}' \
--consistent-read \
--query Item
El elemento tipado contiene quantity: {"N":"2"} y total_cents: {"N":"600"}. En AWS View, compara los dos registros reales de la tabla con las respuestas de invocación POST y GET.
Una solicitud JSON sintácticamente válida puede incumplir el contrato de negocio. Envía una cantidad negativa:
curl -i -X POST "$API_URL/orders" -H 'Content-Type: application/json' --data '{"id":"bad-negative","quantity":-1}'
Espera HTTP 400 Bad Request y Use an id and an integer quantity from 1 to 10. También se rechaza un número codificado como cadena JSON:
curl -i -X POST "$API_URL/orders" -H 'Content-Type: application/json' --data '{"id":"bad-type","quantity":"2"}'
Por último, prueba un cuerpo JSON mal formado:
curl -i -X POST "$API_URL/orders" -H 'Content-Type: application/json' --data '{not-json'
Las dos últimas solicitudes también devuelven HTTP 400. Sus eventos reales de controlador pueden aparecer en CloudWatch Logs, pero la tabla debe seguir conteniendo únicamente los dos pedidos válidos. La validación de solicitudes ocurre en la aplicación suministrada antes de PutItem; una ruta de API coincidente por sí sola no valida su cuerpo.
Un ID válido de lectura puede referirse a un pedido no almacenado. Consulta uno que no se haya creado:
curl -i "$API_URL/orders?id=missing-order"
Espera HTTP 404 con Order not found. Esto difiere de una solicitud no válida 400: el ID tiene el formato esperado, pero no existe ningún elemento. Observa AWS View en la parte superior e inspecciona las respuestas reales 201, 200, 400 y 404; expande Show logs de una invocación para comparar su entrada con su resultado. Esta inspección manual de la interfaz complementa las comprobaciones independientes de solo lectura de registros remotos y ejecuciones reales.

Desplázate hasta la tarjeta de tablas de DynamoDB para comparar estos campos en tu entorno.
Estas respuestas 400 comprueban la validación de la aplicación: la solicitud llega a Lambda, que rechaza la entrada antes de escribir. El rechazo JWT posterior detiene la solicitud en API Gateway antes de Lambda. Compara el registro de ejecución y los elementos almacenados para identificar qué límite rechazó la solicitud.
Eliminar la API y los recursos de pedidos del laboratorio
En este paso, eliminarás los recursos de la API conservando la tabla de referencia ajena al laboratorio, los registros y el rol de ejecución preparado.
Tu inventario consta del ID de API de api-id.txt, labex-a02-orders-api, su grupo de registros /aws/lambda/labex-a02-orders-api, labex-a02-orders y la política insertada de rol OrdersData. Elimina primero la API, incluidas sus rutas, integración y etapa predeterminada:
aws apigatewayv2 delete-api --api-id "$API_ID"
Elimina la función y su política de invocación:
aws lambda delete-function --function-name labex-a02-orders-api
Elimina el grupo independiente de registros de la función:
aws logs delete-log-group --log-group-name /aws/lambda/labex-a02-orders-api
Elimina la tabla de pedidos del laboratorio y sus datos:
aws dynamodb delete-table \
--table-name labex-a02-orders \
--query TableDescription.TableName \
--output text
Elimina únicamente la política de datos que añadiste al rol preparado:
aws iam delete-role-policy --role-name labex-a02-execution --policy-name OrdersData
Lee correctamente los inventarios para demostrar la eliminación. Los errores de autenticación o red no son evidencia de eliminación:
aws apigatewayv2 get-apis --query 'Items[].Name'
aws lambda list-functions --query 'Functions[].FunctionName'
aws dynamodb list-tables --query TableNames
Las dos primeras listas deben estar vacías; la lista de tablas debe contener únicamente labex-a02-reference. Confirma que su elemento original permanece:
aws dynamodb get-item \
--table-name labex-a02-reference \
--key '{"id":{"S":"reference"}}' \
--query Item
Espera message: {"S":"keep unchanged"}. El rol debe conservar su política de registro ajena al trabajo del laboratorio:
aws iam list-role-policies --role-name labex-a02-execution --query PolicyNames
Espera únicamente FunctionLogs. En AWS View, la API, la función y los registros de invocación deben haber desaparecido, mientras permanecen la tabla de referencia e INFO platform reference keep unchanged. Conserva estos recursos preparados; las credenciales de prueba y el apagado de la VM se gestionan después de las comprobaciones de recursos.
Resumen
Conectaste tres rutas HTTP a una aplicación Lambda suministrada con una política precisa de base de datos y concesiones de invocación de la API. Creaste y recuperaste pedidos con distintos totales calculados, comprobaste registros reales de DynamoDB y distinguiste respuestas correctas, no válidas y de pedidos ausentes. Después eliminaste la API y sus datos, función, registros y política del laboratorio conservando los recursos de referencia.
Para ampliar este tema, consulta la referencia de AWS: Eventos Lambda de HTTP API y formatos de respuesta; Rutas HTTP API y parámetros de consulta.



