نحوه افزودن فیلتر، مرتبسازی، محدود کردن و صفحهبندی به برنامه Nest.js
اگر در حال خواندن این مقاله هستید، احتمالاً توسعه دهنده ای هستید که از یک API برای فراخوانی داده های برنامه خود استفاده کرده اید. همچنین ممکن است از آپشن های ی مانند فیلتر کردن و صفحهبندی برای محدود کردن مقدار دادهای که میخواهید دریافت کنید استفاده کرده باشید.
این ویژگی های API هنگام ساختن API خود مهم هستند. آنها کمک می کنند تا اطمینان حاصل شود که API شما سریع، ایمن و به راحتی برای افرادی که از آن استفاده می کنند قابل درک است.
در این مقاله، یک API هزینه ساده با Nest.js و MongoDB برای یک پایگاه داده میسازید. سپس فیلتر، مرتبسازی، محدود کردن و صفحهبندی را اجرا میکنید تا API خود را سریعتر و آسانتر کنید. شروع کنیم!
در اینجا چیزی است که ما پوشش خواهیم داد:
چگونه یک برنامه Nest.js را راه اندازی کنیم
نحوه پیاده سازی فیلترینگ و مرتب سازی
نحوه پیاده سازی محدودیت و صفحه بندی
API چیست؟
API ها ستون فقرات توسعه نرم افزار مدرن هستند. API مخفف Application Programming Interface است و به یک نرم افزار اجازه می دهد تا با نرم افزار دیگری ارتباط برقرار کند.
API های وب از پروتکل های ارتباطی HTTP برای برقراری ارتباط با رایانه ها استفاده می کنند. انواع مختلفی از API وجود دارد، اما ما در اینجا به آنها نخواهیم پرداخت.
این روزها، برای APIهای وب، آپشن های طراحی مانند فیلتر کردن، مرتبسازی، محدود کردن و صفحهبندی برای سریعتر کردن، استفاده آسانتر و ایمنتر کردن API رایج است. نحوه پیاده سازی این ویژگی ها برای ساخت API بهتر را در این مقاله خواهید آموخت.
چگونه یک برنامه Nest.js را راه اندازی کنیم
اول از همه، شما یک CRUD API هزینه ساده در Nestjs خواهید ساخت. Nestjs یک چارچوب Node.js پیشرو برای ساخت APIهای مدرن است که استفاده از آن بسیار آسان است.
برای شروع، خط فرمان خود را باز کنید و دستورات زیر را تایپ کنید:
$ npm i -g @nestjs/cli $ nest new expense-app
راهنمای نصب را دنبال کنید. با این کار چند فایل دیگ بخار برای شما تولید می شود. سپس می توانید برنامه Nest.js خود را در یک IDE انتخابی خود باز کنید.
نحوه پیکربندی MongoDB
از آنجایی که MongoDB پایگاه داده ترجیحی ما است، مهم است که آن را پیکربندی کنید تا بتوانید از آن در برنامه خود استفاده کنید. ابتدا بسته @nestjs/mongoose
را نصب کنید:
$ npm i @nestjs/mongoose mongoose
پس از اتمام نصب، به فایل ماژول برنامه خود بروید و MongooseModule
وارد کنید:
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { MongooseModule } from '@nestjs/mongoose'; @Module({ imports: [MongooseModule.forRoot(`mongodb+srv://*******:*******@cluster0.30vt0jd.mongodb.net/expense-test-app`)], controllers: [AppController], providers: [AppService], }) export class AppModule {}
اگر نمی خواهید رشته خود را به این شکل در معرض دید قرار دهید، می توانید یک فایل .env
ایجاد کنید و رشته اتصال پایگاه داده خود را در آن ذخیره کنید. سپس باید بسته @nestjs/config
را نصب کنید که از dotenv داخلی استفاده می کند.
در داخل فایل ماژول برنامه خود، ConfigModule
وارد کنید:
@Module({ imports: [ ConfigModule.forRoot({ envFilePath: '.env', isGlobal: true }), MongooseModule.forRoot(process.env.DATABASE), ], controllers: [AppController], providers: [AppService], })
isGlobal: true
این است که ماژول را در همه جای برنامه خود در دسترس قرار دهید. envFilePath
مسیر فایل .env
شما را مشخص می کند.
نحوه تنظیم نقاط پایانی هزینه
شما MongoDB را پیکربندی کرده اید. اکنون زمان تنظیم نقاط پایانی هزینه است.
میتوانید با تایپ کردن موارد زیر در ترمینال، یک ماژول در Nest.js ایجاد کنید: nest generate module expenses
. همچنین میتوانید کنترلر را به این صورت تولید کنید: nest generate controller expenses
و nest generate service expenses
. همه این کارها را باید در پوشه src انجام دهید.
ادامه دهید و یک فایل costs.schema.ts ایجاد کنید. در داخل فایل costs.schema.ts، یک طرح هزینه با مقداری اعتبار ایجاد کنید.
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import mongoose, { HydratedDocument } from 'mongoose'; export type ExpenseDocument = HydratedDocument<Expense>; @Schema() export class Expense { @Prop({ trim: true, required: [true, 'Title is required'], }) title: string; @Prop({ min: 0, required: [true, 'Amount is required'], }) amount: number; @Prop({ type: String, trim: true, required: [true, 'Category is required'], }) category: string; @Prop({ type: Date, default: Date.now, }) incurred: Date; @Prop({ type: String, trim: true }) notes: string; @Prop() slug: string; @Prop() updated: Date; @Prop({ type: Date, default: Date.now, }) created: Date; } export const ExpenseSchema = SchemaFactory.createForClass(Expense);
آپشن های این طرح شامل عنوان، مقدار، دسته، یادداشتها و اسلاگ است.
پس از انجام این کار، می خواهید مدل هزینه را در فایل costs.module.ts ثبت کنید:
import { Module } from '@nestjs/common'; import { ExpensesController } from './expenses.controller'; import { ExpensesService } from './expenses.service'; import { MongooseModule } from '@nestjs/mongoose'; import { Expense, ExpenseSchema } from './expenses.schema'; @Module({ imports: [ MongooseModule.forFeature([{ name: Expense.name, schema: ExpenseSchema }]), ], controllers: [ExpensesController], providers: [ExpensesService], }) export class ExpensesModule {}
هنگامی که طرح را ثبت کردید، سپس می توانید مدل Expense
را با استفاده از دکوراتور @InjectModel()
به ExpensesService
تزریق کنید.
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Expense } from './expenses.schema'; import { Model } from 'mongoose'; import { ExpenseDto } from './dto/expense.dto'; @Injectable() export class ExpensesService { constructor( @InjectModel(Expense.name) private expenseModel: Model<Expense>, ) {} async createExpense(data: ExpenseDto) { const expense = this.expenseModel.create(data); return expense; } async getExpenses() { const expenses = await this.expenseModel.find(); return expenses; } }
در فایل ExpensesService
، مدل Expense
را به عنوان یک وابستگی با استفاده از دکوراتور @InjectModel()
تزریق کردیم. هنگامی که این کار را انجام دادید، سپس ادامه می دهید و تابعی را تعریف می کنید که هزینه ایجاد می کند و تابعی که تمام هزینه ها را دریافت می کند.
در کنترلر خود کد زیر را اضافه کنید:
import { Body, Controller, Get, Post, Res } from '@nestjs/common'; import { ExpensesService } from './expenses.service'; import { ExpenseDto } from './dto/expense.dto'; @Controller('expenses') export class ExpensesController { constructor(private readonly expenseService: ExpensesService) {} @Post() async createExpense(@Body() data: ExpenseDto, @Res() response: any) { const expense = await this.expenseService.createExpense(data); console.log(expense); return response.status(201).json({ message: 'success', data: expense, }); } @Get() async getExpenses(@Res() response: any) { const expenses = await this.expenseService.getExpenses(); return response.status(200).json({ message: 'success', data: expenses, }); } }
اگر با خطای وابستگی مواجه شدید، به فایل app.module.ts
خود بروید و ExpenseController
از آرایه controllers
حذف کنید.
می توانید نقطه پایانی را در Postman تست کنید.
نحوه پیاده سازی فیلترینگ و مرتب سازی
اکنون که با موفقیت نقاط پایانی هزینه را تنظیم کرده اید، زمان اجرای ویژگی های فیلتر و مرتب سازی در API است.
فیلتر کردن
فیلتر کردن اساساً به همان روشی که در Node.js انجام می دهیم انجام می شود.
در داخل پوشه src خود، یک پوشه جدید به نام Utils
ایجاد کنید و در داخل آن پوشه یک فایل جدید به نام apiFeatures.ts
ایجاد کنید.
در داخل این فایل، کلاسی به نام APIFeatures
تعریف کنید. این کلاس حاوی متدهایی است که آپشن های API را که پیادهسازی میکنید در خود جای میدهد.
export class APIFeatures { mongooseQuery: any; queryString: any; constructor(mongooseQuery: any, queryString: any) { this.mongooseQuery = mongooseQuery; this.queryString = queryString; } filter() { // 1) Filtering const queryObj = { ...this.queryString }; const excludedFields = ['page', 'sort', 'limit', 'fields']; excludedFields.forEach((fields) => { delete queryObj[fields]; }); // console.log(queryObj); //2) Advanced filtering let queryStr = JSON.stringify(queryObj); queryStr = queryStr.replace(/\b(gte|gt|lte|lt)\b/g, (match) => `$${match}`); //console.log(JSON.parse(queryStr)); this.mongooseQuery = this.mongooseQuery.find(JSON.parse(queryStr)); return this; } }
در روش فیلتر، یک نسخه چاپی از req.query
ایجاد کردید. به عنوان آرگومان در قالب queryString
ارسال می شود.
قبل از فیلتر کردن، میخواهید برخی از فایلهای خاص مانند page
، sort
، limits
و fields
را حذف کنید. این فیلدها از نسخه چاپی شی که در متغیر queryObj
ذخیره می شود حذف می شوند. همچنین می خواهید از عملگرهای MongoDB مانند gt
یا gte
استفاده کنید.
برای مثال، در Postman به این صورت است که عبارت را تایپ می کنید: ?amount[gt]=100
در MongoDB، به این صورت خواهد بود: { amount: { $gt: 100 } }
. در روش فیلتر، علامت $
را با استفاده از یک عبارت منظم به عملگرها اضافه کردیم.
پس از آن، شی با استفاده از متد JSON.parse()
تجزیه می شود و سپس به تابع query Mongoose ارسال می شود. مطمئن شوید که کل کلاس را با تایپ return this
برگردانید.
مرتب سازی
همانطور که می بینید، پیاده سازی فیترینگ در Nest.js مانند Node.js بسیار آسان است.
اکنون زمان اجرای مرتب سازی است. در کلاس APIFeatures
تابع دیگری به نام مرتب سازی تعریف کنید.
sorting() { if (this.queryString.sort) { const sortBy = this.queryString.sort.split(',').join(' '); // console.log(sortBy); this.mongooseQuery = this.mongooseQuery.sort(sortBy); } else { this.mongooseQuery = this.mongooseQuery.sort('-created'); } return this; }
روش بالا تحلیل می کند که آیا یک ویژگی مرتب سازی در شی query وجود دارد یا خیر. اگر این کار را انجام داد، رشته را با یک تقسیم می کنید ,
در صورتی که پرس و جوهای مرتب سازی متعدد وجود داشته باشد. سپس با یک ' '
به آن بپیوندید.
هنگامی که این کار را انجام دادید، آن را با یک روش مرتب سازی که در همه اسناد وجود دارد، به پرس و جوی Mongoose زنجیر می کنید. بلوک else سند را بر اساس تاریخ ایجاد آن مرتب می کند، در صورتی که کاربر درخواست مرتب سازی را مشخص نکرده باشد.
نحوه پیاده سازی محدودیت و صفحه بندی
تبریک میگم شما فیلترینگ و مرتب سازی را اجرا کرده اید. اکنون نوبت به پیاده سازی محدودیت و صفحه بندی می رسد.
محدود کردن
برای محدود کردن فیلدها، میتوانید متد select()
را در کوئری Mongoose فراخوانی کنید.
متد دیگری را در کلاس تعریف کنید:
limit() { if (this.queryString.fields) { const fields = this.queryString.fields.split(',').join(' '); this.mongooseQuery = this.mongooseQuery.select(fields); } else { this.mongooseQuery = this.mongooseQuery.select('-__v'); } return this; }
و شما می روید.
صفحه بندی
برای پیاده سازی صفحه بندی، می خواهید page
و limit
از شی پرس و جو دریافت کنید. سپس میخواهید تعداد معینی از اسناد را رد کنید تا به صفحه مورد نظر خود برسید. یک متد skip()
و یک متد limit()
در کوئری Mongoose وجود دارد.
pagination() { // get the page and convert it to a number. If no page set default to 1 const page = this.queryString.page * 1 || 1; // get limit and if no limit, set limit to 100 const limit = this.queryString.limit * 1 || 100; // calculate skip value const skip = (page - 1) * limit; // chain it to the mongoose query. this.mongooseQuery = this.mongooseQuery.skip(skip).limit(limit); // return the object return this; }
هنگامی که این کار را انجام دادید، می خواهید کلاس APIfeatures
را در کلاس ExpensesService
در فایل shpenzims.service.ts خود فراخوانی کنید.
تابع getExpenses
خود را با این کد جایگزین کنید:
async getExpenses(query?: any) { const features = new APIFeatures(this.expenseModel.find(), query) .filter() .sort() .limit() .pagination(); //Execute the query const expenses = await features.mongooseQuery; return expenses; }
در تابع، این امکان وجود دارد که تمام این متدها را در کلاس APIFeatures
زنجیره ای کنیم زیرا هر متد شی را برمی گرداند.
در فایل shpenzims.controller.ts تابع getExpenses
شما باید به شکل زیر باشد:
@Get() async getExpenses(@Res() response: any, @Req() request: any) { const expenses = await this.expenseService.getExpenses(request.query); return response.status(200).json({ message: 'success', data: expenses, }); }
اکنون برنامه را با npm start:dev
اجرا کنید و ویژگی های API خود را در Postman تست کنید.
نتیجه
در این راهنما، نحوه پیادهسازی مرتبسازی، فیلتر کردن، محدود کردن و صفحهبندی را در برنامههای Nest.js خود یاد گرفتهاید.
با این دانش، میتوانید این ویژگیها را در پروژههای شخصی خود که با استفاده از Nest.js ساخته شدهاند، پیادهسازی کنید.
ارسال نظر