به نام خدا

یکی از فریمورک های اصلی که همیشه با nodejs همراه بوده و خیلی طرفدار داره فریمورک express هست که قبلا توی الفبا یه آموزش مختصری از Route هاش و یه سری از توابعش گذاشتم.

اما امروز میخوایم باهم Adonis js رو یاد بگیریم

این فریمورک الهام گرفته از لاراول php هست که حتی صفحه داکیومنتش شباهت عجیبی داره (سرفصل ها و عنوان های آموزشی یکسانی دارن) و این باعث میشه کسانی که قبلا با لاراول کار کردن به راحتی بتونن با این فریمورک به node js سوییچ کنن (البته که سینتکس زبان جاوا اسکریپت با php تفاوت داره)

خب بریم سراغ آموزشمون

این فریمورک روی معماری MVC کار میکنه (Model View Controller) برای نصبش از خط زیر در ترمینالتون استفاده کنید

npm i -g @adonisjs/cli

توجه: توی این آموزش فقط به ساخت api (بدون ویو و html) میپردازیم (یعنی ویوی ما جیسون هست)

حالا وارد فولدری بشید که میخواید اولین پروژتون رو ایجاد کنید و از دستور زیر استفاده کنید:

adonis new yardstick --api-only

خب حالا میتونید با ادیتور مورد علاقتون (ترجیحا WebStorm) این دایرکتوری رو به عنوان پروژه Node باز کنید

 

معرفی فولدر بندی و توضیحات هر فولدر

خب حالا از اینجا شروع میکنیم به شناختن فولدر ها و فایل ها:

فولدر app: کل برنامه شما شامل controller و model توی این پوشه قرار میگیره (همچنین Middleware ها)

فولدر config: این فولدر شامل یک سری فایل های جاوا اسکریپت هست که وظفشون تنظیمات اولیه و یه سری ثابت ها برای اجرای سرور هست (مثلا میتونید نوع احراز هویت رو اینجا تنظیم کنید که jwt میخواید باشه یا ...)

فولدر database: که شامل یک فولدر به نام migration و یک فایل به نام factory.js میشه (مایگریشن ها یه سری فایل ها جاوا اسکریپت هستن که توسط همین فریمورک با ترمینال ساخته میشن و توشون ستون ها و نام table رو مشخص میکنید اینجوری هرموقع دیتابیس پاک بشه یا حتی دیتابیس رو عوض کنید با انجام یه دستور توی ترمینال همه تیبل ها روی دیتابیس جدید ساخته میشن)

فولدر start: این فولدر شامل سه فایل app و  kernel و routes میشه که از فایل routes.js بیشتر از همشون استفاده میکنیم اسم گذاری این پوشه به این خاطر بوده که یه سری اتفاقای کلی برای کل اپ توی این فایل ها انجام میشن

و در نهایت فایل .env در روت پروژه: اینجا همون environment شماست جایی که یک سری ثابت های برنامه رو به شکل Key=Value مینویسید همه خط های این فایل مهم هستند تنظیمات اتصال به دیتابیس از اینجا انجام میشه

(یه نکته مهم: هرجا که به یه چیزی مثل Env.get("key","default") خوردید بدونید که داره یه مقداری رو از توی این فایل میخونه و اگه توی این فایل چنین کلیدی نداشته باشه مقدار default رو که به عنوان ارگومان دوم میگیره به شما برمیگردونه)

همچنین هرجا Config.get دید یه چنین کاری رو برای فولدر کانفیگ انجام میده با این تفاوت که آدرس دهیش با دات انجام میشه (زیاد چیز مهمی نیست هرموقع بهش برخوردید خودتون متوجه میشید)

 

تنظیمات اتصال به دیتابیس PSQL

پست گرس از دیتابیس های خوب و پر استفاده توی این روز هاست که توی این آموزش هم بهش میپردازیم

اول مطمئن بشید که psql رو توی داکر یا سیستم خودتون نصب کردید (اگر توی داکر نصبش کردید حتما مطمئن بشید که اون کانیتینر روشن باشه) پورت دیفالتی که این دیتابیس استفاده میکنه ۵۴۳۲ هست

وارد فایل .env بشید و اطلاعات زیر رو متناسب با دیتابیس خودتون تغییر بدید

DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASSWORD=
DB_DATABASE=adonis

 

DB_CONNECTION رو بنویسید pg (مخفف postgres)

DB_POST رو هم روی ۵۴۳۲ بزارید (یا اگر روی داکر تغییر دادید اون رو وارد کنید)

DB_USER رو روی چیزی که تنظیم کردید قرار بدید (به صورت پیشفرض postgres)

DB_PASSWORD رو هم موقع کانفیگ کردن دیتابیس (يا نصب کانتینر به صورت environment دادید بهش) اینجا قرار بدید

DB_DATABASE هم اسم اون دیتابیسی هست که میخواد توش تیبل ها رو ایجاد کنه (به صورت پیشفرض پستگرس خودش یه دیتابیس به اسم psotgres میسازه که میتونید فعلا روی اون بزاریدش)

حالا برای اینکه بتونید تیبل ها رو با یه خط کد بنویسید لازمه که درایور pg رو نصب کنید 

npm install pg

و حالا توی دایرکتوری پروژتون کد زیر رو توی ترمینال بزنید:

adonis migration:run

اگر همه چیز درست باشه دوتا تیبل به اسم های users و tokens میسازه

ساخت کنترلر

حالا بریم برای ساخت یه کنترلر برای اینکه بتونیم توی دیتابیس User رکورد اضافه کنیم و بعدش هم بتونیم لاگین کنیم و توکن بدیم.

برای ساخت یه کنترلر باید از دستور زیر استفاده کنید

adonis make:controller user

 از شما میپرسه که HTTP یا Socket شما باید HTTP رو انتخاب کنید

حالا توی فولدر App یه پوشه به اسم Controller اضافه میشه که درونش یه فولدر دیگه به اسم Http قرار داره اونو باز کنید تا فایل UserController.js رو ببینید

وارد این فایل بشید توی این کلاس هرچی که لازم دارید و مربوط به یوزر هست رو باید بنویسید (مثل لیست یوزر ها، ثبت یه یوزر جدید، لاگین کردن و توکن گرفتن، رفرش توکن و...)

یادتون باشه که چون میخوایم اینجا با اون تیبل یوزر کار کنیم در بالای کلاس حتما اونو use کنیم (این تابع فقط ماله این فریمورکه که میتونید راجع بهش توی داکیومنت خود ادونیس بخونید)

const User = use("App/Models/User");

حالا با User میتونید خیلی کار ها بکنید (find, findBy, all,etc) که توابع و کاربردشو میتونید از داکیومنت ادونیس بخونید (یا اینجا کلیک کنید)

تابع اولمون تابع create هست (که یه کاربر جدید به دیتابیس توی تیبل users اضافه میکنه)

  async create ({request,response}) {
    const userParams = request.only(["username","password","email"])
    const newUser = User.create(userParams)
    newUser.password = undefined
    response.json({"success":true,"user":newUser})
  }

تابع بالا رو توی یوزر کنترلر قرار بدید

حالا بریم یه جا که بتونیم یه EndPoint بسازیم

وارد فولدر start بشید و فایل routes رو باز کنید

اینجا تمامی EndPoint ها رو تعریف میکنید به تعبیر بهتر اینجا روتر اپ شماست که کدوم آدرس کجا پردازش بشه

اگر قبلا اکسپرس کار کرده باشید میبینید که توابع get و post و.. رو مثل همون ساپورت میکنه ولی اینجا یه تفاوتی که داره مستقیم میتونید به یه تابع توی یه کنترلر آدرس بدید.

به این شکل

Route.post("/user/create","UserController.create")

حالا میتونید برنامه رو اجرا کنید‌ (با دستور زیر توی دایرکتوری روت پروژتون)

node server.js

حالا وارد آدرس http://localhost:3333 بشید (از داخل PostMan) 

اگه همه چی درست باشه باید یه جیسون بیاره که بهتون خوش آمد میگه

حالا به ته آدرسی که وارد کردید /user/create اضافه کنید و روی Post قرارش بدید توی Body  هم یه جیسون بدید که شامل username و password و email باشه

status مقدار true داره ولی user خالیه! چرا؟ یه نگاه به کد create بندازید. یه چیزی رو جا انداختیم. 

خط سوم رو به کد زیر تغییر بدید

const newUser = await User.create(userParams)

حالا یه بار دیگه مجددا امتحان کنید.

احتمالا از جوابی که سرور بهتون میده وحشت میکنید چون یه صفحه html برمیگردونه که خلاصه اش این میشه که شما دارید یه چیزی که توی دیتابیس بهش گفتید یکتا هست رو تکراری وارد میکنید و دیگه با این یوزر و ایمیل نمیتونید یه رکورد جدید ثبت کنید

مشکل خیلی راحت حل میشه کافیه که یوزر و ایمیل رو تغییر بدید

اما این یه جورایی پاک کردن صورت مسئله است (بیشتر بین مسئولین کشور رایجه) پس در ادامه با Validation اطلاعات ارسال شده از طرف کاربر ادامه میدیم.

اعتبار سنجی ورودی های کاربر:

برای اینکار لازمه که در ابتدا پکیج زیر رو نصب کنید

adonis install @adonisjs/validator

حالا به فایل start/app.js در قسمت 

providers

ادرس زیر را وارد کنید

 '@adonisjs/validator/providers/ValidatorProvider'

حالا میتونید با خیال راحت یه ولیدیتور با دستور زیر بسازید

adonis make:validator StoreUser

با اجرای کد بالا یه فایل با چنین محتوایی توی App/Validator براتون ایجاد میشه

'use strict'

class User {
  get rules () {
    return {
      // validation rules
    }
  }
}

module.exports = User

که باید به این شکل کاملش کنید

email: 'required|email|unique:users',
      password: 'required'

یعنی مقدار بالا رو بریزید توی قسمت return

required یه فلگ به معنی الزامیه که باید حتما توسط کاربر ارسال شده باشه همچنین unique از مهمترین دستور هاست به این معنا که این یک فیلد یکتا است پس مقدار توش نباید تکراری باشه این فلگ بعدش دونقطه میخواد و بعد از دونقطه باید اسم تیبلی که میخواید توش unique بودن این فیلد چک بشه رو وارد میکنید و بعد از اسم تیبل حتما یه کاما بزارید و اسم خود فیلد رو بنویسید یعنی اینجوری 

unique:users,email

حالا اگه باید بریم توی فایل start/routes.js

و کدی که قبل از این داستان اضافه کردیم رو به شکل زیر تغییر بدیم (به انتهاش validator اضافه کردم)

Route.post("/user/create","UserController.create").validator("User")

حالا اگه رکوئست بدید میبینید که بهتون میگه Validation Failed شده

توجه: برای کنترل ارور ها و تنظیم دستی پیام های ارور ها باید دو تابع message و fails رو پیاده کنید (که میتونید از توی داکیومنت مطالب بیشتری رو بخونید)

  async fails (error) {
    this.ctx.response.json(error[0])
  }
  get message () {
    return {
      'required':"please enter all thing true",
      'unique':"please enter a unique"
    }
  }

خب حالا بریم سر احراز هویت

هندل کردن احرازهویت و مجوز ها:

وقتی با استفاده از فلگ --api-only یه پروژه بسازیم به صورت اتوماتیک از jwt با یه کلید (که خودش رندوم میسازه و توی فایل env در دسترس هست) استفاده میکنه

ولی باید بهش بگیم که چه توابعی رو میخوایم احراز هویت کنیم (توکنش رو چک کنیم)

