DevGang
Авторизоваться

Как добавить фильтрацию, сортировку, ограничение и нумерацию страниц в ваше приложение Nest.js

Если вы читаете эту статью, вы, вероятно, разработчик, который использовал API для вызова данных для своего приложения. Возможно, вы также использовали такие функции, как фильтрация и нумерация страниц, чтобы ограничить объем данных, которые вы хотите получить.

Эти функции API важны при создании собственного API. Они помогают гарантировать, что ваш API работает быстро, безопасно и легко понятен людям, использующим его.

В этой статье вы создадите простой API расходов с помощью Nest.js и MongoDB для базы данных. Затем вы реализуете фильтрацию, сортировку, ограничение и нумерацию страниц, чтобы сделать ваш API более быстрым и простым в использовании. Давай начнем!

Что такое API?

API — это основа современной разработки программного обеспечения. API означает интерфейс прикладного программирования и позволяет одной части программного обеспечения взаимодействовать с другой частью программного обеспечения.

Веб-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 module expenses контроллера и услугу следующим образом: nest generate module expenses на обслуживание. Все это следует делать в папке src.

Продолжайте и создайте файл Costs.schema.ts. Внутри файла Costes.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 в ExpensesService с помощью декоратора @InjectModel().

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 мы внедрили модель расходов в качестве зависимости с помощью декоратора @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 из массива контроллеров.

Вы можете протестировать конечную точку на 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. Это принято как аргумент в форме запроса.

Перед фильтрацией вы хотите исключить определенные специальные поля, такие как, page, sort, limits и fields. Эти поля удаляются из жесткой копии объекта, который хранится в переменной queryOBJ. Вы также хотите использовать операторы MongoDB, такие как GT или GTE.

Например, на Postman это то, как вы вводите запрос: ?amount[gt]=100

В MongoDB это будет выглядеть следующим образом: { amount: { $gt: 100 } }. В методе фильтра мы добавили знака $ к операторам, используя регулярное выражение.

После этого объект проанализируется с использованием метода json.parse (), а затем передается в функцию монгуозного запроса. Убедитесь, что вы возвращаете весь класс, набрав это.

Сортировка

Как видите, реализовать фитеринг в 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;
  }

Приведенный выше метод проверяет, существует ли свойство сортировки в объекте запроса. Если это так, вы разделяете строку на , если имеется несколько запросов на сортировку. Затем вы присоединяетесь к нему с помощью ''.

Сделав это, вы связываете его с запросом 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 из объекта запроса. Затем вы хотите пропустить определенное количество документов, чтобы перейти на нужную страницу. В запросе Mongoose есть метод skip() и метод limit().

  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 в файле Costs.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, поскольку каждый метод возвращает объект.

В файле expenses.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.

Источник:

#NestJS
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу