← Cloudflare Workers / workers / tutorials
Развертывание приложения Express.js на Cloudflare Workers
В этом руководстве вы узнаете, как развернуть Express.js ↗ приложение в Cloudflare Workers с помощью Платформа Cloudflare Workers и База данных D1. Вы создадите Members Registry API с базовыми операциями Create, Read, Update и Delete (CRUD). В качестве базы данных для хранения и получения данных участников будет использоваться D1.
Прежде чем начать
Во всех руководствах предполагается, что вы уже выполнили Руководство по началу работы, который поможет вам настроить аккаунт Cloudflare Workers, C3 ↗, а также Wrangler.
быстрый старт
Если вы хотите пропустить шаги и быстро начать, выберите Deploy to Cloudflare ниже.
Это создаёт репозиторий в вашем аккаунте GitHub и разворачивает приложение в Cloudflare Workers. Выберите этот вариант, если вы уже знакомы с Cloudflare Workers и хотите пропустить пошаговые инструкции.
Если вы только начинаете работать с Cloudflare Workers, можете пройти все шаги вручную.
1. Создайте новый проект Cloudflare Workers
Используйте C3 ↗, интерфейс командной строки для инструментов разработчика Cloudflare, чтобы создать новый каталог и инициализировать новый проект Worker:
npm create cloudflare@latest -- express-d1-appДля настройки выберите следующие параметры:
- Для С чего вы хотите начать?, выберите
Hello World example. - Для Какой шаблон вы хотите использовать?, выберите
Worker only. - Для Какой язык вы хотите использовать?, выберите
TypeScript. - Для Хотите использовать git для контроля версий?, выберите
Yes. - Для Хотите развернуть приложение?, выберите
No(мы внесём некоторые изменения перед развёртыванием).
Перейдите в каталог нового проекта:
cd express-d1-app2. Установка Express и зависимостей
В этом руководстве вы будете использовать Express.js ↗, популярный веб-фреймворк для Node.js. Чтобы использовать Express в среде Cloudflare Workers, установите Express вместе с необходимыми типами TypeScript:
npm i express @types/expressДля Express.js на Cloudflare Workers требуется nodejs_compat флаг совместимости. Этот флаг включает API Node.js и позволяет запускать Express в среде выполнения Workers. Добавьте следующее в файл конфигурации Wrangler:
{
"compatibility_flags": [
"nodejs_compat"
]
}compatibility_flags = [ "nodejs_compat" ]3. Создание базы данных D1
Теперь вы создадите базу данных D1 для хранения информации об участниках. Используйте wrangler d1 create команду, чтобы создать новую базу данных:
npx wrangler d1 create members-dbКоманда создаст новую базу данных D1 и задаст вам следующие вопросы:
- Добавить это от вашего имени с помощью Wrangler?: Тип
Y. - Какое имя привязки вы хотите использовать?: Тип
DBи нажмите Enter. - Для локальной разработки вы хотите подключаться к удалённому ресурсу вместо локального?: Тип
N.
⛅️ wrangler 4.44.0
───────────────────
✅ Successfully created DB 'members-db' in region WNAM
Created your new D1 database.
To access your new D1 Database in your Worker, add the following snippet to your configuration file:
{
"d1_databases": [
{
"binding": "members_db",
"database_name": "members-db",
"database_id": "<unique-ID-for-your-database>"
}
]
}
✔ Would you like Wrangler to add it on your behalf? … yes
✔ What binding name would you like to use? … DB
✔ For local dev, do you want to connect to the remote resource instead of a local resource? … noПривязка будет добавлена в ваш файл конфигурации Wrangler.
{
"d1_databases": [
{
"binding": "DB",
"database_name": "members-db",
"database_id": "<unique-ID-for-your-database>"
}
]
}[[d1_databases]]
binding = "DB"
database_name = "members-db"
database_id = "<unique-ID-for-your-database>"4. Создайте схему базы данных
Создайте каталог с именем schemas в корне вашего проекта, а внутри него создайте файл с именем schema.sql:
DROP TABLE IF EXISTS members;
CREATE TABLE IF NOT EXISTS members (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
joined_date TEXT NOT NULL
);
-- Insert sample data
INSERT INTO members (name, email, joined_date) VALUES
('Alice Johnson', '[email protected]', '2024-01-15'),
('Bob Smith', '[email protected]', '2024-02-20'),
('Carol Williams', '[email protected]', '2024-03-10');Эта схема создает members таблицу с полями автоинкрементного ID, имени, email и даты регистрации, а также добавляет трех тестовых участников.
Выполните файл схемы в вашей базе данных D1:
npx wrangler d1 execute members-db --file=./schemas/schema.sqlЭта команда создаёт таблицу в вашей локальной базе данных для разработки. Схему вы развернёте в продакшене позже.
5. Инициализируйте приложение Express
Обновите ваш src/index.ts файл, чтобы настроить Express с TypeScript. Замените содержимое файла следующим:
import { env } from "cloudflare:workers";
import { httpServerHandler } from "cloudflare:node";
import express from "express";
const app = express();
// Middleware to parse JSON bodies
app.use(express.json());
// Health check endpoint
app.get("/", (req, res) => {
res.json({ message: "Express.js running on Cloudflare Workers!" });
});
app.listen(3000);
export default httpServerHandler({ port: 3000 });Этот код инициализирует Express и создаёт базовую конечную точку проверки работоспособности. Ключевой импорт import { env } from "cloudflare:workers" позволяет получить доступ к привязки например, вашу базу данных D1, из любого места в коде. httpServerHandler интегрирует Express со средой выполнения Workers, позволяя приложению обрабатывать HTTP-запросы в сети Cloudflare.
Затем выполните команду typegen, чтобы сгенерировать определения типов для окружения Worker:
npm run cf-typegen6. Реализуйте операции чтения
Добавьте endpoints для получения участников из базы данных. Обновите свой src/index.ts файл, добавив следующие маршруты после эндпоинта проверки работоспособности:
// GET all members
app.get('/api/members', async (req, res) => {
try {
const { results } = await env.DB.prepare('SELECT * FROM members ORDER BY joined_date DESC').all();
res.json({ success: true, members: results });
} catch (error) {
res.status(500).json({ success: false, error: 'Failed to fetch members' });
}
});
// GET a single member by ID
app.get('/api/members/:id', async (req, res) => {
try {
const { id } = req.params;
const { results } = await env.DB.prepare('SELECT * FROM members WHERE id = ?').bind(id).all();
if (results.length === 0) {
return res.status(404).json({ success: false, error: 'Member not found' });
}
res.json({ success: true, member: results[0] });
} catch (error) {
res.status(500).json({ success: false, error: 'Failed to fetch member' });
}
});Эти маршруты используют привязку (binding) D1 (env.DB) для подготовки SQL-выражений и их выполнения. Поскольку вы импортировали env от cloudflare:workers в верхней части файла, оно доступно во всём приложении. prepare, bind, а также all методы привязки D1 позволяют безопасно выполнять запросы к базе данных. См. D1 Workers Binding API для получения списка всех доступных методов.
7. Реализуйте операцию создания
Добавьте endpoint для создания новых участников. Добавьте следующий маршрут в src/index.ts файле:
// POST - Create a new member
app.post("/api/members", async (req, res) => {
try {
const { name, email } = req.body;
// Validate input
if (!name || !email) {
return res.status(400).json({
success: false,
error: "Name and email are required",
});
}
// Basic email validation (simplified for tutorial purposes)
// For production, consider using a validation library or more comprehensive checks
if (!email.includes("@") || !email.includes(".")) {
return res.status(400).json({
success: false,
error: "Invalid email format",
});
}
const joined_date = new Date().toISOString().split("T")[0];
const result = await env.DB.prepare(
"INSERT INTO members (name, email, joined_date) VALUES (?, ?, ?)"
)
.bind(name, email, joined_date)
.run();
if (result.success) {
res.status(201).json({
success: true,
message: "Member created successfully",
id: result.meta.last_row_id,
});
} else {
res
.status(500)
.json({ success: false, error: "Failed to create member" });
}
} catch (error: any) {
// Handle unique constraint violation
if (error.message?.includes("UNIQUE constraint failed")) {
return res.status(409).json({
success: false,
error: "Email already exists",
});
}
res.status(500).json({ success: false, error: "Failed to create member" });
}
});Эта конечная точка проверяет входные данные, формат email и добавляет нового участника в базу данных. Также она обрабатывает дублирующиеся адреса email, проверяя нарушения ограничения уникальности.
8. Реализуйте операцию обновления
Добавьте endpoint для обновления существующих участников. Добавьте следующий маршрут в src/index.ts файле:
app.put("/api/members/:id", async (req, res) => {
try {
const { id } = req.params;
const { name, email } = req.body;
// Validate input
if (!name && !email) {
return res.status(400).json({
success: false,
error: "At least one field (name or email) is required",
});
}
// Basic email validation if provided (simplified for tutorial purposes)
// For production, consider using a validation library or more comprehensive checks
if (email && (!email.includes("@") || !email.includes("."))) {
return res.status(400).json({
success: false,
error: "Invalid email format",
});
}
// Build dynamic update query
const updates: string[] = [];
const values: any[] = [];
if (name) {
updates.push("name = ?");
values.push(name);
}
if (email) {
updates.push("email = ?");
values.push(email);
}
values.push(id);
const result = await env.DB.prepare(
`UPDATE members SET ${updates.join(", ")} WHERE id = ?`
)
.bind(...values)
.run();
if (result.meta.changes === 0) {
return res
.status(404)
.json({ success: false, error: "Member not found" });
}
res.json({ success: true, message: "Member updated successfully" });
} catch (error: any) {
if (error.message?.includes("UNIQUE constraint failed")) {
return res.status(409).json({
success: false,
error: "Email already exists",
});
}
res.status(500).json({ success: false, error: "Failed to update member" });
}
});Эта конечная точка позволяет обновить у существующего участника поле имени, email или оба поля сразу. Она формирует динамический SQL-запрос на основе переданных полей.
9. Реализуйте операцию удаления
Добавьте endpoint для удаления участников. Добавьте следующий маршрут в src/index.ts файле:
// DELETE - Delete a member
app.delete("/api/members/:id", async (req, res) => {
try {
const { id } = req.params;
const result = await env.DB.prepare("DELETE FROM members WHERE id = ?")
.bind(id)
.run();
if (result.meta.changes === 0) {
return res
.status(404)
.json({ success: false, error: "Member not found" });
}
res.json({ success: true, message: "Member deleted successfully" });
} catch (error) {
res.status(500).json({ success: false, error: "Failed to delete member" });
}
});Эта конечная точка удаляет участника по его ID и возвращает ошибку, если участник не найден.
10. Локальное тестирование
Запустите сервер разработки, чтобы протестировать API локально:
npm run devСервер разработки запустится, и вы сможете обратиться к своему API по адресу http://localhost:8787.
Откройте новое окно терминала и протестируйте эндпоинты с помощью curl:
curl http://localhost:8787/api/members{
"success": true,
"members": [
{
"id": 1,
"name": "Alice Johnson",
"email": "[email protected]",
"joined_date": "2024-01-15"
},
{
"id": 2,
"name": "Bob Smith",
"email": "[email protected]",
"joined_date": "2024-02-20"
},
{
"id": 3,
"name": "Carol Williams",
"email": "[email protected]",
"joined_date": "2024-03-10"
}
]
}Проверка создания нового участника:
curl -X POST http://localhost:8787/api/members \
-H "Content-Type: application/json" \
-d '{"name": "David Brown", "email": "[email protected]"}'{
"success": true,
"message": "Member created successfully",
"id": 4
}Проверка получения одного участника:
curl http://localhost:8787/api/members/1Проверка обновления участника:
curl -X PUT http://localhost:8787/api/members/1 \
-H "Content-Type: application/json" \
-d '{"name": "Alice Cooper"}'Проверка удаления участника:
curl -X DELETE http://localhost:8787/api/members/411. Развёртывание в Cloudflare Workers
Перед развёртыванием в продакшене выполните файл схемы для удалённой (продакшен) базы данных:
npx wrangler d1 execute members-db --remote --file=./schemas/schema.sqlТеперь разверните приложение в сети Cloudflare:
npm run deploy⛅️ wrangler 4.44.0
───────────────────
Total Upload: 1743.64 KiB / gzip: 498.65 KiB
Worker Startup Time: 48 ms
Your Worker has access to the following bindings:
Binding Resource
env.DB (members-db) D1 Database
Uploaded express-d1-app (2.99 sec)
Deployed express-d1-app triggers (5.26 sec)
https://<your-subdomain>.workers.dev
Current Version ID: <version-id>После успешного развёртывания Wrangler выведет URL вашего Worker.
12. Тестирование продакшен-развёртывания
Протестируйте развёрнутый API с помощью предоставленного URL. Замените <your-worker-url> на фактический URL вашего Worker:
curl https://<your-worker-url>/api/membersВы должны увидеть те же данные участников, которые вы создали в продакшен базе данных.
Создайте нового участника в продакшене:
curl -X POST https://<your-worker-url>/api/members \
-H "Content-Type: application/json" \
-d '{"name": "Eva Martinez", "email": "[email protected]"}'Ваше приложение Express.js с базой данных D1 теперь работает на Cloudflare Workers.
Заключение
В этом руководстве вы создали Members Registry API с помощью Express.js и базы данных D1, а затем развернули его в Cloudflare Workers. Вы реализовали полный набор операций CRUD (Create, Read, Update, Delete) и научились:
- Настройка приложения Express.js для Cloudflare Workers
- Создание и настройка базы данных D1 с привязками
- Реализация операций с базой данных с помощью подготовленных выражений D1
- Тестируйте API локально и в продакшене
Следующие шаги
- Подробнее о Возможности базы данных D1
- Изучите Маршрутизация и промежуточное ПО Workers
- Добавьте аутентификацию к своему API с помощью аутентификация Workers
- Реализация пагинации для больших наборов данных с помощью Оптимизация запросов D1