ยกระดับ Express.js ด้วย TypeScript เพื่อความปลอดภัยของประเภท ครอบคลุมการกำหนด Route Handler, Middleware และแนวทางปฏิบัติที่ดีที่สุดสำหรับการสร้าง API ที่ปรับขนาดและดูแลรักษาง่าย
การผสาน TypeScript กับ Express: การรับประกันความปลอดภัยของประเภทใน Route Handler
TypeScript ได้กลายเป็นรากฐานสำคัญของการพัฒนา JavaScript ยุคใหม่ โดยนำเสนอความสามารถในการระบุประเภทแบบสแตติกที่ช่วยเพิ่มคุณภาพของโค้ด ความสามารถในการบำรุงรักษา และความสามารถในการปรับขนาด เมื่อรวมกับ Express.js ซึ่งเป็นเฟรมเวิร์กแอปพลิเคชันเว็บ Node.js ยอดนิยม TypeScript สามารถปรับปรุงความแข็งแกร่งของ API แบ็กเอนด์ของคุณได้อย่างมาก คู่มือฉบับสมบูรณ์นี้จะสำรวจวิธีใช้ประโยชน์จาก TypeScript เพื่อให้เกิดความปลอดภัยของประเภทใน Route Handler ในแอปพลิเคชัน Express.js โดยนำเสนอตัวอย่างที่เป็นประโยชน์และแนวทางปฏิบัติที่ดีที่สุดสำหรับการสร้าง API ที่แข็งแกร่งและดูแลรักษาง่ายสำหรับผู้ใช้ทั่วโลก
ทำไมความปลอดภัยของประเภทจึงสำคัญใน Express.js
ในภาษาไดนามิกอย่าง JavaScript ข้อผิดพลาดมักจะถูกตรวจพบเมื่อรันไทม์ ซึ่งอาจนำไปสู่พฤติกรรมที่ไม่คาดคิดและปัญหาที่ยากต่อการดีบัก TypeScript แก้ไขปัญหานี้ด้วยการนำเสนอการระบุประเภทแบบสแตติก ทำให้คุณสามารถตรวจจับข้อผิดพลาดระหว่างการพัฒนา ก่อนที่จะเผยแพร่ไปยังการผลิต ในบริบทของ Express.js ความปลอดภัยของประเภทมีความสำคัญอย่างยิ่งสำหรับ Route Handler ซึ่งคุณต้องจัดการกับอ็อบเจกต์คำขอและการตอบกลับ พารามิเตอร์การสืบค้น และเนื้อหาคำขอ การจัดการองค์ประกอบเหล่านี้ที่ไม่ถูกต้องอาจนำไปสู่การขัดข้องของแอปพลิเคชัน การเสียหายของข้อมูล และช่องโหว่ด้านความปลอดภัย
- การตรวจจับข้อผิดพลาดแต่เนิ่นๆ: ตรวจจับข้อผิดพลาดที่เกี่ยวข้องกับประเภทระหว่างการพัฒนา ลดโอกาสที่จะเกิดข้อผิดพลาดขณะรันไทม์โดยไม่คาดคิด
- ปรับปรุงการบำรุงรักษาโค้ด: การระบุประเภททำให้โค้ดเข้าใจและปรับปรุงได้ง่ายขึ้น
- การเติมโค้ดอัตโนมัติและเครื่องมือที่ดียิ่งขึ้น: IDE สามารถให้คำแนะนำและการตรวจสอบข้อผิดพลาดที่ดีขึ้นด้วยข้อมูลประเภท
- ลดข้อผิดพลาด: ความปลอดภัยของประเภทช่วยป้องกันข้อผิดพลาดในการเขียนโปรแกรมทั่วไป เช่น การส่งประเภทข้อมูลที่ไม่ถูกต้องไปยังฟังก์ชัน
การตั้งค่าโปรเจกต์ TypeScript Express.js
ก่อนที่จะลงลึกถึงความปลอดภัยของประเภทใน Route Handler เรามาตั้งค่าโปรเจกต์ TypeScript Express.js พื้นฐานกันก่อน สิ่งนี้จะเป็นรากฐานสำหรับตัวอย่างของเรา
ข้อกำหนดเบื้องต้น
- ติดตั้ง Node.js และ npm (Node Package Manager) แล้ว คุณสามารถดาวน์โหลดได้จากเว็บไซต์ทางการของ Node.js ตรวจสอบให้แน่ใจว่าคุณมีเวอร์ชันล่าสุดเพื่อความเข้ากันได้ที่ดีที่สุด
- โปรแกรมแก้ไขโค้ด เช่น Visual Studio Code ซึ่งรองรับ TypeScript ได้อย่างยอดเยี่ยม
การเริ่มต้นโปรเจกต์
- สร้างไดเรกทอรีโปรเจกต์ใหม่:
mkdir typescript-express-app && cd typescript-express-app - เริ่มต้นโปรเจกต์ npm ใหม่:
npm init -y - ติดตั้ง TypeScript และ Express.js:
npm install typescript express - ติดตั้งไฟล์ประกาศ TypeScript สำหรับ Express.js (สำคัญสำหรับความปลอดภัยของประเภท):
npm install @types/express @types/node - เริ่มต้น TypeScript:
npx tsc --init(สิ่งนี้จะสร้างไฟล์tsconfig.jsonซึ่งกำหนดค่าคอมไพเลอร์ TypeScript)
การกำหนดค่า TypeScript
เปิดไฟล์ tsconfig.json และกำหนดค่าให้เหมาะสม นี่คือการกำหนดค่าตัวอย่าง:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
การกำหนดค่าที่สำคัญที่ควรทราบ:
target: ระบุเวอร์ชันเป้าหมายของ ECMAScriptes6เป็นจุดเริ่มต้นที่ดีmodule: ระบุการสร้างโค้ดโมดูลcommonjsเป็นทางเลือกทั่วไปสำหรับ Node.jsoutDir: ระบุไดเรกทอรีเอาต์พุตสำหรับไฟล์ JavaScript ที่คอมไพล์แล้วrootDir: ระบุไดเรกทอรีรากของไฟล์ต้นฉบับ TypeScript ของคุณstrict: เปิดใช้งานตัวเลือกการตรวจสอบประเภทที่เข้มงวดทั้งหมดเพื่อเพิ่มความปลอดภัยของประเภท ซึ่งแนะนำเป็นอย่างยิ่งesModuleInterop: เปิดใช้งานการทำงานร่วมกันระหว่าง CommonJS และ ES Modules
การสร้างจุดเริ่มต้น
สร้างไดเรกทอรี src และเพิ่มไฟล์ index.ts:
mkdir src
touch src/index.ts
ใส่ข้อมูลในไฟล์ src/index.ts ด้วยการตั้งค่าเซิร์ฟเวอร์ Express.js พื้นฐาน:
import express, { Request, Response } from 'express';
const app = express();
const port = 3000;
app.get('/', (req: Request, res: Response) => {
res.send('Hello, TypeScript Express!');
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
การเพิ่มสคริปต์ Build
เพิ่มสคริปต์ build ลงในไฟล์ package.json ของคุณเพื่อคอมไพล์โค้ด TypeScript:
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "npm run build && npm run start"
}
ตอนนี้คุณสามารถรัน npm run dev เพื่อ build และเริ่มเซิร์ฟเวอร์ได้
ความปลอดภัยของประเภทใน Route Handler: การกำหนดประเภทคำขอและการตอบกลับ
หัวใจสำคัญของความปลอดภัยของประเภทใน Route Handler คือการกำหนดประเภทสำหรับอ็อบเจกต์ Request และ Response อย่างถูกต้อง Express.js มีประเภททั่วไปสำหรับอ็อบเจกต์เหล่านี้ที่ช่วยให้คุณสามารถระบุประเภทของพารามิเตอร์การสืบค้น เนื้อหาคำขอ และพารามิเตอร์ของเส้นทางได้
ประเภท Route Handler พื้นฐาน
มาเริ่มต้นด้วย Route Handler แบบง่ายๆ ที่คาดหวังชื่อเป็นพารามิเตอร์การสืบค้น:
import express, { Request, Response } from 'express';
const app = express();
const port = 3000;
interface NameQuery {
name: string;
}
app.get('/hello', (req: Request, res: Response) => {
const name = req.query.name;
if (!name) {
return res.status(400).send('Name parameter is required.');
}
res.send(`Hello, ${name}!`);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
ในตัวอย่างนี้:
Request<any, any, any, NameQuery>กำหนดประเภทสำหรับอ็อบเจกต์คำขอanyตัวแรกแสดงถึงพารามิเตอร์ของเส้นทาง (เช่น/users/:id)anyตัวที่สองแสดงถึงประเภทเนื้อหาการตอบกลับanyตัวที่สามแสดงถึงประเภทเนื้อหาคำขอNameQueryเป็นอินเทอร์เฟซที่กำหนดโครงสร้างของพารามิเตอร์การสืบค้น
ด้วยการกำหนดอินเทอร์เฟซ NameQuery ตอนนี้ TypeScript สามารถตรวจสอบได้ว่าคุณสมบัติ req.query.name มีอยู่จริงและเป็นประเภท string หากคุณพยายามเข้าถึงคุณสมบัติที่ไม่มีอยู่จริงหรือกำหนดค่าที่มีประเภทผิดพลาด TypeScript จะแจ้งข้อผิดพลาด
การจัดการเนื้อหาคำขอ
สำหรับเส้นทางที่ยอมรับเนื้อหาคำขอ (เช่น POST, PUT, PATCH) คุณสามารถกำหนดอินเทอร์เฟซสำหรับเนื้อหาคำขอและใช้ในประเภท Request ได้:
import express, { Request, Response } from 'express';
import bodyParser from 'body-parser';
const app = express();
const port = 3000;
app.use(bodyParser.json()); // Important for parsing JSON request bodies
interface CreateUserRequest {
firstName: string;
lastName: string;
email: string;
}
app.post('/users', (req: Request, res: Response) => {
const { firstName, lastName, email } = req.body;
// Validate the request body
if (!firstName || !lastName || !email) {
return res.status(400).send('Missing required fields.');
}
// Process the user creation (e.g., save to database)
console.log(`Creating user: ${firstName} ${lastName} (${email})`);
res.status(201).send('User created successfully.');
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
ในตัวอย่างนี้:
CreateUserRequestกำหนดโครงสร้างของเนื้อหาคำขอที่คาดหวังapp.use(bodyParser.json())มีความสำคัญอย่างยิ่งสำหรับการแยกวิเคราะห์เนื้อหาคำขอ JSON หากไม่มีreq.bodyจะเป็น undefined- ประเภท
Requestตอนนี้คือRequest<any, any, CreateUserRequest>ซึ่งระบุว่าเนื้อหาคำขอควรเป็นไปตามอินเทอร์เฟซCreateUserRequest
ตอนนี้ TypeScript จะตรวจสอบให้แน่ใจว่าอ็อบเจกต์ req.body มีคุณสมบัติที่คาดหวัง (firstName, lastName และ email) และประเภทถูกต้อง ซึ่งช่วยลดความเสี่ยงของข้อผิดพลาดขณะรันไทม์ที่เกิดจากข้อมูลเนื้อหาคำขอที่ไม่ถูกต้องได้อย่างมาก
การจัดการพารามิเตอร์ของเส้นทาง
สำหรับเส้นทางที่มีพารามิเตอร์ (เช่น /users/:id) คุณสามารถกำหนดอินเทอร์เฟซสำหรับพารามิเตอร์ของเส้นทางและใช้ในประเภท Request ได้:
import express, { Request, Response } from 'express';
const app = express();
const port = 3000;
interface UserParams {
id: string;
}
interface User {
id: string;
firstName: string;
lastName: string;
email: string;
}
const users: User[] = [
{ id: '1', firstName: 'John', lastName: 'Doe', email: 'john.doe@example.com' },
{ id: '2', firstName: 'Jane', lastName: 'Smith', email: 'jane.smith@example.com' },
];
app.get('/users/:id', (req: Request, res: Response) => {
const userId = req.params.id;
const user = users.find(u => u.id === userId);
if (!user) {
return res.status(404).send('User not found.');
}
res.json(user);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
ในตัวอย่างนี้:
UserParamsกำหนดโครงสร้างของพารามิเตอร์เส้นทาง โดยระบุว่าพารามิเตอร์idควรเป็นสตริง- ประเภท
Requestตอนนี้คือRequest<UserParams>ซึ่งระบุว่าอ็อบเจกต์req.paramsควรเป็นไปตามอินเทอร์เฟซUserParams
ตอนนี้ TypeScript จะตรวจสอบให้แน่ใจว่าคุณสมบัติ req.params.id มีอยู่จริงและเป็นประเภท string ซึ่งช่วยป้องกันข้อผิดพลาดที่เกิดจากการเข้าถึงพารามิเตอร์เส้นทางที่ไม่มีอยู่จริงหรือการใช้พารามิเตอร์เหล่านั้นกับประเภทที่ไม่ถูกต้อง
การระบุประเภทการตอบกลับ
แม้ว่าการให้ความสำคัญกับความปลอดภัยของประเภทคำขอเป็นสิ่งสำคัญ การกำหนดประเภทการตอบกลับยังช่วยเพิ่มความชัดเจนของโค้ดและช่วยป้องกันความไม่สอดคล้องกัน คุณสามารถกำหนดประเภทของข้อมูลที่คุณส่งกลับในการตอบกลับได้
import express, { Request, Response } from 'express';
const app = express();
const port = 3000;
interface User {
id: string;
firstName: string;
lastName: string;
email: string;
}
const users: User[] = [
{ id: '1', firstName: 'John', lastName: 'Doe', email: 'john.doe@example.com' },
{ id: '2', firstName: 'Jane', lastName: 'Smith', email: 'jane.smith@example.com' },
];
app.get('/users', (req: Request, res: Response) => {
res.json(users);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
ในที่นี้ Response<User[]> ระบุว่าเนื้อหาการตอบกลับควรเป็นอาร์เรย์ของอ็อบเจกต์ User สิ่งนี้ช่วยให้แน่ใจว่าคุณกำลังส่งโครงสร้างข้อมูลที่ถูกต้องในคำตอบ API ของคุณอย่างสม่ำเสมอ หากคุณพยายามส่งข้อมูลที่ไม่เป็นไปตามประเภท User[] TypeScript จะออกคำเตือน
ความปลอดภัยของประเภทใน Middleware
ฟังก์ชัน Middleware มีความสำคัญสำหรับการจัดการข้อกังวลที่หลากหลายในแอปพลิเคชัน Express.js การรับประกันความปลอดภัยของประเภทใน Middleware มีความสำคัญพอๆ กับใน Route Handler
การกำหนดประเภทฟังก์ชัน Middleware
โครงสร้างพื้นฐานของฟังก์ชัน Middleware ใน TypeScript คล้ายกับของ Route Handler:
import express, { Request, Response, NextFunction } from 'express';
function authenticationMiddleware(req: Request, res: Response, next: NextFunction) {
// Authentication logic
const isAuthenticated = true; // Replace with actual authentication check
if (isAuthenticated) {
next(); // Proceed to the next middleware or route handler
} else {
res.status(401).send('Unauthorized');
}
}
const app = express();
const port = 3000;
app.use(authenticationMiddleware);
app.get('/', (req: Request, res: Response) => {
res.send('Hello, authenticated user!');
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
ในตัวอย่างนี้:
NextFunctionเป็นประเภทที่ Express.js มีให้ ซึ่งแสดงถึงฟังก์ชัน Middleware ถัดไปในเชน- ฟังก์ชัน Middleware รับอ็อบเจกต์
RequestและResponseเช่นเดียวกับ Route Handler
การเสริมอ็อบเจกต์ Request
บางครั้ง คุณอาจต้องการเพิ่มคุณสมบัติที่กำหนดเองลงในอ็อบเจกต์ Request ใน Middleware ของคุณ ตัวอย่างเช่น Middleware การรับรองความถูกต้องอาจเพิ่มคุณสมบัติ user ลงในอ็อบเจกต์คำขอ หากต้องการทำเช่นนี้ด้วยวิธีที่ปลอดภัยของประเภท คุณต้องเสริมอินเทอร์เฟซ Request
import express, { Request, Response, NextFunction } from 'express';
interface User {
id: string;
username: string;
email: string;
}
// Augment the Request interface
declare global {
namespace Express {
interface Request {
user?: User;
}
}
}
function authenticationMiddleware(req: Request, res: Response, next: NextFunction) {
// Authentication logic (replace with actual authentication check)
const user: User = { id: '123', username: 'johndoe', email: 'john.doe@example.com' };
req.user = user; // Add the user to the request object
next(); // Proceed to the next middleware or route handler
}
const app = express();
const port = 3000;
app.use(authenticationMiddleware);
app.get('/', (req: Request, res: Response) => {
const username = req.user?.username || 'Guest';
res.send(`Hello, ${username}!`);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
ในตัวอย่างนี้:
- เราใช้การประกาศแบบ global เพื่อเสริมอินเทอร์เฟซ
Express.Request - เราเพิ่มคุณสมบัติ
userที่เป็นทางเลือก ซึ่งเป็นประเภทUserไปยังอินเทอร์เฟซRequest - ตอนนี้ คุณสามารถเข้าถึงคุณสมบัติ
req.userใน Route Handler ของคุณโดยที่ TypeScript จะไม่บ่น เครื่องหมาย?ในreq.user?.usernameมีความสำคัญอย่างยิ่งสำหรับการจัดการกรณีที่ผู้ใช้ไม่ได้รับการยืนยันตัวตน เพื่อป้องกันข้อผิดพลาดที่อาจเกิดขึ้น
แนวทางปฏิบัติที่ดีที่สุดสำหรับการผสาน TypeScript กับ Express
เพื่อเพิ่มประโยชน์สูงสุดของ TypeScript ในแอปพลิเคชัน Express.js ของคุณ ให้ปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดเหล่านี้:
- เปิดใช้งาน Strict Mode: ใช้ตัวเลือก
"strict": trueในไฟล์tsconfig.jsonของคุณเพื่อเปิดใช้งานตัวเลือกการตรวจสอบประเภทที่เข้มงวดทั้งหมด สิ่งนี้ช่วยตรวจจับข้อผิดพลาดที่อาจเกิดขึ้นแต่เนิ่นๆ และรับประกันความปลอดภัยของประเภทในระดับที่สูงขึ้น - ใช้อินเทอร์เฟซและ Type Alias: กำหนดอินเทอร์เฟซและ Type Alias เพื่อแสดงโครงสร้างข้อมูลของคุณ สิ่งนี้ทำให้โค้ดของคุณอ่านง่ายและบำรุงรักษาได้มากขึ้น
- ใช้ Generic Type: ใช้ประโยชน์จาก Generic Type เพื่อสร้างคอมโพเนนต์ที่นำกลับมาใช้ใหม่ได้และปลอดภัยของประเภท
- เขียน Unit Test: เขียน Unit Test เพื่อตรวจสอบความถูกต้องของโค้ดของคุณและให้แน่ใจว่าการระบุประเภทของคุณถูกต้อง การทดสอบมีความสำคัญอย่างยิ่งต่อการรักษาคุณภาพโค้ด
- ใช้ Linter และ Formatter: ใช้ Linter (เช่น ESLint) และ Formatter (เช่น Prettier) เพื่อบังคับใช้รูปแบบการเขียนโค้ดที่สอดคล้องกันและตรวจจับข้อผิดพลาดที่อาจเกิดขึ้น
- หลีกเลี่ยงประเภท
any: ลดการใช้ประเภทanyให้น้อยที่สุด เนื่องจากจะข้ามการตรวจสอบประเภทและขัดต่อวัตถุประสงค์ของการใช้ TypeScript ใช้เฉพาะเมื่อจำเป็นอย่างยิ่งเท่านั้น และพิจารณาใช้ประเภทที่เฉพาะเจาะจงมากขึ้นหรือ Generic Type เมื่อเป็นไปได้ - จัดโครงสร้างโปรเจกต์ของคุณอย่างมีเหตุผล: จัดระเบียบโปรเจกต์ของคุณเป็นโมดูลหรือโฟลเดอร์ตามฟังก์ชันการทำงาน สิ่งนี้จะช่วยปรับปรุงความสามารถในการบำรุงรักษาและการปรับขนาดของแอปพลิเคชันของคุณ
- ใช้ Dependency Injection: พิจารณาใช้ Dependency Injection Container เพื่อจัดการการพึ่งพาของแอปพลิเคชันของคุณ สิ่งนี้สามารถทำให้โค้ดของคุณทดสอบได้ง่ายขึ้นและบำรุงรักษาได้มากขึ้น ไลบรารีเช่น InversifyJS เป็นตัวเลือกยอดนิยม
แนวคิด TypeScript ขั้นสูงสำหรับ Express.js
การใช้ Decorator
Decorator เป็นวิธีที่กระชับและแสดงออกเพื่อเพิ่มเมตาดาต้าให้กับคลาสและฟังก์ชัน คุณสามารถใช้ Decorator เพื่อลดความซับซ้อนของการลงทะเบียนเส้นทางใน Express.js ได้
ก่อนอื่น คุณต้องเปิดใช้งาน experimental decorators ในไฟล์ tsconfig.json ของคุณโดยเพิ่ม "experimentalDecorators": true ไปยัง compilerOptions
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"experimentalDecorators": true
}
}
จากนั้น คุณสามารถสร้าง Decorator ที่กำหนดเองเพื่อลงทะเบียนเส้นทางได้:
import express, { Router, Request, Response } from 'express';
function route(method: string, path: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
if (!target.__router__) {
target.__router__ = Router();
}
target.__router__[method](path, descriptor.value);
};
}
class UserController {
@route('get', '/users')
getUsers(req: Request, res: Response) {
res.send('List of users');
}
@route('post', '/users')
createUser(req: Request, res: Response) {
res.status(201).send('User created');
}
public getRouter() {
return this.__router__;
}
}
const userController = new UserController();
const app = express();
const port = 3000;
app.use('/', userController.getRouter());
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
ในตัวอย่างนี้:
- Decorator
routeรับเมธอด HTTP และพาธเป็นอาร์กิวเมนต์ - มันลงทะเบียนเมธอดที่ถูกตกแต่งเป็น Route Handler บน Router ที่เชื่อมโยงกับคลาส
- สิ่งนี้ช่วยลดความซับซ้อนของการลงทะเบียนเส้นทางและทำให้โค้ดของคุณอ่านง่ายขึ้น
การใช้ Custom Type Guard
Type Guard คือฟังก์ชันที่จำกัดประเภทของตัวแปรภายในขอบเขตที่กำหนด คุณสามารถใช้ Custom Type Guard เพื่อตรวจสอบความถูกต้องของเนื้อหาคำขอหรือพารามิเตอร์การสืบค้น
interface Product {
id: string;
name: string;
price: number;
}
function isProduct(obj: any): obj is Product {
return typeof obj === 'object' &&
obj !== null &&
typeof obj.id === 'string' &&
typeof obj.name === 'string' &&
typeof obj.price === 'number';
}
import express, { Request, Response } from 'express';
import bodyParser from 'body-parser';
const app = express();
const port = 3000;
app.use(bodyParser.json());
app.post('/products', (req: Request, res: Response) => {
if (!isProduct(req.body)) {
return res.status(400).send('Invalid product data');
}
const product: Product = req.body;
console.log(`Creating product: ${product.name}`);
res.status(201).send('Product created');
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
ในตัวอย่างนี้:
- ฟังก์ชัน
isProductเป็น Custom Type Guard ที่ตรวจสอบว่าอ็อบเจกต์เป็นไปตามอินเทอร์เฟซProductหรือไม่ - ภายใน Route Handler
/productsฟังก์ชันisProductถูกใช้เพื่อตรวจสอบความถูกต้องของเนื้อหาคำขอ - หากเนื้อหาคำขอเป็นผลิตภัณฑ์ที่ถูกต้อง TypeScript จะรู้ว่า
req.bodyเป็นประเภทProductภายในบล็อกif
การพิจารณาในระดับโลกในการออกแบบ API
เมื่อออกแบบ API สำหรับผู้ใช้ทั่วโลก ควรพิจารณาหลายปัจจัยเพื่อให้มั่นใจในการเข้าถึง ความสามารถในการใช้งาน และความอ่อนไหวทางวัฒนธรรม
- การแปลและการทำให้เป็นสากล (i18n และ L10n):
- การเจรจาต่อรองเนื้อหา: รองรับหลายภาษาและภูมิภาคผ่านการเจรจาต่อรองเนื้อหาตามส่วนหัว
Accept-Language - การจัดรูปแบบวันที่และเวลา: ใช้รูปแบบ ISO 8601 สำหรับการแสดงวันที่และเวลาเพื่อหลีกเลี่ยงความกำกวมในภูมิภาคต่างๆ
- การจัดรูปแบบตัวเลข: จัดการการจัดรูปแบบตัวเลขตามภาษาท้องถิ่นของผู้ใช้ (เช่น ตัวคั่นทศนิยมและตัวคั่นหลักพัน)
- การจัดการสกุลเงิน: รองรับหลายสกุลเงินและให้ข้อมูลอัตราแลกเปลี่ยนเมื่อจำเป็น
- ทิศทางข้อความ: รองรับภาษาที่เขียนจากขวาไปซ้าย (RTL) เช่น ภาษาอาหรับและฮิบรู
- การเจรจาต่อรองเนื้อหา: รองรับหลายภาษาและภูมิภาคผ่านการเจรจาต่อรองเนื้อหาตามส่วนหัว
- เขตเวลา:
- จัดเก็บวันที่และเวลาใน UTC (Coordinated Universal Time) ที่ฝั่งเซิร์ฟเวอร์
- อนุญาตให้ผู้ใช้ระบุเขตเวลาที่ต้องการและแปลงวันที่และเวลาตามนั้นที่ฝั่งไคลเอ็นต์
- ใช้ไลบรารีเช่น
moment-timezoneเพื่อจัดการการแปลงเขตเวลา
- การเข้ารหัสอักขระ:
- ใช้การเข้ารหัส UTF-8 สำหรับข้อมูลข้อความทั้งหมดเพื่อรองรับตัวอักษรที่หลากหลายจากภาษาต่างๆ
- ตรวจสอบให้แน่ใจว่าฐานข้อมูลและระบบจัดเก็บข้อมูลอื่นๆ ของคุณได้รับการกำหนดค่าให้ใช้ UTF-8
- การเข้าถึง:
- ปฏิบัติตามแนวทางปฏิบัติในการเข้าถึง (เช่น WCAG) เพื่อให้ API ของคุณสามารถเข้าถึงได้โดยผู้ใช้ที่มีความพิการ
- ให้ข้อความแสดงข้อผิดพลาดที่ชัดเจนและเข้าใจง่าย
- ใช้ส่วนประกอบ HTML เชิงความหมายและคุณสมบัติ ARIA ในเอกสารประกอบ API ของคุณ
- ความอ่อนไหวทางวัฒนธรรม:
- หลีกเลี่ยงการใช้การอ้างอิงทางวัฒนธรรมโดยเฉพาะ สำนวน หรืออารมณ์ขันที่ผู้ใช้บางรายอาจไม่เข้าใจ
- คำนึงถึงความแตกต่างทางวัฒนธรรมในรูปแบบการสื่อสารและความชอบ
- พิจารณาผลกระทบที่อาจเกิดขึ้นของ API ของคุณต่อกลุ่มวัฒนธรรมต่างๆ และหลีกเลี่ยงการคงอยู่ของภาพเหมารวมหรืออคติ
- ความเป็นส่วนตัวของข้อมูลและความปลอดภัย:
- ปฏิบัติตามกฎระเบียบความเป็นส่วนตัวของข้อมูล เช่น GDPR (General Data Protection Regulation) และ CCPA (California Consumer Privacy Act)
- ใช้กลไกการรับรองความถูกต้องและการอนุญาตที่แข็งแกร่งเพื่อปกป้องข้อมูลผู้ใช้
- เข้ารหัสข้อมูลที่ละเอียดอ่อนทั้งระหว่างการส่งและเมื่อไม่ได้ใช้งาน
- ให้ผู้ใช้ควบคุมข้อมูลของตนและอนุญาตให้เข้าถึง แก้ไข และลบข้อมูลของตนได้
- เอกสารประกอบ API:
- จัดทำเอกสารประกอบ API ที่ครอบคลุมและจัดระเบียบอย่างดี ซึ่งง่ายต่อการทำความเข้าใจและนำทาง
- ใช้เครื่องมือเช่น Swagger/OpenAPI เพื่อสร้างเอกสารประกอบ API แบบโต้ตอบได้
- รวมตัวอย่างโค้ดในหลายภาษาโปรแกรมเพื่อรองรับกลุ่มเป้าหมายที่หลากหลาย
- แปลเอกสารประกอบ API ของคุณเป็นหลายภาษาเพื่อเข้าถึงกลุ่มเป้าหมายที่กว้างขึ้น
- การจัดการข้อผิดพลาด:
- ให้ข้อความแสดงข้อผิดพลาดที่เฉพาะเจาะจงและให้ข้อมูล หลีกเลี่ยงข้อความแสดงข้อผิดพลาดทั่วไปเช่น "Something went wrong."
- ใช้รหัสสถานะ HTTP มาตรฐานเพื่อระบุประเภทของข้อผิดพลาด (เช่น 400 สำหรับ Bad Request, 401 สำหรับ Unauthorized, 500 สำหรับ Internal Server Error)
- รวมรหัสข้อผิดพลาดหรือตัวระบุที่สามารถใช้เพื่อติดตามและแก้ไขปัญหาได้
- บันทึกข้อผิดพลาดที่ฝั่งเซิร์ฟเวอร์สำหรับการดีบักและการตรวจสอบ
- การจำกัดอัตรา: ใช้การจำกัดอัตราเพื่อปกป้อง API ของคุณจากการใช้งานที่ไม่เหมาะสมและรับประกันการใช้งานที่เป็นธรรม
- การกำหนดเวอร์ชัน: ใช้การกำหนดเวอร์ชัน API เพื่อให้สามารถเปลี่ยนแปลงที่เข้ากันได้แบบย้อนหลังและหลีกเลี่ยงการทำให้ไคลเอ็นต์ที่มีอยู่เสียหาย
สรุป
การผสาน TypeScript กับ Express ช่วยปรับปรุงความน่าเชื่อถือและความสามารถในการบำรุงรักษาของ API แบ็กเอนด์ของคุณได้อย่างมาก ด้วยการใช้ความปลอดภัยของประเภทใน Route Handler และ Middleware คุณสามารถตรวจจับข้อผิดพลาดได้ตั้งแต่เนิ่นๆ ในกระบวนการพัฒนา และสร้างแอปพลิเคชันที่แข็งแกร่งและปรับขนาดได้สำหรับผู้ใช้ทั่วโลก ด้วยการกำหนดประเภทคำขอและการตอบกลับ คุณจะมั่นใจได้ว่า API ของคุณเป็นไปตามโครงสร้างข้อมูลที่สอดคล้องกัน ซึ่งช่วยลดโอกาสที่จะเกิดข้อผิดพลาดขณะรันไทม์ อย่าลืมปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุด เช่น การเปิดใช้งาน Strict Mode การใช้อินเทอร์เฟซและ Type Alias และการเขียน Unit Test เพื่อเพิ่มประโยชน์สูงสุดของ TypeScript พิจารณาปัจจัยทั่วโลกเสมอ เช่น การแปล การแบ่งเขตเวลา และความอ่อนไหวทางวัฒนธรรม เพื่อให้แน่ใจว่า API ของคุณสามารถเข้าถึงและใช้งานได้ทั่วโลก