<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های حسین صادقی</title>
        <link>https://virgool.io/feed/@hossein.s</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-08 14:43:58</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/48809/avatar/PaLQq7.png?height=120&amp;width=120</url>
            <title>حسین صادقی</title>
            <link>https://virgool.io/@hossein.s</link>
        </image>

                    <item>
                <title>ساختن بک‌اند تایپ‌اسکریپتی - بخش ۴: هر کاربر، Todoهای متفاوت</title>
                <link>https://virgool.io/iran-nodejs-community/%D8%B3%D8%A7%D8%AE%D8%AA%D9%86-%D8%A8%DA%A9%D8%A7%D9%86%D8%AF-%D8%AA%D8%A7%DB%8C%D9%BE%D8%A7%D8%B3%DA%A9%D8%B1%DB%8C%D9%BE%D8%AA%DB%8C-%D8%A8%D8%AE%D8%B4-%DB%B4-%D9%87%D8%B1-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1-todo%D9%87%D8%A7%DB%8C-%D9%85%D8%AA%D9%81%D8%A7%D9%88%D8%AA-lytm2xb6riaq</link>
                <description>NestJSسرفصل‌هافریمورک NestJS چیست و چرا؟شروع پروژه Todoدیتابیس!هر کاربر، Todoهای متفاوتمقدمهتوی بخش قبل Todoها رو توی دیتابیس ذخیره کردیم و تونستیم که اون‌ها رو صورت دائمی اونجا نگهداری کنیم. اما هیچکس نمیخواد که Todoهایی داشته باشه که بقیه بتونن اونارو ببینن و حتی ویرایش و حذف کنن!توی این بخش سراغ یکی از بخش‌های اصلی هر API میریم. اینکه کاربرها رو اعتباریابی (authenticate) کنیم و اون‌ها رو توی سیستم خودمون بشناسیم و بتونیم داده‌های شخصی‌سازی شده برای اونها داشته باشیم.مقدمه‌ی بیشتربرای اینکه توی اپلیکیشن font-end کاربر رو لاگین نگه داریم چندتا استراتژی وجود داره. یکیش اینکه که وقتی کاربر توی صفحه ورود، ایمیل و پسورد رو وارد کرد، اون‌ها رو ذخیره کنیم و برای درخواست‌های بعدی همون رو بفرستیم برای backend. اونجا هم توی هر ریکوئست ایمیل و پسورد رو بررسی کنیم و کاربر رو اعتبار یابی کنیم. ولی ذخیره پسورد کاربر روش خوبی نیست. اصلا نیست!روش دیگه اینه که وقتی کاربر ایمیل و پسورد رو وارد کرد و درست بود، ما بهش یک Token بدیم که این Token مثل بلیت کاربر برای استفاده از سیستم میمونه. ولی به مدت محدود.از: https://blog.larapulse.com/web/jwtروش مرسوم در APIها استفاده از JWT (Json Web Token)‎ هست. این نوع توکن از سه بخش تشکیل شده. بخش اول که بهش header میگن، یک استرینگ json هست که اطلاعاتی مثل نوع توکن و الگوریتم استفاده شده برای امضا رو توی خودش نگه میداره (سمت چپ). در آخر این استرینگ json با base64 کد شده (سمت راست). بخش دوم (payload) اطلاعاتی که ما نیاز داریم برای این توکن رو نگهداری میکنه. مثلا id کاربری که این توکن مال اون هست و یک عدد رندوم برای اینکه توکن‌ها مثل هم نباشن و حتی تاریخ منقضی شدن توکن. این بخش هم استرینگ json هست که با base64 کد شده. بخش سوم JWT، امضا (signature) از بخش اول و دوم هست که با یک کلید محرمانه که سمت سرور داریم درست میشه. با این امضا میشه مطمئن بود که توکن‌هایی که میسازیم توسط هیچ‌کسی امکان جعل شدن نداره. هر سه بخش با یک نقطه به هم وصل میشن و توکن ما رو تشکیل میدن.نتیجه‌گیریِ مقدمهخب توی اپ nestjs خودمون، ما نیاز به یک endpoint برای لاگین داریم که یوزرنیم و پسورد رو بگیره و اون‌ها رو چک کنه، اگر درست بود JWT برای کاربر برگردونه. از اون به بعد کافیه کاربر توی هر ریکوئست JWT رو بفرسته و ما سمت backend هر جایی که نیاز داشتیم از یک گارد (جلوتر باهاش آشنا میشیم) که JWT رو چک می‌کنه برای محافظت از endpointهایی که نیاز به اعتباریابی کاربر دارن استفاده می‌کنیم.پیاده‌سازی...نصب مواد مورد نیازبرای پیاده‌سازی این ویژگی، نیاز به hash.js برای هش کردن پسورد (پسورد خام رو کسی توی دیتابیس نگهداری نمی‌کنه)، passport (کتابخونه‌ای برای اعتباریابی کاربر با استفاده از روش‌های مختلف) و ماژول ‎@nestjs/passport (برای استفاده از passport در nestjs) و ‎passport-jwt (روش JWT در passport) و همچنین ‎@nestjs/jwt (ماژولی برای راحت کردن کار با JWT) داریم. که خب نصب می‌کنیم.npm install hash.js passport passport-jwt @nestjs/passport @nestjs/jwt
npm install -D @types/passport-jwtایجاد ماژول و entityاول از همه یه ماژول جدید به نام auth میسازیم. این بار از nest cli استفاده می‌کنیم. کامند زیر رو اجرا می‌کنیم.npx nest generate module authاین کامند یک پوشه برای ماژول و کلاس ماژول رو میسازه. توی BootstrapModule هم ماژول جدید رو اضافه می‌کنه.بعد از اون باید کلاس کاربر رو توی سیستم تعریف کنیم. توی پوشه auth یک فایل به نام user.entity.ts با محتوای زیر ایجاد می‌کنیم.user.entity.ts به این شکل entityمون رو توی ماژول رجیستر می‌کنیم.auth.module.tsسرویس JWTاول از همه فایل auth.constants.ts رو برای نگهداری ثابت‌های ماژول ایجاد می‌کنیم.auth.constants.tsقبلا ماژول ‎@nestjs/jwt رو نصب کردیم. این ماژول سرویسی به نام JwtService رو پیاده‌سازی کرده که میتونیم با ایمپورت کردن ماژول توی ماژول خودمون، به این سرویس دسترسی داشته باشیم.auth.module.tsایجاد و پیاده‌سازی سرویس Authبرای نوشتن منطق لاگین کاربر نیاز به یک سرویس داریم. اون هم اینطوری ایجاد می‌کنیم:npx nest generate service authاین دستور یک سرویس به نام auth توی پوشه auth (پوشه ماژولمون) ایجاد می‌کنه و سرویس رو توی ماژول رجیستر می‌کنه. یک فایل تست (spec) هم ایجاد می‌کنه که پاکش می‌کنیم. (سعی کنید تست رو توی روند کار خودتون داشته باشید، به علت ضیغ وقت توی این مقاله تست نداریم)توی سرویس قرار هست که یوزرنیم و پسورد کاربر رو بگیریم و اگر درست بود JWT برگردونیم برای کاربر. اگر هم درست نبود خطایی رو نشون کاربر میدیم.auth.service.tsهمونطور که میبینید، توی constructor، آبجکت JwtService و User Repository رو دریافت کردیم. توی متد لاگین که نوشتیم، email و password رو دریافت کردیم، دنبال یوزری با ایمیل داده شده می‌گردیم. اگر همچین کاربری پیدا نشه، متد findOne مقدار undefined برمیگردونه و اگر پیدا بشه، آبجکت user رو. یوزر پیدا نشده باشه خطایی رو پرتاب می‌کنیم که Nest خطایی برای کاربر میفرسته.اگر کاربر پیدا شده باشه، هش پسورد ارسال شده توسط کاربر رو حساب می‌کنیم و با هش پسورد ذخیره شده توی دیتابیس مقایسه می‌کنیم. اگر هر دو هش یکی باشه، یعنی پسورد اولیه که به تابع هش دادیم هم یکی بوده و پسورد درست هست. بنابراین توکن Jwt رو با استفاده از JwtService ایجاد و امضا می‌کنیم. توی payload فقط id کاربر رو میذاریم. پارامتر بعدی هم زمان منقضی شدن توکن هست که ما 24 ساعت در نظر گرفتیم (بر حسب ثانیه هست). در آخر هم توکن رو به عنوان خروجی متد میفرستیم.ایجاد کنترلربرای ایجاد controller از دستور زیر استفاده می‌کنیم.npx nest generate controller authاینم نگم چیکار می‌کنه دیگه.. خودتون میدونید ;)نکته: دستورات حالت خلاصه هم دارن، میتونید با npx nest راهنمای دستورات و خلاصه‌ها رو ببینید.بعد از generate کردن، به این شکل پیاده‌سازی می‌کنیم.auth.module.tsتوی constructor فقط AuthService رو دریافت می‌کنیم. بعد از اون یک متد با دکوراتور Post داریم که فقط برای متد HTTP POST کار می‌کنه. توی اون با استفاده از Body، از اطلاعات پست شده توسط کاربر، email و password رو میگیریم و خیلی ساده متد login از AuthService رو صدا می‌زنیم و محتوای اون رو برمیگردونیم تا برای کاربر ارسال بشه.تست، تست، تستبهتره تا اینجای کار رو یک دور تست کنیم، بعد ادامه کار رو داشته باشیم. از اونجایی که هنوز کاربری توی دیتابیس نداریم و قابلیت ثبت‌نام کاربر هم نداریم، دستی دیتابیس رو باز می‌کنیم و کاربر رو اضافه می‌کنیم.برای این کار یک بار npm run start:dev رو بزنید که دیتابیس با entityها سینک بشه.بعدش SQLite Browser رو نصب کنید. توی این برنامه، Open Database رو بزنید، فایل app.db پروژه رو باز کنید. سپس روی جدول user راست کلیک کنید و Browse Table رو بزنید. دکمه New Record رو بزنید و توی سطر ایجاد شده، ایمیل و هش پسورد زیر رو وارد کنید. بعد هم Write Changes رو وارد کنید.email: sample@sample.compassword: 3627909a29c31381a071ec27f7c9ca97726182aed29a7ddd2e54353322cfb30abb9e3a6df2ac2c20fe23436311d678564d0c8d305930575f60e2d3d048184d79این متن پسورد، هش شده‌ی 12345 هست. حالا میتونیم با این کاربر، لاگین رو تست کنیم.این ریکوئست رو توی Postman وارد می‌کنیم. و بعد از پست کردن اون.. توکن رو دریافت می‌کنیم. پس همه مراحل خوب انجام شده و لاگینمون کار می‌کنه.Postman login requestپیاده‌سازی Jwt Guardتوی nestjs، گاردها ساختاری هستن برای محافظت کنترلرهامون. توی ماژول ‎@nestjs/passport گارد از قبل تعریف شده‌ای وجود داره که در لایه‌های زیرین از کتابخونه passport برای لاگین کاربر استفاده می‌کنه. کار ما این هست که Jwt Strategy رو برای استفاده درون این ماژول تعریف کنیم.فایل jwt.strategy.ts رو میسازیم.jwt.strategy.tsمتد getUserById که به AuthService اضافه شده، به صورت زیر هست:بخشی از auth.service.tsتوی این استراتژی، از استراتژی موجود در passport-jwt ارث بری می‌کنیم و اون رو با مقادیر خودمون کانفیگ می‌کنیم. توی constructor این کلاس، constructor کلاس ارث‌بری شده رو با super صدا میزنیم و مقادیر لازم رو بهش ارسال می‌کنیم. توی متد validate هم، payload جدا شده از JWT برای ما ارسال میشه و باید بررسی کنیم که آیا درست هست یا نه. چون ما id رو توی payload ذخیره می‌کردیم، کاربری با این id پیدا بشه یعنی JWT درسته، پس کاربر رو برمیگردونیم. اگر نه خطا میدیم.حالا کافیه توی ماژول auth، کلاس JwtStrategy و ماژول PassportModule رو رجیستر کنیم.auth.module.tsالان میتونیم از AuthGuard که توسط ماژول ‎@nestjs/passport پیاده‌سازی شده و در لایه زیرین از کتابخونه passport استفاده می‌کنه و به JwtStrategy که پیاده‌سازی کردیم وصله، توی کنترلرمون استفاده کنیم.بخشی از todo.controller.tsبا این کار استفاده از کنترلر رو ملزم به ارسال توکن Jwt میکنیم و passport از JwtStrategy ما استفاده می‌کنه و کاربر رو اعتباریابی می‌کنه.هر کاربر، Todoهای متفاوتبرای اینکه هر کدوم از کاربرها Todoهای متفاوتی داشته باشن باید ساختار entity برای Todo رو تغییر بدیم. ارتباط Todo به User یک ارتباط چند به یک هست. یعنی چند Todo میتونن به یک کاربر ربط داده بشن.بخشی از todo.entity.tsاینجا ما یک property جدید توی کلاسمون ایجاد کردیم و با دکوراتور ManyToOne، رابطه اون با User رو مشخص کردیم.نکته: اگر از قبل Todo توی دیتابیس داشتید، احتمالا با اجرای برنامه به دلیل تغییر ساختار جداول به مشکل میخورید. باید فایل app.db قبلی رو پاک کنید و دوباره برنامه رو اجرا کنید تا فایل با ساختار جدید ایجاد بشه. البته همه Todo ها و کاربری که چند پاراگراف قبل ایجاد کردیم هم پاک میشه. کاربر رو دوباره ایجاد کنید که بهش نیاز داریم.حالا سرویسمون رو جوری می‌نویسیم که موقع ذخیره Todo و گرفتن از دیتابیس، User رو در نظر بگیره.todo.service.tsهمونطور که میبینید، توی constructor، آبجکت ریکوئست رو دریافت می‌کنیم. این آبجکت اطلاعاتی راجع به ریکوئست کاربر در اختیار داره. مثل header های ریکوئست. هنگامی هم که از ماژول passport استفاده می‌کنید، کاربری که اعتباریابی اون انجام شده به این آبجکت اضافه میشه، پس با ریکوئست به آبجکت کاربر دسترسی داریم.حالا کافیه هر جایی که نیاز هست، این کاربر رو در ذخیره کردن و گرفتن Todoها از دیتابیس دخیل کنیم. توی شرط‌هایی find و توی آبجکتی که برای save میفرستیم!تستبرای تست این مطالب تازه اضافه شده، ابتدا باید لاگین کنید و یک توکن جدید بگیرید. لاگین رو که قبلا گفتیم...با در دست داشتن توکن، توی Headerهامون، یک بخش به صورت:Authorization: Bearer {token}اضافه می‌کنیم و درخواست‌هامون رو با این Header ارسال می‌کنیم. بقیه مراحل مثل بخش اول هست. برای ایجاد و آپدیت و دیلیت و گرفتن Todoها میتونید endpointهای مختلفی که داشتیم رو تست کنید.Postman Authorization headerسخن پایانیامیدوارم که این نوشته برای شما مفید بوده باشه. بخش آخر یکم عجله‌ای شد. اگر مشکلی در نوشته‌ها هست یا سوالی در این خصوص هست میتونید توی کامنت‌ها بگید.سورس کامل پروژه هم میتونید توی این مخزن گیت‌هاب پیدا کنید.</description>
                <category>حسین صادقی</category>
                <author>حسین صادقی</author>
                <pubDate>Fri, 23 Aug 2019 20:16:23 +0430</pubDate>
            </item>
                    <item>
                <title>ساختن بک‌اند تایپ‌اسکریپتی - بخش ۳: دیتابیس!</title>
                <link>https://virgool.io/iran-nodejs-community/%D8%B3%D8%A7%D8%AE%D8%AA%D9%86-%D8%A8%DA%A9%D8%A7%D9%86%D8%AF-%D8%AA%D8%A7%DB%8C%D9%BE%D8%A7%D8%B3%DA%A9%D8%B1%DB%8C%D9%BE%D8%AA%DB%8C-%D8%A8%D8%AE%D8%B4-%DB%B3-%D8%AF%DB%8C%D8%AA%D8%A7%D8%A8%DB%8C%D8%B3-bbk2njhmiwhj</link>
                <description>NestJSسرفصل‌هافریمورک NestJS چیست و چرا؟شروع پروژه Todoدیتابیس!هر کاربر، Todoهای متفاوتاگر این سری نوشته‌ها رو دنبال کرده باشید، میدونید که رسیدیم به اونجا که API خودمون رو برای اپلیکیشن ذخیره Todoها ایجاد کردیم و عملیات ایجاد کردن Todo، لیست کردن و گرفتن جزئیات یک Todo، آپدیت و حذف رو پیاده‌سازی کردیم و اطلاعات رو ذخیره می‌کردیم، ولی توی مموری!برای کار با دیتابیس و ذخیره‌سازی دائمی داده‌ها، NestJS ماژولی برای کار با TypeORM (که بهترین ORM تایپ‌اسکریپتی هست به نظر من :)) ارائه داده که کار رو ساده خیلی می‌کنه.در ادامه این نوشته، با استفاده از این ORM اپلیکیشنمون رو تغییر میدیم و داده‌ها رو در دیتابیس ذخیره می‌کنیم. بریم بیایم.قبل از شروعتوی بخش قبلی ما ماژول Todo رو ساختیم و همون رو به عنوان پارامتر به متد create از NestFactory دادیم. ولی با گسترش اپلیکیشن ما فقط ۱ ماژول نداریم که بتونیم این کار رو بکنیم، برای همین ماژولی رو در نظر میگیریم که وظیفه اون فقط و فقط import کردن بقیه ماژول‌ها هست (هیچ سرویس و کنترلی نداره) و اون رو میدیم به NestFactory. من اسم این ماژول رو میذارم BootstrapModule، به این صورت:bootstrap.module.tsحالا دیگه میتونیم بقیه ماژول‌هامون رو هم پیاده‌سازی کنیم و خیلی راحت اینجا import کنیم تا لود بشه.TypeORMاین ORM بر روی ایده‌هایی از Hibernate توی جاوا و Entity Framework توی .NET بنا شده و با استفاده از Decoratorها کار با دیتابیس و عملیات‌های مختلف روی اون رو تا حد زیادی ساده کرده.برای شروع باید این رو پکیج رو نصب کنیم:npm install typeorm @nestjs/typeormبرای این آموزش ما از دیتابیس sqlite استفاده می‌کنیم که باید درایور اون رو هم نصب کنیمnpm install sqilte3بعد از اون، ماژول TypeORM رو توی اپلیکیشن خودمون import می‌کنیم و کانفیگ دیتابیس رو بهش میدیم تا بتونه وصل بشه. کجا بهتر از BootstrapModule میتونه باشه P:ایمپورت TypeORMتوی چند خط اضافه شده، همونطور که قبلا ذکر شد، ماژول TypeOrm رو import کردیم و کانفیگ دیتابیس رو بهش پاس دادیم. متد forRoot یکبار برای اتصال اپلیکیشن به دیتابیس استفاده میشه و متد دیگری به نام forFeature هم وجود داره که جلوتر با اون آشنا میشیم.خط اول توی آبجکت کانفیگ، نوع دیتابیس هست. اینجا از دیتابیس sqlite استفاده می‌کنیم که کل دیتابیس رو توی یک فایل ذخیره می‌کنه و ساده و جمع و جور هست. برای دیتابیس‌های دیگه‌ای که توی production استفاده میشه کانفیگ متفاوتی نیاز هست که تمامی اون‌هارو می‌تونید توی این لینک ببینید.خط دوم کانفیگ، آدرس فایل دیتابیس هست. اگر قبلا دیتابیس خاصی نداشتید هر اسمی میتونید بدید و در صورت نبود اون، اپلیکیشن فایل رو درست می‌کنه.خط سوم و چهارم توی همه نوع دیتابیس‌ها مشترک هست. خط سوم آدرس موجودیت‌های سیستم رو تعریف می‌کنه (TypeORM برای خوندن decoratorها و ایجاد اطلاعات اون‌ها به این گزینه نیاز داره). خط آخر هم جداول دیتابیس رو با چیزایی که توی اپلیکیشن تعریف کردیم یا تغییر دادیم همگام‌سازی می‌کنه. این گزینه سرعت توسعه رو خیلی بالا میبره و برای محیط توسعه عالی هست. ولی برای production باید غیرفعال بشه.شناسایی Entity?توی بخش قبل ما Entity سیستم رو تعریف کردیم. برای اینکه TypeORM بتونه اون رو شناسایی کنه و به خوبی توی دیتابیس جدول رو بسازه و داده‌ها رو ذخیره کنه، باید از decoratorهای TypeORM استفاده کنیم و  Entity خودمون رو برای TypeORM تعریف کنیم.todo.entity.tsبا یه نگاه ساده میشه فهمید که هر کدوم از Decoratorها چه کاری می‌کنه.دکوراتور Entity که مشخص می‌کنه این کلاسمون یک Entity درون سیستم هست و باید برای اون یک Table توی دیتابیس درست بشه.برای مشخص کردن ستون‌های دیتابیس هم دکوراتورهای مختلفی وجود داره که چندتاش رو استفاده کردیم.برای ستون‌های عادی از دکوراتور Column استفاده میشه. در حالت عادی نوع ستون با توجه به نوع فیلد به صورت اتوماتیک انتخاب میشه اما برای انواع پیچیده‌تر، باید نوع ستون رو به عنوان ورودی به این دکوراتور پاس بدید. برای کنترل بیشتر (مثل طول ستون کاراکتری) هم این دکوراتور آبجکتی دریافت می‌کنه که این تنظیمات رو مشخص می‌کنه. مثلا nullable بودن فیلد مثل completeTime. توی این قسمت داکیومنت TypeORM توضیحات کامل این موارد قرار داده شده.دکوراتور PrimaryGeneratedColumn برای مشخص کردن ستون به عنوان کلید اصلی و generated (که به صورت اتوماتیک توسط دیتابیس تولید میشه) به صورت همزمان هست.فیلدهای حاوی دکوراتورهای CreateDateColumn و UpdateDateColumn هم به صورت اتوماتیک هنگام ایجاد و آپدیت این entity، ایجاد و آپدیت میشن.حالا برای اینکه توی ماژول خودمون، یعنی TodoModule به TypeORM و ریپاسیتوری‌های این entity دسترسی داشته باشیم، باید ماژول TypeORM رو با متد forFeature ایمپورت کنیم و entity های مورد نظرمون رو به عنوان پارامتر به این متد پاس بدیم!todo.module.tsبا افزودن این چند خط، به ماژول TypeORM توی این ماژول دسترسی خواهیم داشت. همچنین repository ایجاد شده برای entityمون Todo رو میتونیم داشته باشیم.مرحله آخرخب الان همه چیز سر جاشه? باید از قابلیت‌هایی که تا اینجا بدست آوردیم، استفاده کنیم و داده‌هامون رو ذخیره کنیم. این دفعه توی دیتابیس و برای همیشه.جایی از برنامه که باید تغییر کنه، سرویس‌هامون هست. سرویس Todo رو به شکل زیر تغییر میدیم.todo.service.tsخب! تغییراتی که inject کردن Repository توی constructor و استفاده از این Repository توی همه متدهامون هست. (storage و lastId که برای ذخیره توی مموری نیاز داشتیم رو هم حذف کردیم).در حالت عادی برای استفاده از Injection اینکه تایپ فیلد رو داشته باشیم کافی هست، اما چون Repository تایپ Generic داره و قابلیت‌های Typescript برای خوندن تایپ‌ها توی برنامه کم هست، به دکوراتور InjectRepository نیاز داریم.اول این نکته رو بگم که Repository پیاده‌سازی شده طبق Repository Pattern هست. طبق این پترن شما مستقیماً با دیتابیس تعامل ندارید و از کلاس‌های repository برای ذخیره و حذف و ... استفاده میشه. اینطوری راحت‌تر میشه تست کرد و تغییر داد قسمت‌های مختلف رو.حالا توی متدهای مختلفمون از این repository استفاده می‌کنیم و کارهایی که قبلا توی مموری انجام میدادیم رو با دیتابیس انجام میدیم.چون کار با دیتابیس زمان‌بر هست و async انجام میشه، همه متدهامون async هستن و خروجی اون‌ها Promise خواهد بود.توی متد getTodo از Repository.findOneOrFail استفاده کردیم که یک آبجکت با شرایط خاص (یا مثل اینجا id خاص) رو برمیگردونه. اگر همچین آبجکتی وجود نداشت، exceptionی رخ میده که اینجا هندل نکردیم و کاربر اون رو میبینه.توی متد getTodos هم از Repository.find استفاده کردیم که آرایه‌ای از آبجکت‌ها با شرایط خاص رو برمیگردونه.توی متد createTodo، آبجکت Todo رو داشتیم و توسط متد Repository.save اون رو توی دیتابیس ذخیره کردیم. توجه داشته باشید که خروجی این متد آبجکت کاملمون هست که توی دیتابیس ذخیره شده. برای مثال توی ورودی ما createTime و updateTime وجود نداشت اما توی آیجکتی که از Repository.save میگیریم این فیلدها نیز مقداردهی شده.توی متد updateTodo، آبجکت با آیدی که میخوایم آپدیت کنیم رو از دیتابیس گرفتیم. با استفاده از اون و مقادیر جدیدی که کاربر بهمون داده، آبجکت جدیدی درست کردیم و اون آبجکت جدید رو توی دیتابیس ذخیره کردیم. به دلیل اینکه id یا همون Primary Column مون توی آبجکت نهایی وجود داره، عملیات update با استفاده از Repository.save رخ میده. اما توی متد قبلی همین save رو برای create استفاده کردیم.توی متد deleteTodo هم از Repository.delete استفاده کردیم که آبجکت‌های با شرایط خاص (یا مثل متدهای قبلی با id خاص) رو حذف می‌کنه.خب سرویسمون با این تغییرات، از این به بعد todo ها رو توی دیتابیس ذخیره می‌کنه. و نیازی به دست زدن به بقیه اجزای برنامه نداریم. تنها تغییر کنترلرها، افزودن async/await هست که به خوانایی برنامه کمک می‌کنه.todo.controller.tsهمین دیگه.حالا با اجرای برنامه، فایل دیتابیس sqlite ساخته میشه. به دلیل اینکه توی تنظیمات TypeORM گزینه synchronize رو برابر true قرار دادیم، دیتابیس با Entityهای ما همگام‌سازی میشه و اگر با برنامه‌ای که دیتابیس sqlite رو میخونه، فایل دیتابیس رو باز کنید میبینید که جداول مطابق اون چیزی که خواسته بودیم ساخته شدن.مثل بخش قبل میتونیم آدرس‌های مختلف رو تست کنیم؛ این قسمت رو به خودتون میسپارم P-:جمع بندیتوی این بخش، اطلاعات برنامه رو توی دیتابیس نگهداری کردیم تا با بستن و اجرا کردن دوباره برنامه اطلاعاتمون از بین نره. در این راه از sqlite به عنوان دیتابیس و TypeORM به عنوان لایه ارتباط entity ها با دیتابیس استفاده کردیم.مشکل بعدیمشکلی که هنوز حل نکردیم این هست که همه اطلاعات برای همه کاربران قابل دسترسی هست. ولی خب Todoهای هر کسی با Todoهای کس دیگه فرق داره. بخش بعدی به این میپردازیم که چگونه کاربر توی سیستم تعریف کنیم، اون رو احراز هویت کنیم درون سیستم و Todoهای مخصوص خودش رو براش بسازیم!به پیشنهاد Majid ganji سورس پروژه رو روی گیت‌هات قرار دادم. از اینجا میتونید ببینید.</description>
                <category>حسین صادقی</category>
                <author>حسین صادقی</author>
                <pubDate>Sat, 10 Aug 2019 20:53:03 +0430</pubDate>
            </item>
                    <item>
                <title>ساختن بک‌اند تایپ‌اسکریپتی با NestJS - بخش ۲: شروع پروژه Todo</title>
                <link>https://virgool.io/iran-nodejs-community/%D8%B3%D8%A7%D8%AE%D8%AA%D9%86-%D8%A8%DA%A9%D8%A7%D9%86%D8%AF-%D8%AA%D8%A7%DB%8C%D9%BE%D8%A7%D8%B3%DA%A9%D8%B1%DB%8C%D9%BE%D8%AA%DB%8C-%D8%A8%D8%A7-nestjs-%D8%A8%D8%AE%D8%B4-%DB%B2-%D8%B4%D8%B1%D9%88%D8%B9-%D9%BE%D8%B1%D9%88%DA%98%D9%87-todo-mb1bxwk5pqgh</link>
                <description>NestJSسرفصل‌هافریمورک NestJS چیست و چرا؟شروع پروژه Todoدیتابیس!هر کاربر، Todoهای متفاوتتوی بخش اول، بیشتر سعی کردیم با خودِ فریمورک آشنا بشیم و بفهمیم که چطوری کار می‌کنه. وقتشه بریم سراغ پروژه تا درک عمیق‌تری بدست بیاریم.پروژه‌ای که قرار هست انجام بدیم اپلیکیشنی برای وظایف (همون Todo) هست. درسته موضوع خیلی کلیشه‌ای هست اما خب هم به قدر کافی ساده هست که بشه توی چندتا نوشته تمامش کرد و هم انقدر پیچیده هست که مفاهیم مختلف NestJS رو یاد بگیریم، پس انتخاب خوبیه.شروع ? برای ساخت پروژه todo دستور &#x60;nest new todo-app&#x60; رو میزنیم. این دستور همه‌ی پکیج‌های مورد نیاز رو نصب می‌کنه و کنترلر و سرویس Hello World هم ایجاد می‌کنه.غیر از main.ts بقیه فایل‌های ایجاد شده به درد ما نمی‌خوره، پاکشون کنید.ماژول Todoبرای نوشتن app خودمون یک ماژول جدید ایجاد می‌کنیم. برای ایجاد ماژول جدید میشه از cli هم استفاده کرد. اما برای درک بهتر خودمون این کار رو انجام میدیم. یک پوشه به نام todo ایجاد کنید. این پوشه همه‌ی اجزای مختلف ماژول رو در بر می‌گیره. حالا باید فایل todo.module.ts رو درست کنیم و محتوای زیر رو داخلش بنویسیم.ماژول Todoالان ماژولمون آماده هست. بریم سراغ کدهای اصلی.تعریف موجودیت‌ها (Entity)به نوع داده‌هایی باهاشون کار می‌کنیم و ذخیره می‌کنیم و برای کاربر میفرستیم موجودیت (Entity)های سیستم میگن. موجودیت‌ها توی هر زبانی کلاس‌های معمولی همون زبان هستن.برای اپ Todo نیاز به یک کلاس داریم که همون Todoهامون رو توش ذخیره کنیم. فایل todo-item.entity.ts رو با محتوای زیر درست می‌کنیم.کلاس Todoتوی این فایل کلاس Todo رو ایجاد کردیم. propertyهای کلاس id برای پیدا کردن Todo خاص، text که همون متن Todo هست، completed برای مشخص کردن اینکه این آیتم انجام شده یا نه. دو فیلد createTime و completeTime هم برای ذخیره زمان ایجاد و انجام شدن آیتم هستن.سرویس Todoتوی این سرویس میخوایم عملیات ساختن، گرفتن، آپدیت کردن و حذف کردن این Entity رو انجام بدیم. فایل todo.service.ts رو میسازیم و برای هر کدوم از این کارها. یک متد ایجاد می‌کنیم.سرویس Todoتوی خط ۴ از دکوراتور Injectable استفاده کردیم تا این سرویس قابل Inject شدن توی کلاس‌های دیگه باشه.توی خط ۶ آرایه خالی برای ذخیره Todoهامون ایجاد می‌کنیم. فعلا Todoها رو توی مموری ذخیره می‌کنیم.خط ۷ هم متغیری برای ذخیره id های اختصاص داده می‌گیریم تا id ها یکتا باشن.متد getTodo ورودی id دریافت می‌کنه و خروجی اون هم یک Todo هست. توی این متد آرایه رو می‌گردیم تا Todo با اون id رو پیدا می‌کنیم. اگر پیدا نشد خطای Not Found رو میفرستیم و اگر پیدا شد اون رو برمیگردونیم.متد getTodos همه‌ی Todoها (کل آرایه) رو برمیگردونه.متد createTodo، آبجکت Todo دریافت می‌کنه، آیدی به اون اختصاص میده و اون رو توی آرایه ذخیره می‌کنه.متد updateTodo هم آبجکت Todo دریافت می‌کنه. سپس ایندکس Todo با آیدی اون رو توی آرایه ذخیره شده پیدا می‌کنه و اون ایندکس آرایه رو با آبجکت جدید جایگزین می‌کنه.متد deleteTodo هم آیدی آبجکتی که قصد حذفش رو داریم دریافت می‌کنه، ایندکسش رو توی آرایه پیدا می‌کنه و اون رو با استفاده از متد splice از آرایه حذف می‌کنه.کنترلر Todoکنترلر Todoاین کنترلر هم خیلی ساده هست. فقط داریم متدهای مختلفی که توی سرویس تعریف کردیم رو صدا می‌زنیم و استفاده می‌کنیم.چندتا چیز جدید اینجا هست.توی دکوراتور Controller اینجا todo رو وارد کردیم. برای همین همه Get و Post و ...هایی که توی این کنترلر داریم با این آدرس شروع میشن.توی خط ۸ هم TodoService رو توی کنترلر Inject کردیم. این جدید نبود ولی دوست داشتم دوباره بگم?توی خط ۱۵، آدرسمون :id رو داریم. این یک جور متغیر توی url هست. هر چیزی ممکنه جای id بیاد. با استفاده از دکوراتور Param به این متغیرها توی url دسترسی داریم. مثلا همون ۱۶ پارامتر id رو گرفتیم.توی خط ۲۰ دکوراتور Body رو داریم که پارامترهایی که توی بدنه درخواست پست شدن رو بهمون میده. اینجا بدنه درخواست باید نوع Todo داشته باشه.حالا کافیه سرویس و کنترلر رو توی ماژول todo رجیستر کنیم و توی main.ts این ماژول رو به NestFactory بدیم.todo.module.tsmain.tsوقت تست!تا اینجای کار یک اپ نوشتیم که Todoها رو میسازه، لیست می‌کنه، آپدیت و حذف می‌کنه. وقتشه که تست کنیم ببینیم واقعاً کار می‌کنه؟برای تست از Postman استفاده می‌کنیم. اول اپ رو با دستور npm run start:dev اجرا می‌کنیم و عملیات مختلف رو تست می‌کنیم.وقتی که درخواست خودمون رو با پارامترهای مورد نیاز به آدرس /todo/ بفرستیم، کنترلر createTodo درخواست رو هندل می‌کنه و Todo مورد نظر ما رو ایجاد می‌کنه. خروجی درخواست هم todo با اطلاعات کامل هست که پایین میتونید ببینید. با ارسال درخواست GET به همون آدرس، کنترلر getTodos مسئولیت هندل کردن درخواست رو بر عهده میگیره و آرایه همه Todoهای ذخیره شده رو برای ما میفرسته.متدهای Update و Delete و گرفتن جزئیات یک Todo خاص رو هم با درخواست به آدرس todo/1 میشه برای این todo ساخته شده انجام داد.در آخر هم با زدن Ctrl + C میتونید اپ خودتون رو ببندید.اگر دوباره اپ رو اجرا کنید و آدرس /todo/ رو ببینید، مشاهده می‌کنید که همه‌ی اطلاعات و Todo هایی که ساخته بودیم پاک شده :-\ در واقع ما همه چیز رو توی مموری ذخیره کردیم و مادامی که اپ ما در حال اجرا هست این مموری رو داره. پس بعد از بستن اپ اطلاعات به صورت کامل از بین میره.توی نوشته بعدی برای حل این مشکل اپ Nest رو به دیتابیس وصل می‌کنیم و داده‌هامون رو برای همیشه درون دیتابیس نگهداری می‌کنیم.</description>
                <category>حسین صادقی</category>
                <author>حسین صادقی</author>
                <pubDate>Sun, 21 Jul 2019 19:27:36 +0430</pubDate>
            </item>
                    <item>
                <title>ساختن بک‌اند تایپ‌اسکریپتی با NestJS - بخش ۱: NestJS چیست و چرا؟</title>
                <link>https://virgool.io/JavaScript8/%D8%B3%D8%A7%D8%AE%D8%AA%D9%86-%D8%A8%DA%A9%D8%A7%D9%86%D8%AF-%D8%AA%D8%A7%DB%8C%D9%BE%D8%A7%D8%B3%DA%A9%D8%B1%DB%8C%D9%BE%D8%AA%DB%8C-%D8%A8%D8%A7-nestjs-%D8%A8%D8%AE%D8%B4-%DB%B1-nestjs-%DA%86%DB%8C%D8%B3%D8%AA-%D9%88-%DA%86%D8%B1%D8%A7-afrkrhtczpbp</link>
                <description>               NestJSتوی این رشته نوشته‌ها قصد داریم با فریمورک NestJS آشنا شیم و بعدش با هم یک پروژه کوچیک درست کنیم.هدفتوی این پست بیشتر با خود NestJS و ساختار اون آشنا میشیم. توی پست‌های بعدی سراغ پروژه خودمون میریم. پروژه‌ای که قرار هست درست کنیم بک‌اند برای یک اپ Todo هست. شامل نوشتن کنترلرها و سرویس‌ها، کار با دیتابیس، ورود کاربران و اعتباریابی و حالا اگر چیز دیگه‌ای هم بود میگیم?.سرفصل‌هافریمورک NestJS چیست و چرا؟شروع پروژه Todoدیتابیس!هر کاربر، Todoهای متفاوتکمی درباره NestJSفریمورک NestJS به قول سازندش اومده که یک مشکل حل نشده توی فریمورک‌های جاوااسکریپت رو حل بکنه، یعنی معماری!فریمورک‌هایی مثل Express ،Koa و ... ابزارهای مورد نیاز برای ساختن بک‌اند رو به شما میدن و شما آزاد هستید که هر طور دلتون میخواد بخش‌های مختلف پروژه رو بچینید که این انعطاف‌پذیری خیلی زیادی به شما میده.. ولی یکی از ضعف‌های این روش این هست که همواره باید دنبال best practice ها بگردید که این برای بعضی‌ها مثل من سخته راستش.در مقابل فریمورک NestJS شما رو ملزم می‌کنه توی یک چارچوب مشخص کدزنی کنید (و شاید انعطاف‌پذیری گزینه‌های قبلی رو نداشته باشه) ولی می‌تونید مطمئن باشید این چارچوب برگرفته از best practiceها و تجارب سالیان از بهترین فریمورک‌هاست.(توی این پرانتز این رو هم بگم که فریمورک NestJS خیلی از ایده‌ها رو از Angular گرفته و برای کسایی که با Angular کار کردن بسیار آشنا خواهد بود.)ساختار برنامهتوی NestJS اجزای برنامه به قطعات کوچکتر به نام ماژول تقسیم میشن. هر ماژول مثل یک دسته‌بندی هست که سرویس‌ها و کنترلرهای مربوط به هم رو در بر می‌گیره. این ماژول‌ها مثل تیکه‌های پازل همدیگه رو تکمیل می‌کنن و اپ ما رو تشکیل می‌دن. مثلا یک برنامه فروشگاه میتونه شامل ماژول محصولات، ماژول پرداخت، کاربران و ... باشه.پس ماژول یک جور دسته‌بندی منطقی برای اجزای برنامه هست تا کدهامون قاطی نشه. ولی کار اصلی توی اجزای ماژول انجام میشه.ساختاری که توی NestJS پیشنهاد شده برای کدها در نظر بگیریم معماری سه لایه (three-layer architecture) هست.عکس از pinte.ro توی این ساختار اولین لایه‌ای که با کاربر ارتباط داره، لایه رابط کاربری (همون کنترلرهامون) هستن. پیشنهاد شده که این لایه کمترین کد ممکن رو داشته باشه و خالی از منطق باشه.منطق اصلی برنامه توی سرویس‌ها قرار می‌گیره. سرویس‌ها پردازش‌های لازم رو انجام میدن و ارتباط با دیتابیس و دسترسی به داده‌ها هم توسط لایه Data Access فراهم می‌شه.با این مفاهیم به صورت عملی توی پروژه آشنا میشیم. خب دیگه تئوری بسه بریم وارد کار بشیم.شروع کار‍فریمورک NestJS ابزار CLI خیلی قوی داره که خیلی از کارها رو راحت میکنه. برای نصب اون دستور زیر رو اجرا کنید.npm i -g @nestjs/cliحالا میتونیم با دستور زیر پروژه جدید ایجاد کنیم:nest new [project-name]بعد از اجرای این دستور (و انتخاب package manager دلخواهتون) nest براتون کلی فایل درست می‌کنه. حالا با دستور npm run start:dev، سرور شروع به کار میکنه و روی پورت ۳۰۰۰ لوکال هاست، میتونید خروجی اپ تولید شده رو ببینید!همین. فقط میگه Hello World? ولی برای تولید این خروجی توی nest کلی اتفاق افتاده.?کنترلر چیستگفتیم اولین تیکه‌ای که درخواست میرسه دستش و شروع می‌کنه به تلاش برای پاسخ دادن، controllerهامون هستن.محتویات app.controller.tsهمونطور که مشاهده می‌کنید کنترلرهامون کلاس‌های ساده هستن. این کلاس یک فیلد برای ذخیره آبجکت AppService داره و این آبجکت رو توی constructor گرفته و ذخیره کرده (چیزی که nest تولید کرده خلاصه شده همین تعریف فیلد و مقدار دهی توی تایپ‌اسکریپت هست، حالا که یاد گرفتید از همون استفاده کنید).از decoratorها (اون تیکه‌هایی که با @ شروع شدن) استفاده زیاد و مفیدی توی nest شده. اینجا دکوراتور ‎@Controller()‎ مشخص می‌کنه که کلاس AppController حاوی متدهایی برای پردازش درخواست‌هاست و آدرس‌هایی که توی این کلاس گفتیم باید توی راهیاب (router) خود nest رجیستر بشن.دکوراتور ‎@Get()‎ مشخص می‌کنه که این متد درخواست‌های HTTP GET رو پاسخ میده، توی پرانتز میشه مشخص کرد که برای پاسخ به چه آدرسی هست و چون پرانتز خالی هست، به صورت پیش‌فرض درخواست‌های صفحه / رو پاسخ میده.اممم. پس این Hello World که توی آدرس /‎http://localhost:3000 دیدیم داره از اینجا میاد. پس برای فهمیدن بقیش میتونیم از همینجا پیش بریم. کاری که این متد داره می‌کنه فقط صدا زدن متد getHello روی سرویس appService هست. همونطور که قبلا هم گفتم سعی میشه محتوی متدهای controller خیلی مینیمال باشه. دلیلش هم این هست که بشه راحت‌تر منطق برنامه رو تست کرد و حتی بشه اون رو با کانال‌های مختلف دوباره استفاده کرد (REST API, GraphQL و حتی توی رندر سمت سرور).سرویس‌هاحالا ببینیم منطق برنامه که توی app.service.ts هست چیه...محتوی app.service.tsهمونطور که میبینید سرویس‌ها هم یک کلاس ساده هستن. اینجا از دکوراتور Injectable استفاده شده که مشخص می‌کنه این سرویس قابل Inject شدن توی بخش‌های مختلف اپلیکیشن از طریق Dependency Injection که nest برامون فراهم کرده هست! (راجع به Dependency Injection آخرِ نوشته گفتم).توی سرویس‌ها معمولا به Data Access Layer دسترسی پیدا می‌کنیم و مواردی رو ذخیره می‌کنیم، تغییر میدیم یا حذف می‌کنیم.. اما خب توی این مثال فرستادن رشته Hello World کافی بوده.به دلیل این پروژه تولید شده خیلی ساده نگه داشته بشه برای دسترسی به دیتابیس هیچ فایلی نیست و با این لایه توی پروژه خودمون (Todo App) آشنا میشیم.ماژول، جایی برای وصل کردن همه چیزمحتویات app.module.tsماژول جایی هست که اجزای مختلفمون رو معرفی می‌کنیم. اینجا nest میتونه جستوجوی خودش رو انجام بده و Dependency Injection (پایین‌تر راجع بهش می‌گم) رو برای اجزای متخلف اعمال کنه.ماژول هم یک کلاس ساده (این دیگه خیلی سادست و هیچ بدنه‌ای نداره?) هست که دکوراتور ‎@Module()‎ روش اعمال شده. پارامتر این دکوراتور یک آبجکت هست که خصیصه (property)های اون برای این کاراست:خصیصه imports و exports: این دو خصیصه برای ارتباط بین ماژول‌های مختلف هستن. providerهای ماژول فقط توی بقیه اجزای همون ماژول قابل دسترسی هستن. برای اینکه بقیه ماژول‌ها هم بتونن از اونا استفاده کنن باید توی آرایه exports هم افزوده بشن. آرایه imports هم ماژول‌های دیگه‌ای که توی این بهشون نیاز داریم رو مشخص می‌کنه، با افزودن اونا به این آرایه به اجزای export شده اون‌ها توی این ماژول دسترسی داریم.خصیصه Controllers: این‌ها کنترلرهای ماژول هستن، توی router باید register بشن.خصیصه Providers: این‌ها سرویس‌ها و دیگر اجزای Injectable ما هستن، هر جزئی از ماژول که به این‌ها نیاز داشت توسط Dependency Injection (پایین‌تر گفتم) اون‌ها رو دریافت می‌کنه.نقطه شروعحالا که همه اجزای برنامه رو بررسی کردیم میرسیم به نقطه شروع برنامه.main.tsتوی این نقطه توسط NestFactory آبجکت app رو می‌سازیم و ماژولی که توی اون شروع می‌کنه به گشتن دنبال Controllerها و Providerها و ماژول‌های دیگه که import شدن و اون‌ها رو مقداردهی می‌کنه و بعد روی پورت 3000 وب‌سرور رو اجرا می‌کنیم تا برنامه به درخواست‌ها جواب بده!کمی عمیق‌تر بشویموقتی که متد create رو صدا می‌زنیم، nest شروع می‌کنه به جستوجو توی ماژولی که متد پاس دادیم (اینجا AppModule). اونموقع، از کلاس‌هایی که توی Controllerها و Providerها معرفی کردیم، instanceهایی میسازه و (این وسط کنترلرهامونم توی router رجیستر می‌کنه).تا اینجا که نکته‌ای نداشت. ولی ما توی constructor کلاس AppController یک ورودی داشتیم، appService. با این وجود، چطوری instance این کنترلر رو ساخت؟مثل خیلی از فریمورک‌های دیگه، nest از پترن Dependency Injection استفاده می‌کنه و براتون این پارمترها رو توی constructor فراهم می‌کنه. شما dependencyهای کلاس خودتون توی constructor مشخص می‌کنید (به لطف تایپ‌اسکریپت نوع اون‌ها رو هم مشخص می‌کنید، مثل appService: AppService). حالا nest با کمک Reflection میدونه کنترلر شما به چه کلاس‌هایی نیاز داره و میره توی بخش‌های مختلف Providerها یا Controllerها یا ... دنبال اونا میگرده، اون رو پیداشون میکنه و کلاس شما رو با در اختیار گذاشتن اون‌ها new میکنه. به این کار میگن Dependency Injection.پایان بخش ۱توی این بخش سعی کردیم با nest و اجزای مختلف اون آشنا بشیم. توی بخش‌های بعدی پروژه Todo App رو شروع می‌کنیم.</description>
                <category>حسین صادقی</category>
                <author>حسین صادقی</author>
                <pubDate>Fri, 21 Jun 2019 18:09:10 +0430</pubDate>
            </item>
            </channel>
</rss>