תיעוד 207
פריסת יישום Express.js על Cloudflare Workers
במדריך הזה תלמדו איך לפרוס יישום Express.js ↗︎ על Cloudflare Workers באמצעות פלטפורמת Cloudflare Workers ומסד הנתונים D1. תבנו API של רישום חברים עם פעולות בסיסיות של יצירה, קריאה, עדכון ומחיקה (CRUD). תשתמשו ב-D1 כמסד הנתונים לאחסון ולשליפה של נתוני חברים.
#לפני שמתחילים
כל המדריכים מניחים שכבר השלמתם את מדריך תחילת העבודה, שמגדיר עבורכם חשבון Cloudflare Workers, את C3 ↗︎ ואת Wrangler.
#התחלה מהירה
אם אתם רוצים לדלג על השלבים ולהתחיל במהירות, בחרו Deploy to Cloudflare למטה.
הפעולה הזו יוצרת מאגר בחשבון GitHub שלכם ופורסת את היישום ל-Cloudflare Workers. השתמשו באפשרות הזו אם אתם מכירים את Cloudflare Workers ורוצים לדלג על ההדרכה שלב אחר שלב.
ייתכן שתרצו לעקוב אחרי השלבים באופן ידני אם אתם חדשים ב-Cloudflare Workers.
#1. יצירת פרויקט Cloudflare Workers חדש
השתמשו ב-C3 ↗︎, כלי שורת הפקודה למוצרי המפתחים של Cloudflare, כדי ליצור ספרייה חדשה ולאתחל פרויקט Worker חדש:
npm:
npm create cloudflare@latest -- express-d1-appyarn:
yarn create cloudflare express-d1-apppnpm:
pnpm create cloudflare@latest express-d1-appבהגדרה, בחרו את האפשרויות הבאות:
- עבור What would you like to start with?, בחרו
Hello World example. - עבור Which template would you like to use?, בחרו
Worker only. - עבור Which language do you want to use?, בחרו
TypeScript. - עבור Do you want to use git for version control?, בחרו
Yes. - עבור Do you want to add an AGENTS.md file to help AI coding tools understand Cloudflare APIs?, בחרו
Yes. - עבור Do you want to deploy your application?, בחרו
No(נבצע כמה שינויים לפני הפריסה).
עברו לספריית הפרויקט החדשה:
cd express-d1-app#2. התקנת Express ותלויות
במדריך הזה תשתמשו ב-Express.js ↗︎, מסגרת אינטרנט נפוצה ל-Node.js. כדי להשתמש ב-Express בסביבת Cloudflare Workers, התקינו את Express יחד עם טיפוסי TypeScript הנדרשים:
npm:
npm i express @types/expressyarn:
yarn add express @types/expresspnpm:
pnpm add express @types/expressbun:
bun add express @types/expressExpress.js על Cloudflare Workers דורש את דגל התאימות nodejs_compat. הדגל הזה מפעיל ממשקי 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 חדש ותשאל את השאלות הבאות:
- Would you like Wrangler to add it on your behalf?: הקלידו
Y. - What binding name would you like to use?: הקלידו
DBולחצו Enter. - For local dev, do you want to connect to the remote resource instead of a local resource?: הקלידו
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ה-binding יתווסף לקובץ התצורה של 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:
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 עם מזהה שגדל אוטומטית, שם, דוא"ל ותאריך הצטרפות. היא גם מוסיפה שלושה חברים לדוגמה.
הריצו את קובץ הסכמה מול מסד הנתונים D1:
npx wrangler d1 execute members-db --file=./schemas/schema.sqlהפקודה למעלה יוצרת את הטבלה במסד הנתונים המקומי לפיתוח. תפרסו את הסכמה לייצור בהמשך.
#5. אתחול יישום Express
עדכנו את הקובץ src/index.ts כדי להגדיר את Express עם TypeScript. החליפו את תוכן הקובץ בקטע הבא:
src/index.ts
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" מאפשר לגשת ל-bindings כמו מסד הנתונים D1 מכל מקום בקוד. ה-httpServerHandler משלב את Express עם סביבת הריצה של Workers, ומאפשר ליישום לטפל בבקשות HTTP ברשת של Cloudflare.
לאחר מכן, הריצו את פקודת typegen כדי לייצר הגדרות טיפוסים לסביבת ה-Worker:
npm run cf-typegen#6. מימוש פעולות קריאה
הוסיפו נקודות קצה לשליפת חברים ממסד הנתונים. עדכנו את הקובץ src/index.ts על ידי הוספת הנתיבים הבאים אחרי נקודת הקצה לבדיקת תקינות:
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 על ה-binding של D1 מאפשרות לשלוח שאילתות למסד הנתונים בצורה בטוחה. עיינו ב-D1 Workers Binding API לכל המתודות הזמינות.
#7. מימוש פעולת יצירה
הוסיפו נקודת קצה ליצירת חברים חדשים. הוסיפו את הנתיב הבא לקובץ src/index.ts:
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" });
}
});נקודת הקצה הזו מאמתת את הקלט, בודקת את פורמט הדוא"ל ומוסיפה חבר חדש למסד הנתונים. היא גם מטפלת בכתובות דוא"ל כפולות על ידי בדיקת הפרות של אילוץ ייחודיות.
#8. מימוש פעולת עדכון
הוסיפו נקודת קצה לעדכון חברים קיימים. הוסיפו את הנתיב הבא לקובץ src/index.ts:
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" });
}
});נקודת הקצה הזו מאפשרת לעדכן את השם, את הדוא"ל, או את שני השדות של חבר קיים. היא בונה שאילתת SQL דינמית לפי השדות שסופקו.
#9. מימוש פעולת מחיקה
הוסיפו נקודת קצה למחיקת חברים. הוסיפו את הנתיב הבא לקובץ src/index.ts:
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" });
}
});נקודת הקצה הזו מוחקת חבר לפי המזהה שלו ומחזירה שגיאה אם החבר לא קיים.
#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/4#11. פריסה ל-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:
בדיקת ה-API בייצור
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.
#סיכום
במדריך הזה בניתם API של רישום חברים באמצעות Express.js ומסד הנתונים D1, ואז פרסתם אותו ל-Cloudflare Workers. מימשתם פעולות CRUD מלאות (יצירה, קריאה, עדכון, מחיקה) ולמדתם איך:
- להגדיר יישום Express.js עבור Cloudflare Workers
- ליצור ולהגדיר מסד נתונים D1 עם bindings
- לממש פעולות מסד נתונים באמצעות משפטים מוכנים של D1
- לבדוק את ה-API באופן מקומי ובייצור
#השלבים הבאים
- למדו עוד על יכולות מסד הנתונים D1
- עיינו ב-ניתוב ו-middleware של Workers
- הוסיפו אימות ל-API באמצעות אימות Workers
- ממשו עימוד למערכי נתונים גדולים באמצעות אופטימיזציית שאילתות D1