Введение
Команде заказов нужно принимать заказы JSON и возвращать рассчитанные суммы. Вы подключите маршруты состояния, записи и чтения к предоставленному приложению Lambda, проверите допустимые и отклонённые запросы и изучите сохранённые записи DynamoDB перед очисткой.
Сначала выполните Предоставление доступа к функции Lambda через HTTP API и Чтение и запись DynamoDB из Lambda. Эта свежая среда предоставляет приложение, роль и отдельные таблицы.
Связь с сертификацией
| Сертификация | Задача экзамена | Практика |
|---|---|---|
| Solutions Architect – Associate (SAA-C03) | Задача 2.1 | Проверка запросов API, ответы и сохранённые бизнес-данные. |
| Developer – Associate (DVA-C02) | Задача 1.1, Задача 3.2 | Проверка запросов API, ответы и сохранённые бизнес-данные. |
| DevOps Engineer – Professional (DOP-C02) | Задача 3.2 | Базовая практика: Проверка запросов API, ответы и сохранённые бизнес-данные. |
Обзор лабораторной работы

Подготовьте серверную часть заказов
На этом шаге вы изучите предоставленный контракт запросов, дадите функции доступ к её таблице заказов и развернёте серверную часть. Приложение вычисляет целое число центов: quantity × 250 + сбор за обработку в 100 центов. Используйте AWS View вверху для сравнения запросов с сохранёнными данными.
Перейдите в рабочую папку и прочитайте приложение:
cd /home/labex/project
cat app.py
handler получает формат полезной нагрузки HTTP 2.0. POST /orders ожидает ровно два поля JSON: id в нижнем регистре длиной 2–40 символов, начинающийся с буквы и содержащий буквы, цифры или дефисы, и целое quantity от 1 до 10. Код отклоняет другие формы данных перед PutItem. GET /orders?id=... читает сохранённую запись через GetItem. Каждый ответ содержит HTTP-статус и тело JSON. Переписывать предоставленное приложение не нужно.
Прочитайте список подготовленных таблиц:
aws dynamodb list-tables --query TableNames
Ожидайте labex-a02-orders и labex-a02-reference. Только таблица заказов относится к бизнес-операциям этого API. Прочитайте её ARN в переменную оболочки:
TABLE_ARN=$(aws dynamodb describe-table \
--table-name labex-a02-orders \
--query Table.TableArn \
--output text)
echo "$TABLE_ARN"
Роль выполнения управляет исходящим доступом к базе данных. Создайте файл политики с помощью here-document. Маркер JSON без кавычек позволяет подставить в $TABLE_ARN только что прочитанный ARN; он не содержит учётных данных:
cat > orders-policy.json <<JSON
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["dynamodb:PutItem", "dynamodb:GetItem"],
"Resource": "$TABLE_ARN"
}]
}
JSON
Прикрепите эту именованную встроенную политику к подготовленной роли выполнения:
aws iam put-role-policy \
--role-name labex-a02-execution \
--policy-name OrdersData \
--policy-document file://orders-policy.json
Упакуйте предоставленный код, поместив app.py в корень архива:
zip orders.zip app.py
Прочитайте ARN подготовленной роли:
ROLE_ARN=$(aws iam get-role \
--role-name labex-a02-execution \
--query Role.Arn \
--output text)
echo "$ROLE_ARN"
Разверните функцию с десятисекундным тайм-аутом. Приложение читает TABLE_NAME из своей среды, отделяя выбор таблицы от исходного кода:
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}'
Ожидайте имя функции, app.handler и labex-a02-orders. В AWS View изучите карточку Function и подтвердите, что таблица заказов всё ещё содержит ноль элементов. Развёртывание кода и предоставление доступа к данным не создают заказ.
Сопоставьте маршруты состояния и заказов
На этом шаге вы настроите одну интеграцию для трёх маршрутов и дадите каждому маршруту разрешение вызова функции.
Создайте HTTP API и сохраните его идентификатор:
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
Создайте стадию с буквальным именем $default и автоматическим развёртыванием:
aws apigatewayv2 create-stage \
--api-id "$API_ID" \
--stage-name '$default' \
--auto-deploy \
--query '{Stage:StageName,AutoDeploy:AutoDeploy}'
Прочитайте ARN серверной части и создайте интеграцию с payload 2.0. Её метод POST вызывает Lambda; каждый клиентский маршрут по-прежнему имеет собственный 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"
Сопоставьте общедоступную конечную точку состояния с этой интеграцией:
aws apigatewayv2 create-route \
--api-id "$API_ID" \
--route-key 'GET /health' \
--target "integrations/$INTEGRATION_ID" \
--authorization-type NONE \
--query RouteKey \
--output text
Сопоставьте маршрут записи JSON:
aws apigatewayv2 create-route \
--api-id "$API_ID" \
--route-key 'POST /orders' \
--target "integrations/$INTEGRATION_ID" \
--authorization-type NONE \
--query RouteKey \
--output text
Сопоставьте маршрут чтения сохранённого заказа:
aws apigatewayv2 create-route \
--api-id "$API_ID" \
--route-key 'GET /orders' \
--target "integrations/$INTEGRATION_ID" \
--authorization-type NONE \
--query RouteKey \
--output text
Политика базы данных роли выполнения не позволяет API Gateway вызывать функцию. Прочитайте идентификатор аккаунта, затем добавьте три точных разрешения вызова. Каждая инструкция использует идентификатор API, буквальное $default, метод клиента и путь маршрута; \$ сохраняет знак доллара в строке оболочки с подстановками:
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
Сформируйте подготовленный адрес API рабочей среды со своим сгенерированным идентификатором. Этот адрес обслуживает запросы внутри рабочей среды и не является публичным именем хоста AWS:
API_URL="http://127.0.0.1:8081/api/$API_ID"
echo "$API_URL"
Проверьте маршрут состояния. curl -i включает заголовки HTTP-ответа:
curl -i "$API_URL/health"
Ожидайте HTTP 200 и {"healthy": true}. В AWS View подтвердите, что все три ключа маршрутов имеют NONE, у стадии включено AutoDeploy, а вызов состояния вернул 200. Таблица заказов всё ещё должна быть пустой, поскольку этот запрос проверяет состояние, а не сохраняет заказ.

