مقدمه
Node.js به عنوان یک بستر قدرتمند و محبوب برای توسعه خدمات پشتیبان و ایجاد نقاط پایانی API شناخته میشود. بسیاری از شرکتهای بزرگ از Node.js در معماری میکروسرویسهای خود بهره میبرند، که این موضوع اهمیت یادگیری و آشنایی با این پلتفرم را دوچندان میکند. به همین ترتیب، فریمورک Express.js به عنوان یکی از پیشروترین ابزارها برای ساخت API ها مطرح است و TypeScript با ارائه قابلیتهای نوعدهی دقیق، ارزش افزودهای در توسعه برنامههای بزرگ و سازمانی به ارمغان میآورد. ترکیب TypeScript و Express.js امکان ساخت سیستمهای پشتیبان توزیعشده و مقاوم را فراهم میآورد. از این رو، تأمین امنیت دسترسی به این سیستمها از اهمیت بالایی برخوردار است.
الزامات اولیه
برای پیگیری این آموزش، اطمینان حاصل کنید که الزامات زیر را دارید:
- آشنایی با زبان جاوااسکریپت. آشنایی با TypeScript نیز مزیت بزرگی به شمار میآید.
- درک عملیات API REST، از جمله
GET
،POST
،PUT
وDELETE
. - نصب Node.js و NPM بر روی سیستم. برای تأیید این موضوع میتوانید از دستورات
node -v
وnpm -v
استفاده کنید. - انتخاب یک ویرایشگر مناسب. ویرایشگر Visual Studio Code که در این آموزش استفاده شده، گزینهای مناسب برای کار با پروژههای Node.js به شمار میآید.
موارد اضافی برای موفقیت در توسعه
علاوه بر موارد فوق، آشنایی با اصول طراحی API و الگوهای معماری نرمافزار میتواند به شما در ساخت سیستمهای پایدار و مقیاسپذیر کمک کند. همچنین، داشتن آگاهی از بهترین شیوههای امنیتی و نحوه پیادهسازی آنها در پروژهها، از دیگر نکات کلیدی است که باید مورد توجه قرار گیرد.
راهاندازی اپلیکیشن جدید NodeJS
برای آغاز کار با NodeJS، اولین قدم ایجاد یک پوشه جدید بر روی سیستم محلی شما است. این پوشه به عنوان محل ذخیرهسازی پروژه شما عمل خواهد کرد. پس از ایجاد پوشه، با استفاده از دستورات زیر، اپلیکیشن NodeJS جدیدی را راهاندازی کنید:
ابتدا باید اطمینان حاصل کنید که NodeJS و NPM بر روی سیستم شما نصب شده باشد. برای این کار میتوانید از دستورات node -v
و npm -v
استفاده کنید تا نسخههای نصب شده را بررسی کنید. در مرحله بعد، با اجرای دستور npm init
، یک پروژه جدید NodeJS ایجاد کنید و تمام اطلاعات مورد نیاز را وارد کنید.
نصب وابستگیها
همچنین، برای اینکه اپلیکیشن شما به درستی کار کند، نیاز به نصب چندین وابستگی دارید. با اجرای دستورات زیر، وابستگیهای لازم را نصب کنید:
npm install express typescript @types/node @types/express
پس از نصب وابستگیها، زمان آن رسیده که تنظیمات TypeScript را پیکربندی کنید. با استفاده از دستور زیر، یک فایل پیکربندی TypeScript ایجاد کنید:
npx tsc --init
اکنون میتوانید پروژه خود را در ویرایشگر دلخواه خود باز کنید و فایل tsconfig.json
را ویرایش کنید تا تنظیمات مورد نیاز خود را اضافه کنید.
"compilerOptions": { "target": "ES6", "module": "commonjs", "strict": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true, "outDir": "./dist" }, "include": ["src"], "exclude": ["node_modules"] }
ساخت اپلیکیشن پایه بدون احراز هویت
برای شروع، یک پوشه به نام src
در دایرکتوری اصلی پروژه خود ایجاد کنید. در این پوشه، یک فایل به نام server.ts
بسازید که شامل کدهای ابتدایی برای راهاندازی سرور باشد. این فایل نقطه شروع اپلیکیشن شما خواهد بود.
/*Path of the file: project-root/src/server.ts*/ import express from 'express'; import dotenv from 'dotenv'; import router from './routes'; dotenv.config(); const app = express(); const PORT = process.env.PORT || 3000; app.use(express.json()); app.use('/api', router); app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); });
حالا، برای مدیریت مسیرها، باید یک پوشه به نام routes
درون پوشه src
بسازید و فایل index.ts
را در آن قرار دهید. این فایل مسئول مدیریت مسیرها و جزئیات مربوط به API خواهد بود.
/*Path of the file: project-root/src/routes/index.ts*/ import { Router } from 'express'; import { getAllBooks, getBookById, addNewBook, removeBook } from '../controllers/bookController'; const router = Router(); router.get('/books', getAllBooks); router.get('/books/:id', getBookById); router.post('/books', addNewBook); router.delete('/books/:id', removeBook); export default router;
در ادامه، یک کنترلر مثلا به نام کتاب ایجاد کنید که وظیفه دریافت و پاسخ به درخواستهای API را بر عهده دارد. برای این کار، یک پوشه به نام controllers
زیر پوشه src
بسازید و فایل bookController.ts
را در آن قرار دهید. کد کنترلر به گونهای طراحی شده است که هر درخواست API را دریافت کرده و در صورت نیاز، آن را پردازش کند و سپس پاسخ مناسبی را به کاربر برگرداند.
/*Path of the file: project-root/src/controllers/userController.ts*/ import { Request, Response } from 'express'; import { getBooks, findBookById, addBook, deleteBook } from '../services/bookService'; export const getAllBooks = (req: Request, res: Response): void => { const books = getBooks(); res.json(books); }; export const getBookById = (req: Request, res: Response): void => { const bookId = parseInt(req.params.id); if (isNaN(bookId)) { res.status(400).json({ message: 'Invalid book ID' }); return; } const book = findBookById(bookId); if (!book) { res.status(404).json({ message: 'Book not found' }); return; } res.json(book); }; export const addNewBook = (req: Request, res: Response): void => { const { title, author, publishedYear } = req.body; if (!title || !author || !publishedYear) { res.status(400).json({ message: 'Missing required fields' }); return; } const newBook = { id: Date.now(), title, author, publishedYear }; addBook(newBook); res.status(201).json(newBook); }; export const removeBook = (req: Request, res: Response): void => { const bookId = parseInt(req.params.id); if (isNaN(bookId)) { res.status(400).json({ message: 'Invalid book ID' }); return; } const book = findBookById(bookId); if (!book) { res.status(404).json({ message: 'Book not found' }); return; } deleteBook(bookId); res.status(200).json({ message: 'Book deleted successfully' }); };
برای ذخیرهسازی دادههای کتاب، یک پایگاه داده موقت در حافظه ایجاد کنید. برای این کار، یک پوشه به نام services
زیر پوشه src
بسازید و فایل bookService.ts
را در آن قرار دهید. این فایل شامل کدی خواهد بود که با پایگاه داده کتاب تعامل دارد و امکان خواندن و نوشتن اطلاعات کتاب را فراهم میکند.
/*Path of the file: project-root/src/data/books.json*/ [ { "id": 1, "title": "To Kill a Mockingbird", "author": "Harper Lee", "publishedYear": 1960 }, { "id": 2, "title": "1984", "author": "George Orwell", "publishedYear": 1949 }, { "id": 3, "title": "Pride and Prejudice", "author": "Jane Austen", "publishedYear": 1813 } ]
/*Path of the file: project-root/src/services/bookService.ts*/ import fs from 'fs'; import path from 'path'; interface Book { id: number; title: string; author: string; publishedYear: number; } let books: Book[] = []; export const initializeBooks = (): void => { const filePath = path.join(__dirname, '../data/books.json'); const data = fs.readFileSync(filePath, 'utf-8'); books = JSON.parse(data); }; export const getBooks = (): Book[] => { return books; }; export const findBookById = (id: number): Book | undefined => { return books.find((b) => b.id === id); }; export const addBook = (newBook: Book): void => { books.push(newBook); }; export const deleteBook = (id: number): void => { books = books.filter((b) => b.id !== id); }; export const saveBooks = (): void => { const filePath = path.join(__dirname, '../data/books.json'); fs.writeFileSync(filePath, JSON.stringify(books, null, 2)); };
پس از تکمیل این مراحل، کد server.ts
را بهروزرسانی کنید تا پایگاه داده را راهاندازی کند و سپس یک اسکریپت راهاندازی سرور در فایل package.json
اضافه کنید. در نهایت، با اجرای دستور npm start
، اپلیکیشن خود را راهاندازی کنید و باید پیغامی مبنی بر راهاندازی سرور را در کنسول مشاهده کنید.
/*Path of the file: project-root/src/server.ts*/ import express from 'express'; import dotenv from 'dotenv'; import router from './routes'; import { initializeBooks } from './services/bookService'; dotenv.config(); initializeBooks(); const app = express(); const PORT = process.env.PORT || 3000; app.use(express.json()); app.use('/api', router); app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); });
*Path of the file: project-root/package.json*/ ...rest of file "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "ts-node-dev src/server.ts" }, ...rest of file
آزمون رابطهای برنامهنویسی (APIs) بدون احراز هویت
اکنون که سرور شما به درستی راهاندازی شده است، زمان آن رسیده که رابطهای برنامهنویسی (API) خود را آزمایش کنید. برای این کار، میتوانید از ابزاری مانند Postman استفاده کنید. با دسترسی به آدرس http://localhost:3000/api/books
، انتظار دارید که پاسخهایی از API دریافت کنید.
در صورت موفقیت، شما باید یک پاسخ مشابه زیر را مشاهده کنید:
علاوه بر این، شما میتوانید از نقاط پایانی API برای بهروزرسانی یا حذف کتابها نیز استفاده کنید. به یاد داشته باشید که یک مجموعه Postman برای شما فراهم شده است که میتوانید آن را به سادگی وارد کنید و استفاده نمایید. آدرس آن را میتوانید از طریق لینک زیر دریافت کنید.
برای ایجاد کتابهای جدید، از آدرس http://localhost:3000/api/books
استفاده کنید و برای حذف کتابها، از http://localhost:3000/api/books/:id
بهره ببرید.
نکات مهم در آزمون
- اطمینان حاصل کنید که سرور در حال اجرا است.
- آدرسهای صحیح API را وارد کنید.
- در صورت بروز خطا، لاگهای سرور را بررسی کنید.
پیادهسازی احراز هویت با JWT
اکنون زمان آن رسیده است که امنیت API های خود را افزایش دهید. برای این کار، به یک لیست از کاربران نیاز داریم که میتوانند به رابطهای مدیریت کتاب دسترسی داشته باشند. برای این منظور، یک فایل users.json
در دایرکتوری دادهها ایجاد کنید تا کاربران در حافظه نگهداری شوند.
در مرحله بعد، دو فایل userService.ts
و userController.ts
را بسازید که وظیفه احراز هویت کاربر بر اساس نام کاربری و رمز عبور را بر عهده داشته باشند.
سپس، نیاز به ایجاد یک تابع middleware برای احراز هویت دارید که تمام درخواستهای API را بررسی کرده و تأیید میکند که آیا این درخواستها از کاربران معتبر میآید یا خیر. برای این کار، یک دایرکتوری middleware
در src
ایجاد کنید و فایل authMiddleware.ts
را به آن اضافه کنید.
در نهایت، قوانین احراز هویت را به هر تماس API اضافه کنید و اطمینان حاصل کنید که کاربران برای دسترسی به نقاط پایانی مدیریت کتاب باید احراز هویت شوند.
آزمون رابطهای برنامهنویسی (APIs) با احراز هویت
حالا که احراز هویت را به API های خود اضافه کردهاید، تلاش برای تماس با API بدون ارائه توکن JWT معتبر، منجر به دریافت خطا از سرور خواهد شد.
قبل از انجام هر گونه درخواست، ابتدا باید با استفاده از آدرس http://localhost:3000/api/login
احراز هویت کنید. با ارائه نام کاربری و رمز عبور، یک توکن JWT معتبر دریافت خواهید کرد.
این توکن را به هر درخواست API اضافه کنید و با کلمه Bearer پیشوند بزنید. این کار به شما امکان میدهد تا پاسخهای صحیحی دریافت کنید.
نکات برای احراز هویت موفق
- اطمینان حاصل کنید که نام کاربری و رمز عبور درست است.
- توکن JWT را در هدر درخواستهای خود قرار دهید.
- در صورت بروز خطا، مراحل احراز هویت را دوباره بررسی کنید.
نتیجهگیری
امنیت API های شما یکی از مهمترین مراحل در طراحی سیستمهای پشتیبان مدرن است. با استفاده از JWT، شما اکنون میتوانید API های Node.js و Express خود را با امنیت بهتری تجهیز کنید و به چالشهای امنیتی دنیای واقعی پاسخ دهید.
JWT (JSON Web Token) به شما امکان میدهد تا فرآیند احراز هویت را به صورت بیحالت و مقیاسپذیر انجام دهید. این به این معنی است که دیگر نیازی به ذخیرهسازی وضعیت کاربر در سرور نیست و میتوانید با اطمینان بیشتری به درخواستهای کاربران پاسخ دهید.