ترکیب Express و Typescript: اضافه کردن middleware

Combining Typescript and Express: Adding Middleware

01 شهریور 1399
ترکیب Express و Typescript: اضافه کردن middleware – قسمت 76

در قسمت قبل اولین سرور خود را نوشتیم اما سرور ما هیچ کاری نمی کند (به پورت 3000 گوش می دهد اما هیچ عکس العملی نشان نخواهد داد). برای حل این مشکل به پوشه src رفته و پوشه جدیدی به نام routes ایجاد کنید. این پوشه باید حاوی فایلی به نام todos.ts باشد. این فایل قرار است یک برنامه API برای todo ها (لیست کار های روزمره کاربر) باشد. حالا می توانیم درون این فایل با استفاده از Express.js مسیر یا route های خودمان را برای سرور تعیین کنیم. در قدم اول باید Router را از Express وارد این فایل کنیم:

import { Router } from 'express';

حالا می توانیم مثل همیشه این router را به عنوان یک تابع صدا بزنیم تا با استفاده از آن یک middleware را ثبت کنیم:

import { Router } from 'express';

const router = Router();

router.post('/');

router.get('/');

router.patch('/:id');

router.delete('/:id');

export default router;

همانطور که در کد بالا می بینید من route ها را برای post (ثبت یک todo جدید) و get (دریافت todo ها) و patch (آپدیت todo ها) و delete (حذف todo ها) ثبت کرده ام. اگر با Express آشنا باشید، می فهمید که این کدها هیچ کاری نمی کنند بلکه فقط route هایی را در ابتدا تعریف کرده ایم تا بعدا به سراغشان آمده و کدهایشان را تکمیل کنیم. هر کدام از این route ها به یک تابع نیاز دارند که مسئول پاسخ دادن به درخواست ها است. توجه داشته باشید که patch و delete از ما id را نیز می خواهند تا بدانند کدام todo را حذف یا به روز رسانی کنند. در نهایت router را export می کنیم تا در فایل های دیگر به آن دسترسی داشته باشیم.

حالا باید route های خودمان را به سرور برنامه متصل کنیم. برای این کار به فایل app.ts رفته و router را در آن import کنید:

import todoRoutes from './routes/todos';

سپس می خواهم طوری سرور را تنظیم کنم که تمام درخواست هایی که با todos/ شروع می شود به router تعریف شده ما ارسال شود بنابراین:

import todoRoutes from './routes/todos';

const app = express();

app.use('/todos', todoRoutes);

با این کد به Express گفته ایم که فقط درخواست هایی با آدرس todos/ را به todoRoutes ارسال کن و درخواست های دیگر را نادیده بگیر. در همین فایل یک middleware جدید را تعریف می کنیم که مسئول مدیریت خطاهای برنامه ما است. هر خطایی در هر قسمتی از برنامه ما اتفاق بیفتد، توسط این middleware مدیریت خواهد شد:

import express from 'express';

import todoRoutes from './routes/todos';

const app = express();

app.use('/todos', todoRoutes);

app.use((err, req, res, next) => {

});

app.listen(3000);

err خطای احتمالی، req درخواست، res پاسخ و next یک تابع هستند که به عنوان پارامترهای تابع پاس داده شده به use تعریف شده اند. باز هم می گویم که شما برای درک این کدها باید با Express آشنا باشید. با نوشتن کد بالا به خطا برمی خوریم چرا که از هیچ کدام از این پارامترها استفاده نکرده ایم و همچنین تایپ تمام آن ها any است. برای حل این مشکل می گوییم:

app.use((err: Error, req: express.Request, res: , next: ) => {

});

این تایپ ها مخصوص Express است و با همان پکیج types/express نصب شده اند. قبل از اضافه کردن تایپ res و next من به جای نوشتن express.request، تایپ request را در همین فایل import می کنم تا کدهایمان شلوغ نشده و فقط Request کافی باشد:

import express, { Request, Response, NextFunction } from 'express';

حالا می توان گفت:

app.use((err: Error, req: Request, res: Response, next: NextFunction) => {

});

توجه داشته باشید که اگر موارد بالا (Request و Response و NextFunction) را در این فایل import نکنید باید حتما تایپ ها را با پیشوند express بنویسید (مثل قبل که از express.Request استفاده کرده بودم). نهایتا کدها را به شکل زیر کامل می کنیم:

import express, { Request, Response, NextFunction } from 'express';

import todoRoutes from './routes/todos';

const app = express();

app.use('/todos', todoRoutes);

app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  res.status(500).json({ message: err.message });
});

app.listen(3000);

کد بالا می گوید در صورت بروز خطا، یک status code با کد 500 را ارسال کن و البته همراه آن یک شیء JSON باشد که خصوصیت message آن برابر پیام خطای ما (Err.message) قرار بگیرد. شما می توانید کد پیشرفته تری برای مدیریت خطاهایتان بنویسید اما برای این برنامه کوچک، همین کافی است.

حالا بیایید منطق ساده ای را برای API خود پیاده سازی کنیم. برای این کار درون پوشه src یک پوشه جدید به نام controller ایجاد کنید. این کار برای جداسازی منطق کنترلر ها از منطق routes و خواناتر شدن کد ما است. پوشه controllers نیز باید فایلی به نام todos.ts داشته باشد. در ابتدا درون این فایل تابعی را تعریف می کنیم که پارامترهای همیشگی تمام توابع middleware را می گیرد:

import express, { Request, Response, NextFunction } from 'express';

export const createTodo = (req: Request, res: Response, next: NextFunction) => {

}

من مثل دفعه قبل Request و Response و NextFunction را وارد فایل کرده ام تا آن ها را به عنوان تایپ برای پارامترهای تابع خودم قرار بدهم اما وارد کردن آن ها و تعیین تایپ برای هر تابع کاری خسته کننده و تکراری است. ما می توانیم به جای اینکه تایپ تک تک پارامترهای این تابع را مشخص کنیم، به تایپ اسکریپت بگوییم چه نوع تابعی قرار است در createTodo ذخیره شود. در واقع به جای تعیین تایپ برای پارامترها، برای کل تابع تعیین تایپ می کنیم.

برای این کار به جای دستور import بالا می گوییم:

import { RequestHandler } from 'express';

export const createTodo: RequestHandler = (req, res, next) => {

}

این تایپ از تایپ های موجود در پکیج types/express است که اینجا به درد ما می خورد. با نوشتن این کد دیگر در رابطه با پارامترها خطایی دریافت نمی کنیم. تایپ requestHandler برای توابعی است که مسئول مدیریت پاسخ ها هستند که یعنی همین تابع createTodo. ما پس از نوشتن تابع createTodo قرار است آن را به route مورد نظرش متصل کنیم تا درخواست های آن route خاص را مدیریت کند.

تکمیل این تابع و اتصال آن به route مورد نظر را در قسمت بعد انجام خواهیم داد.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش جامع تایپ اسکریپت توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مقالات مرتبط
ما را دنبال کنید
اینستاگرام روکسو تلگرام روکسو ایمیل و خبرنامه روکسو