Проверьте допустимые заказы и отклонённые запросы
На этом шаге вы создадите два заказа, прочитаете их сохранённые результаты и проверите сбои до того, как они смогут повлиять на бизнес-данные.
HTTP-запрос состоит из метода, пути, заголовков и необязательного тела. -X POST выбирает метод записи, -H задаёт Content-Type: application/json, а --data отправляет строку JSON. Создайте заказ с количеством 2:
curl -i -X POST "$API_URL/orders" -H 'Content-Type: application/json' --data '{"id":"order-one","quantity":2}'
Ожидайте HTTP 201 Created и тело, содержащее order-one, quantity 2 и total_cents: 600 (2 × 250 + 100). Статус сообщает клиенту, что заказ сохранён; тело сообщает вычисленный результат.
Создайте второй заказ с другим количеством:
curl -i -X POST "$API_URL/orders" -H 'Content-Type: application/json' --data '{"id":"order-two","quantity":5}'
Ожидайте HTTP 201 и total_cents: 1350. Прочитайте оба заказа через API, используя их параметр запроса:
curl -i "$API_URL/orders?id=order-one"
curl -i "$API_URL/orders?id=order-two"
Оба ответа должны быть HTTP 200 с теми же ID, количеством и суммой, что и соответствующий ответ создания. Обработчик чтения получает состояние DynamoDB, а не пересчитывает сумму по новому количеству клиента.
Независимо изучите первый сохранённый элемент через CLI:
aws dynamodb get-item \
--table-name labex-a02-orders \
--key '{"id":{"S":"order-one"}}' \
--consistent-read \
--query Item
Типизированный элемент содержит quantity: {"N":"2"} и total_cents: {"N":"600"}. В AWS View сравните две фактические записи таблицы с ответами вызовов POST и GET.
Синтаксически допустимый запрос JSON всё же может нарушать бизнес-контракт. Отправьте отрицательное количество:
curl -i -X POST "$API_URL/orders" -H 'Content-Type: application/json' --data '{"id":"bad-negative","quantity":-1}'
Ожидайте HTTP 400 Bad Request и Use an id and an integer quantity from 1 to 10. Число, закодированное как строка JSON, также отклоняется:
curl -i -X POST "$API_URL/orders" -H 'Content-Type: application/json' --data '{"id":"bad-type","quantity":"2"}'
В завершение проверьте тело с неверным синтаксисом JSON:
curl -i -X POST "$API_URL/orders" -H 'Content-Type: application/json' --data '{not-json'
Последние два запроса также возвращают HTTP 400. Их фактические события обработчика могут появиться в CloudWatch Logs, но таблица по-прежнему должна содержать только два допустимых заказа. Проверка запросов происходит в предоставленном приложении перед PutItem; один соответствующий маршрут API не проверяет тело.
Допустимый ID чтения может не иметь сохранённого заказа. Запросите тот, который ещё не создан:
curl -i "$API_URL/orders?id=missing-order"
Ожидайте HTTP 404 с Order not found. Это отличается от неверного запроса 400: ID имеет ожидаемый формат, но элемента нет. Посмотрите на AWS View вверху и изучите фактические ответы 201, 200, 400 и 404; разверните Show logs вызова для сравнения входных данных с результатом. Это ручное изучение интерфейса дополняет независимые проверки удалённых записей и фактических выполнений только для чтения.

