Введение
API службы поддержки должен находить открытые тикеты, а также безопасно создавать, изменять и удалять отдельные записи. Вы подключите Worker к D1, реализуете параметризованный доступ к SQL и проверите, как API обрабатывает отсутствующие записи и недопустимые входные данные.
HTTP-маршрутизатор уже предоставлен, поэтому основная задача — интеграция с базой данных. В этой независимой лабораторной работе используются один временный Worker и одна база данных D1, а также отдельные локальные данные.
Используйте собственную учебную учётную запись и новую виртуальную машину. На этапе настройки устанавливается Node.js 22.22.0, затем выполняется npm install для локального Wrangler 4.131.1 и всех зависимостей проверки в каталоге /home/labex/project/ticket-database. Версии прямых зависимостей зафиксированы; установка создаёт собственный lock-файл. На этапе настройки не выполняется вход в облако и не проводятся проверяемые операции с базой данных. На личном компьютере установите ту же версию Wrangler командой npm install --save-dev wrangler@4.131.1 в каталоге проекта.
В этом упражнении используются небольшие синтетические записи в пределах бесплатных лимитов D1. Текущее использование учётной записи также учитывается в этих лимитах. Покупать домен не требуется. Не удаляйте эту виртуальную машину, пока не проверите удаление ресурсов и выход из учётной записи.
Авторизуйте эту виртуальную машину и выберите учётную запись
На этом шаге вы подключите новый терминал к собственной учебной учётной записи. Одного входа в Dashboard недостаточно для авторизации виртуальной машины. Разрешение D1 позволяет создавать базы данных, изменять SQL и удалять базы данных; разрешение Workers позволяет выполнять развёртывание, а разрешение KV нужно Wrangler для инвентаризации при очистке. Перед авторизацией изучите фактическую страницу подтверждения, включая раздел Background Access.
Откройте подготовленный проект и проверьте зафиксированную версию CLI:
cd /home/labex/project/ticket-database
npx wrangler --version
Ожидаемый результат — 4.131.1. Запустите авторизацию устройства. Параметр --device выводит код для браузера, а --browser=false позволяет вам самостоятельно выбрать способ открытия браузера:
npx wrangler login --device --browser=false --scopes account:read user:read d1:write workers_scripts:write workers_kv:write
Откройте показанный URL в браузере, введите текущий код, подтвердите свою учебную учётную запись и разрешения, затем авторизуйте доступ. Дождитесь сообщения об успешной авторизации в терминале. Никогда не вставляйте пароли или токены в файлы проекта.
npx wrangler whoami --json
Проверьте значение loggedIn: true, затем прочитайте name и id учётной записи, даже если в списке указана только одна учётная запись. Скопируйте нужный идентификатор в конфигурацию ниже. Следующая переменная оболочки использует 6 случайных байтов (12 шестнадцатеричных символов), чтобы избежать совпадений с другими учащимися. Here-документ записывает JSON между строками JSON; переменная $RUN раскрывается внутри него.
Обратная косая черта перед $schema сохраняет этот ключ JSON буквально; $RUN по-прежнему подставляет уникальное имя текущего запуска.
RUN=labex-c04-d02-$(openssl rand -hex 6)
cat > wrangler.jsonc <<JSON
{
"\$schema": "./node_modules/wrangler/config-schema.json",
"name": "$RUN",
"account_id": "YOUR_ACCOUNT_ID",
"main": "src/index.js",
"compatibility_date": "2026-09-15",
"workers_dev": true,
"preview_urls": false
}
JSON
Замените YOUR_ACCOUNT_ID перед выполнением блока. Не закрывайте этот терминал, чтобы переменная RUN оставалась доступной. Поле name идентифицирует этот запуск, а account_id выбирает учётную запись для облачных операций. Этот файл представляет собой обычный JSON, который также является допустимым JSONC. Запись файла не развёртывает Worker.
Подготовьте независимые локальные и удалённые данные
На этом шаге вы создадите подключение к D1 и заполните знакомую таблицу тикетов начальными данными. Файл src/index.js уже содержит HTTP-маршрутизацию и проверку входных данных; отсутствующие функции работы с хранилищем находятся в src/store.js. Это позволяет сосредоточиться на доступе к SQL.
Создайте временную облачную базу данных. Параметр --binding DB задаёт короткое имя для кода приложения, --update-config записывает её настоящее имя и UUID в wrangler.jsonc, а --use-remote=false оставляет разработку локальной:
npx wrangler d1 create "$RUN-db" --binding DB --update-config --use-remote=false
Прочитайте созданные имя и идентификатор, затем проверьте сохранённую привязку:
cat wrangler.jsonc
Запись DB должна содержать имя базы данных этого запуска. Привязка — это настроенное соединение между кодом и ресурсом. Её UUID идентифицирует облачную базу данных, а параметр --local использует отдельную базу SQLite на этой виртуальной машине. В командах SQL всегда явно указывайте --local или --remote.
cat schema.sql
npx wrangler d1 execute DB --local --file schema.sql
npx wrangler d1 execute DB --remote --file schema.sql
Теперь в каждой среде находятся одни и те же два начальных тикета. DB — это имя, под которым предоставленный обработчик получает базу через env.DB; оно должно совпадать с привязкой в конфигурации.
Реализуйте параметризованные CRUD-операции
На этом шаге вы реализуете CRUD: создание, чтение, изменение и удаление. Подготовленный оператор отделяет структуру SQL от входных данных. Каждый символ ? — это заполнитель параметра; метод .bind(...) передаёт значения в указанном порядке. Никогда не объединяйте пользовательский ввод со строкой SQL, даже если он кажется безобидным.
Условие WHERE ограничивает изменяемые записи. Метод .all() возвращает объект результата, поле results которого содержит массив строк. Метод .first() возвращает одну строку или null. Конструкция SQLite RETURNING возвращает изменённую строку без отдельного запроса. Для удаления метод .run() предоставляет meta.changes, показывающее, существовала ли запись.
Создайте модуль хранилища:
cat > src/store.js <<'JS'
export async function list(db, status) {
const query = status === null
? db.prepare('SELECT id, subject, status, source FROM tickets ORDER BY id')
: db.prepare('SELECT id, subject, status, source FROM tickets WHERE status = ? ORDER BY id').bind(status);
const { results } = await query.all();
return results;
}
export async function get(db, id) {
return db.prepare('SELECT id, subject, status, source FROM tickets WHERE id = ?').bind(id).first();
}
export async function create(db, subject) {
return db.prepare("INSERT INTO tickets (subject, source) VALUES (?, 'api') RETURNING id, subject, status, source").bind(subject).first();
}
export async function update(db, id, status) {
return db.prepare('UPDATE tickets SET status = ? WHERE id = ? RETURNING id, subject, status, source').bind(status, id).first();
}
export async function remove(db, id) {
const result = await db.prepare('DELETE FROM tickets WHERE id = ?').bind(id).run();
return result.meta.changes === 1;
}
JS
Прочитайте src/index.js, чтобы увидеть, как предоставленная маршрутизация использует эти функции. Отсутствующие записи превращаются в контролируемый ответ 404, некорректные входные данные — в ответ 400, а перехваченная ошибка базы данных — в ответ 503 без раскрытия внутренних сведений о SQL.
Запустите локальный сервер как фоновую задачу, чтобы терминал оставался доступным:
npx wrangler dev --ip 0.0.0.0 > dev.log 2>&1 &
Прочитайте журнал запуска и дождитесь сообщения о начале прослушивания порта:
cat dev.log
curl -i http://localhost:8787/tickets?status=open
Ожидайте HTTP 200 и только тикет 1. Сервер использует локальную базу данных. Сохраните номер задания, который терминал покажет при запуске, — он понадобится для очистки.
Проверьте операции записи и отклонённые входные данные локально
На этом шаге вы проверите не только успешное чтение. curl -i показывает HTTP-статус и заголовки, -H задаёт тип содержимого JSON, а -d по умолчанию отправляет тело запроса вместе с POST.
Создайте тикет с текстом, содержащим похожую на SQL пунктуацию:
curl -i http://localhost:8787/tickets -H 'Content-Type: application/json' -d "{\"subject\":\"Printer ' OR 1=1 --\"}"
Ожидайте ответ 201 с сохранённым в виде данных значением subject. Скопируйте возвращённый числовой id в TICKET_ID ниже; не предполагайте, что идентификаторы останутся теми же после повторных проверок:
TICKET_ID=YOUR_RETURNED_ID
curl -i http://localhost:8787/tickets/$TICKET_ID
curl -i -X PATCH http://localhost:8787/tickets/$TICKET_ID -H 'Content-Type: application/json' -d '{"status":"closed"}'
curl -i -X DELETE http://localhost:8787/tickets/$TICKET_ID
curl -i http://localhost:8787/tickets/$TICKET_ID
Ожидайте ответ 200 при чтении, ответ 200 при изменении со значением closed, ответ 204 при удалении без тела, затем ответ 404 с {"error":"not_found"}. Исходные два тикета должны остаться без изменений.
Отправьте некорректный JSON и недопустимый статус:
curl -i http://localhost:8787/tickets -H 'Content-Type: application/json' -d '{'
curl -i -X PATCH http://localhost:8787/tickets/1 -H 'Content-Type: application/json' -d '{"status":"lost"}'
Ожидайте HTTP 400 со значениями invalid_json и invalid_status соответственно. Параметризация SQL не позволяет входным данным превратиться в SQL, а проверка приложения отклоняет значения, не соответствующие бизнес-правилам. Эти механизмы решают разные задачи.
Разверните приложение и проверьте привязанную базу данных
На этом шаге вы опубликуете обработчик и его привязку к D1. Удалённая база уже заполнена начальными данными; развёртывание не копирует локальные строки.
npx wrangler deploy
Скопируйте фактический URL https://...workers.dev, напечатанный после развёртывания, в переменную оболочки. Это временный синтетический API, поэтому после проверки удалите его:
URL='YOUR_DEPLOYED_HTTPS_URL'
curl -i "$URL/tickets?status=open"
Ожидайте ответ 200 и тикет 1. Если сразу после нового развёртывания временно появляется ошибка платформы, подождите несколько секунд и повторяйте этот запрос чтения не дольше одной минуты. Продолжайте только после совпадения и статуса, и JSON; постоянные ошибки требуют расследования.
Повторите CRUD-операции для удалённого API, скопировав собственный возвращённый идентификатор:
curl -i "$URL/tickets" -H 'Content-Type: application/json' -d '{"subject":"Remote test"}'
TICKET_ID=YOUR_RETURNED_ID
curl -i -X PATCH "$URL/tickets/$TICKET_ID" -H 'Content-Type: application/json' -d '{"status":"closed"}'
curl -i -X DELETE "$URL/tickets/$TICKET_ID"
curl -i "$URL/tickets/$TICKET_ID"
curl -i "$URL/tickets"
Ожидайте ответы 201, 200, 204, 404, а затем два неизменённых начальных тикета. В Dashboard откройте именно этот Worker и представление Bindings. Убедитесь, что DB указывает на вашу базу данных; перейдите по ссылке на базу для просмотра в режиме только чтения. Сохранённая локальная привязка не подтверждает, что развёрнутый Worker подключён к нужной базе.