اول باید بریم یه تابع بسازیم که کاربر بتونه لاگین کنه پس وارد UserController میشیم و تابع زیر رو اضافه میکنیم

  async login({auth,request,response}) {
    let token = await auth.withRefreshToken().attempt(request.body.email,request.body.password)
    response.json(token)
  }

حالا همینو باید به Routes اضافه کنیم

Route.post("/user/login","UserController.login")

حالا پروژه رو ران کنید و یه یوزر بسازید بعدش با استفاده از لاگین براش email و password رو بفرستید تا بهتون یه توکن بده

علاوه بر توکن یه رفرش توکن هم بهتون میده که میتونید اونو هم به راحتی پیاده کنید

  async refreshToken ({auth,response,request}) {
    if (request.body.refreshToken) {
      let newToken = await auth
        .newRefreshToken()
        .generateForRefreshToken(request.body.refreshToken)
      response.json(newToken)
    }
    else {
      response.json({"error": "failed to refresh token"})
    }
  }

و در نهایت هرموقع که خواستید یک api رو کنترل کنید که فقط اونایی دسترسی داشته باشن که توکن ولید دارن باید Route اون آدرس رو یه Middleware اضافه کنید

به این شکل

Route.post("/post","PostController.add").validator("Post").middleware("auth")

middleware که میبینید (یعنی auth) کارش اینه که توکن رو چک میکنه و اگه ولید نباشه یا وجود نداشته باشه ارور میده (توجه کنید که ادرس post رو همینجوری زدم و توی این پروژه که باهم پیش رفتیم وجود نداره)

 

ارور هندلینگ

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

adonis make:ehandler

حالا دیگه همه ارور ها از توی تابع handle موجود در کلاس Handler ساخته شده عبور میکنه

این تابع رو باهم میبینم:

  async handle (error, { request, response }) {
    response.status(error.status).send(error.message)
  }

شما میتونید از error.name هم استفاده کنید و متناسب با اون ارور ها و کد های خاص خودتون رو بدید (یعنی توی response هرچی خواستید میتونید برگردونید اصلا میتونید همه رو ربط بدید به سرور و کد ۵۰۰ برگردونید با یه ارور ثابت)

میان افزار ها

میان افزار ها یه چیزایی هستن که رکوئست اول به اونا میرسه و در نهایت اگه اونا next() بزنن میره به دست کنترلر اونا میتونن داده رو هم عوض کنن مثلا چیزایی که توی request هست رو میتونن تغییر بدن خیلی چیزای مفیدی هستن که با دستور زیر میتونید بسازید و حتما یادتون نره که باید فایل start/kernel.js بخش globalMiddleware اضافش کنید مگرنه میان رکوئست ها قرار نمیگیره یا اینکه یه اسم براش انتخاب کنید و به namedMiddleware  اضافه اش کنید بعدش هم میتونید مثل middleware که برای auth استفاده کردیم ازش استفاده کنید (یعنی برای همه نیست بلکه هر رکوئستی که دوست داشته باشید بهش اینو اضافه میکنید)

adonis make:middleware [Name]

 

الان ساعت نزدیک به دو شبه

ولی به نظرم باید آموزش ساخت مدل رو هم بگم و بعد تموم کنم

 

ساخت مدل به همراه مایگیریشن:

برای اینکه یه تیبل جدید بسازید باید یه مدل بسازید به همراه یه فایل مایگریشن (فایل مایگریشن رو باید برید بخونید که چجوری باید سطر هاشو بنویسید چیز ساده ای هست زیاد نگران نباشید)

ولی برای ساخت یه مدل به همراه مایگریشنش از دستور زیر استفاده کنید

adonis make:model Post --migration

هرجا هم که خواستید چیزی اضافه کنید یا کم کنید یا هرکاری با این تیبل بکنید مثل user باید اول use کنید و با دستوراتی مثل create یا find و یا حتی query() کار کنید باهاش

واسه امشب کافیه سعی کردم با وجود خستیگیم هرچی بود رو بزارم ولی حتما داکیومنت رو مطالعه کنید

موفق باشید

به امید ایران پرافتخارتر از همیشه

یاعلی مدد