Прокрутите вниз до карточки таблиц DynamoDB, чтобы сравнить эти поля в своей среде.
Эти ответы 400 проверяют валидацию приложения: запрос достигает Lambda, которая отклоняет ввод до записи. Изучаемый далее отказ JWT останавливает запрос в API Gateway до Lambda. Сопоставьте журнал выполнения и сохранённые элементы, чтобы определить границу отказа.
Удалите API и ресурсы заказов работы
На этом шаге вы удалите ресурсы API, сохранив независимую эталонную таблицу, журналы и подготовленную роль выполнения.
Ваш список ресурсов состоит из идентификатора API в api-id.txt, labex-a02-orders-api, его группы журналов /aws/lambda/labex-a02-orders-api, labex-a02-orders и встроенной политики роли OrdersData. Сначала удалите API, включая его маршруты, интеграцию и стадию по умолчанию:
aws apigatewayv2 delete-api --api-id "$API_ID"
Удалите функцию и её политику вызова:
aws lambda delete-function --function-name labex-a02-orders-api
Удалите отдельную группу журналов функции:
aws logs delete-log-group --log-group-name /aws/lambda/labex-a02-orders-api
Удалите таблицу заказов работы и её данные:
aws dynamodb delete-table \
--table-name labex-a02-orders \
--query TableDescription.TableName \
--output text
Удалите только политику данных, добавленную к подготовленной роли:
aws iam delete-role-policy --role-name labex-a02-execution --policy-name OrdersData
Успешно прочитайте списки для доказательства удаления. Ошибки аутентификации или сети не являются доказательством удаления:
aws apigatewayv2 get-apis --query 'Items[].Name'
aws lambda list-functions --query 'Functions[].FunctionName'
aws dynamodb list-tables --query TableNames
Первые два списка должны быть пустыми; список таблиц должен содержать только labex-a02-reference. Подтвердите сохранность её исходного элемента:
aws dynamodb get-item \
--table-name labex-a02-reference \
--key '{"id":{"S":"reference"}}' \
--query Item
Ожидайте message: {"S":"keep unchanged"}. Роль по-прежнему должна сохранять независимую политику журналов:
aws iam list-role-policies --role-name labex-a02-execution --query PolicyNames
Ожидайте только FunctionLogs. В AWS View записи API, Function и вызовов должны исчезнуть, а эталонная таблица и INFO platform reference keep unchanged — сохраниться. Оставьте эти подготовленные ресурсы; тестовые учётные данные и выключение VM обрабатываются после проверки ресурсов.
Резюме
Вы подключили три HTTP-маршрута к предоставленному приложению Lambda с точной политикой базы данных и разрешениями вызова API. Вы создали и получили заказы с разными вычисленными суммами, проверили фактические записи DynamoDB и различили успешные ответы, неверные запросы и отсутствие заказа. Затем вы удалили API и его данные, функцию, журналы и политику работы, сохранив эталонные ресурсы.
Подробнее см. в документации AWS: События Lambda HTTP API и форматы ответов; Маршруты HTTP API и параметры запроса.