В этом примере развёрнутый Worker подключён к своей базе D1 через DB. Случайный суффикс обозначает этот пример запуска; ваши имена будут отличаться. Ссылка Value в таблице открывает базу данных, выбранную развёрнутой привязкой.
Удалите временные ресурсы
На этом шаге вы удалите только ресурсы этой лабораторной работы, пока виртуальная машина ещё авторизована. Сначала завершите все функциональные проверки. Не удаляйте конфигурацию, пока не закончите проверку удаления.
npx wrangler delete
Убедитесь, что в конфигурации этого запуска указано только имя нужного Worker.
npx wrangler d1 delete DB
Изучите запрос подтверждения и убедитесь, что он относится только к базе данных этого запуска. Затем выведите список баз данных:
npx wrangler d1 list --json
Имя и UUID записанной вами базы данных должны отсутствовать в успешном ответе. Другие ресурсы могут остаться. Ошибка аутентификации или сети не даёт однозначного результата: восстановите доступ и повторите проверку перед продолжением. Выполните проверку этого шага, пока вы ещё вошли в систему.
Остановите также локальное задание разработки. Просмотрите список заданий и завершите только запущенное вами задание wrangler dev (если его номер отличается, замените %1):
jobs
kill %1
Завершите авторизацию этой виртуальной машины
На этом шаге завершите авторизацию только после успешной независимой проверки удаления. Выход удаляет сохранённые на этой виртуальной машине данные авторизации Wrangler; простое закрытие виртуальной машины не выполняет очистку облачных ресурсов.
npx wrangler logout
npx wrangler whoami --json
Ожидайте loggedIn: false. Этот неаутентифицированный запрос может завершиться с ненулевым кодом; это считается ожидаемым только в том случае, если структурированный ответ явно сообщает, что вы вышли из системы. После завершения проверки закройте среду лабораторной работы.
Резюме
Вы попрактиковались в добавлении поиска тикетов в Worker. Вы проверили наблюдаемые результаты работы с базой данных, явно зафиксировали выбранную учётную запись и локальное состояние, а затем удалили временные ресурсы перед выходом из системы.



