Введение
Nestjs — это передовой фреймворк Node.js для разработки серверных приложений, которые являются эффективными, надежными и масштабируемыми. Он легко интегрируется с базами данных NoSQL и SQL, такими как MongoDB, Yugabyte, SQLite, Postgres, MySQL и другими. Он поддерживает популярные объектно-реляционные мапперы, такие как TypeORM Sequelize и Mongoose.
В этом учебнике мы создадим приложение для электронной коммерции с использованием SQLite и TypeORM. Мы также рассмотрим Arctype, мощный SQL-клиент и инструмент управления базами данных.
Давайте начнем!
Предварительные условия
Этот учебник представляет собой практическую демонстрацию для начала работы. Убедитесь, что вы выполнили следующие требования:
- У вас установлен Node (>= 10.13.0, кроме v13).
- У вас есть базовые знания Javascript
- Установлен Arctype
Настройка проекта
Чтобы начать работу с Nestjs, установите Nestjs CLI с помощью команды ниже:
npm i -g @nestjs/cli
После завершения установки создайте проект Nestjs с помощью команды ниже:
nest new ecommerce
Выберите npm в качестве менеджера пакетов, нажмите кнопку ввода и подождите, пока Nest установит необходимые пакеты для запуска этого приложения.
После завершения установки измените каталог на папку проекта командой ниже:
cd ecommerce
Затем откройте директорию проекта в вашем любимом текстовом редакторе или IDE, откройте новый терминал и запустите сервер в режиме разработки (Это включит горячую перезагрузку и позволит нам увидеть возможные ошибки в консоли) командой ниже:
npm run start:dev
Установка зависимостей
Когда сервер запущен и работает, откройте новое окно терминала, чтобы не выходить из сервера. Это позволит вам увидеть эффект от изменений, внесенных в кодовую базу на протяжении этого руководства.
Теперь установите следующие зависимости:
- Passport
- Passport-local
- Jwt
- Passport-jwt
- SQLIte3
- TypeORM
- Bcrypt
Это можно сделать с помощью команды ниже:
npm install --save @nestjs/passport passport passport-local @nestjs/jwt passport-jwt @nestjs/typeorm typeorm sqlite3 bcrypt
Затем установите dev-зависимости с помощью следующей команды:
npm install --save-dev @types/passport-local @types/passport-jwt @types/bcrypt
Вы можете выпить чашечку кофе, пока npm устанавливает пакеты. Как только установка будет завершена, давайте приступим к работе.
Создание модулей приложения
Собрав все необходимые пакеты для запуска приложения, приступим к созданию модулей приложения. Чтобы создать чистое и легко обслуживаемое приложение, вы создадите отдельные модули для всех функций, реализованных в этом приложении. Поскольку это приложение для электронной коммерции, у вас будут аутентификация, корзина, товары и заказы. Все они будут находиться в своих отдельных модулях. Давайте начнем с модуля аутентификации.
Создание модуля аутентификации
Создайте модуль аутентификации с помощью команды ниже:
nest g module auth
Приведенная выше команда создает папку auth в директории src проекта с необходимыми boilerplates и регистрирует модуль в корневом модуле проекта (файл app.module.ts).
Далее создайте модуль product, cart, order с помощью команды ниже:
#Create a product module
nest g module product
#Create cart module
nest g module cart
#Create cart module
nest g module order
Это создаст папку product, cart и order в папке src проекта с основными шаблонами и зарегистрирует эти модули в корневом модуле app проекта.
Настройка баз данных TypeORM и SQLite
После установки модулей приложения настройте TypeORM для подключения вашего приложения к базе данных SQLite и создания сущностей модуля. Для начала откройте файл app.module.ts и настройте базу данных SQLite с помощью приведенных ниже фрагментов кода:
imports: [
…
TypeOrmModule.forRoot({
type :"sqlite",
database: "shoppingDB",
entities: [__dirname + "/**/*.entity{.ts,.js}"],
synchronize: true
})
],
…
В приведенном выше фрагменте кода вы подключили приложение к базе данных SQLite с помощью TypeORM forRoot, указав тип базы данных, имя базы данных и место, где Nestjs может найти сущности модели.
После обновления сервера вы должны увидеть файл shoppingDB, созданный в корневом каталоге этого проекта.
Создание моделей сущностей приложения
Когда база данных настроена, давайте создадим модели сущностей для модулей нашего приложения. Мы начнем с модуля auth. Создайте файл сущности в папке модуля auth с помощью команды ниже:
nest generate class auth/user.entity –flat
Затем добавьте приведенный ниже фрагмент кода для определения свойств таблицы пользователя с помощью приведенного ниже фрагмента кода:
import { Entity, OneToOne, JoinColumn,Column, CreateDateColumn, UpdateDateColumn, PrimaryGeneratedColumn, OneToMany } from 'typeorm'
import { CartEntity } from 'src/cart/cart.entity'
import { OrderEntity } from 'src/order/order.entity'
@Entity()
export class Users {
@PrimaryGeneratedColumn()
id: number
@Column()
username: string
@Column()
password: string
@Column()
role: string
@CreateDateColumn()
createdAt : String
@UpdateDateColumn()
updtedAt : String
@OneToMany(type => CartEntity, cart => cart.id)
@JoinColumn()
cart: CartEntity[]
@OneToOne(type => OrderEntity, order => order.id)
@JoinColumn()
order : OrderEntity;
}
В этом фрагменте кода вы импортировали декораторы, необходимые для настройки таблицы базы данных. Вы также импортировали классы cartEntity и orderEntity, которые вы создадите в ближайшее время. Используя декоратор typeorm, мы определили свойства базы данных модели пользователя. Наконец, мы создали отношения один-к-одному и один-ко-многим между сущностью users и cartEntity и orderEntity. Таким образом, вы можете связать элемент корзины с пользователем. То же самое относится и к заказу пользователя.
Далее создайте класс сущности product с помощью команды ниже:
nest generate class product/product.entity –flat
Приведенная выше команда создаст файл product.entity.ts в папке модуля products.
Теперь настройте свойства таблицы продуктов с помощью приведенного ниже фрагмента кода:
import { Entity, JoinColumn, OneToMany, Column, CreateDateColumn, UpdateDateColumn, PrimaryGeneratedColumn } from 'typeorm'
import { CartEntity } from 'src/cart/cart.entity'
@Entity()
export class ProductEntity {
@PrimaryGeneratedColumn("uuid")
id!: number
@Column()
name: string
@Column()
price: number
@Column()
quantity: string
@CreateDateColumn()
createdAt: String
@UpdateDateColumn()
updtedAt: String
@OneToMany(type => CartEntity, cart => cart.id)
@JoinColumn()
cart: CartEntity[]
}
В приведенном выше фрагменте кода мы настроили свойства таблицы product и создали связь «один-ко-многим» с сущностью cart.
Затем создайте сущность cart с помощью команды ниже:
nest generate class cart/cart.entity –flat
Приведенная выше команда создаст файл cart.entity.ts в папке модуля cart. Теперь добавьте приведенный ниже фрагмент кода в созданный файл для настройки свойств таблицы cart.
import { Entity, OneToOne,ManyToOne, JoinColumn, Column, PrimaryGeneratedColumn } from 'typeorm'
import { OrderEntity } from 'src/order/order.entity'
import { ProductEntity } from 'src/product/product.entity'
import { Users } from 'src/auth/user.entity'
@Entity()
export class CartEntity {
@PrimaryGeneratedColumn('uuid')
id: number
@Column()
total: number
@Column()
quantity: number
@ManyToOne(type => ProductEntity, order => order.id)
@JoinColumn()
item: ProductEntity
@ManyToOne(type => Users, user => user.username)
@JoinColumn()
user: Users
}
В приведенном выше фрагменте кода вы настроили свойства таблицы cart, создали отношения «многие-к-одному» между сущностью cart и отношения «многие-к-одному» с сущностью user.
И наконец, создайте сущность «Заказ» с помощью следующей команды:
nest generate class order/order.entity –flat
Приведенная выше команда создаст файл order.entity.ts в папке модуля order. Откройте файл order.entity.ts и настройте таблицу базы данных с помощью следующей команды:
import { Entity, OneToMany, JoinColumn, OneToOne, Column, PrimaryGeneratedColumn } from 'typeorm'
import { ProductEntity } from 'src/product/product.entity';
import { Users } from 'src/auth/user.entity';
@Entity()
export class OrderEntity {
@PrimaryGeneratedColumn('uuid')
id: number
@OneToMany(type => ProductEntity, item => item.id)
items: ProductEntity[];
@OneToOne(type => Users, user => user.username)
@JoinColumn()
user : Users;
@Column()
subTotal: number
@Column({ default: false })
pending: boolean
}
В приведенном выше фрагменте кода вы создали отношения «один-к-одному» между сущностями users и «один-ко-многим» с сущностью products.
На данном этапе ваши сущности базы данных установлены и связаны. Теперь создайте бизнес-логику для хранения записей в этих сущностях.
Создание служб приложения
Теперь создайте службы для модулей этого приложения. Здесь вы позволите администратору добавлять продукты в таблицу продуктов, аутентифицировать пользователей, позволять пользователям добавлять продукты в магазине в корзину и заказывать продукты через корзину.
Создание службы авторизации
Чтобы создать службу авторизации, выполните приведенную ниже команду для создания службы для модуля авторизации.
nest generate service auth/service/auth --flat
Приведенная выше команда создаст файл auth.service.ts в папке src/auth/service. Теперь откройте файл auth.service.ts и добавьте приведенный ниже фрагмент кода:
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Users } from '../user.entity';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(@InjectRepository(Users) private userRepository: Repository<Users>, private jwt: JwtService) { }
}
В приведенном выше фрагменте кода вы импортировали модули InjectRepository, Repository decorator, JwtService и bcrypt. Затем, используя декоратор InjectRepository, вы сделали класс сущности User доступным в службе auth, предоставив метод для выполнения операций CRUD в вашей сущности User.
Затем создайте метод signup, чтобы позволить пользователям регистрироваться в приложении с помощью приведенного ниже фрагмента кода:
async signup(user: Users): Promise<Users> {
const salt = await bcrypt.genSalt();
const hash = await bcrypt.hash(user.password, salt);
user.password = hash
return await this.userRepository.save(user);
}
Теперь создайте метод validateUser для проверки данных пользователя и метод login для генерации jwt-токена для аутентифицированного пользователя.
…
async validateUser(username: string, password: string): Promise<any> {
const foundUser = await this.userRepository.findOne({ username });
if (foundUser) {
if (await bcrypt.compare(password, foundUser.password)) {
const { password, ...result } = foundUser
return result;
}
return null;
}
return null
}
async login(user: any) {
const payload = { username: user.username, sub: user.id, role:user.role };
return {
access_token: this.jwt.sign(payload),
};
}
Теперь мы можем реализовать нашу локальную стратегию аутентификации Passport. Создайте файл local.strategy.ts в папке модуля auth и добавьте следующий код:
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './service/auth.service';
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super();
}
async validate(username: string, password: string): Promise<any> {
const foundUser = await this.authService.validateUser(username, password);
if (!foundUser) {
throw new UnauthorizedException();
}
return foundUser;
}
}
В приведенном выше фрагменте кода вы реализовали стратегию passport-local. Опции конфигурации отсутствуют, поэтому наш конструктор просто вызывает super() без объекта options.
Вы также реализовали метод validate(). Passport будет вызывать функцию verify для каждой стратегии, используя соответствующий набор параметров для конкретной стратегии. Для стратегии local-strategy Passport ожидает метод validate() со следующей сигнатурой: validate(username: string, password:string): any.
Затем создайте файл jwt-auth.guard.ts в папке модуля auth и определите пользовательский auth guard с помощью приведенного ниже фрагмента кода:
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}
Вы будете использовать AuthGuard, созданный в этом фрагменте кода, для защиты ваших маршрутов API от неавторизованных пользователей.
Теперь создайте файл jwt-strategy в папке модуля auth для аутентификации пользователей и генерации jwt-токенов для вошедших пользователей с помощью приведенного ниже фрагмента кода:
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { jwtConstants } from './constants';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: jwtConstants.secret,
});
}
async validate(payload: any) {
return { userId: payload.sub, username: payload.username, role: payload.role };
}
}
Затем настройте модуль jwt в файле auth.module.ts в папке модуля auth. Перед этим создайте файл constants.ts в той же папке модуля auth для определения jwt-секрета с помощью приведенного ниже фрагмента кода:
export const jwtConstants = {
secret: 'wjeld-djeuedw399e3-uejheuii33-4jrjjejei3-rjdjfjf',
}
Вы можете сгенерировать более защищенный jwt-секрет на производстве, но мы будем использовать этот для демонстрации.
Теперь импортируйте все необходимые модули в файл auth.module.ts с помощью приведенного ниже фрагмента кода:
…
import { JwtModule } from '@nestjs/jwt';
import { jwtConstants } from './constants';
import { JwtStrategy } from './jwt.strategy';
import { PassportModule } from '@nestjs/passport';
import { LocalStrategy } from './local.strategy';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Users } from './user.entity';
…
Затем в массиве импортов настройте jwt с помощью приведенного ниже фрагмента кода:
…
imports: [
PassportModule,
JwtModule.register({
secret: jwtConstants.secret,
signOptions: { expiresIn: '60m' },
}),
…
В приведенном выше фрагменте кода мы добавляем пакет PassModule, чтобы позволить passport обрабатывать аутентификацию пользователей, и настраиваем jwt с помощью метода JwtModule register. Мы передаем секрет, созданный в файле constants, и указываем время действия сгенерированного токена (Вы можете уменьшить или увеличить это время в зависимости от конкретного случая использования).
Создание службы продукта
Настроив службу авторизации, создайте службу продукта с помощью следующей команды:
nest generate service product/service/product
Теперь откройте файл product.service.ts, сгенерированный вышеуказанной командой, в модуле продукта и добавьте приведенные ниже фрагменты кода:
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { ProductEntity } from '../product.entity';
import { Repository, UpdateResult, DeleteResult } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { Users } from 'src/auth/user.entity';
@Injectable()
export class ProductsService {
constructor(@InjectRepository(ProductEntity) private productRepository: Repository<ProductEntity>) { }
async getAll(): Promise<ProductEntity[]> {
return await this.productRepository.find()
}
async create(product: ProductEntity, user: Users): Promise<ProductEntity> {
if (user.role == 'admin') {
return await this.productRepository.save(product);
}
throw new UnauthorizedException();
}
async getOne(id: number): Promise<ProductEntity> {
return this.productRepository.findOne(id);
}
async update(id: number, product: ProductEntity, user: Users): Promise<UpdateResult> {
if (user.role == 'admin') {
return await this.productRepository.update(id, product);
}
throw new UnauthorizedException();
}
async delete(id: number, user: Users): Promise<DeleteResult> {
if (user.role == 'admin') {
return await this.productRepository.delete(id);
}
throw new UnauthorizedException();
}
}
В приведенном выше фрагменте мы создали наши CRUD-сервисы. Методы создания, обновления и удаления ограничены для пользователей. Только администратор может создать продукт, удалить или обновить его.
Теперь откройте файл product.module.ts и сделайте сущность product доступной с помощью приведенного ниже фрагмента кода:
imports: [TypeOrmModule.forFeature([ProductEntity])],
Создание службы корзины
На данный момент администратор может добавлять продукты в базу данных, а авторизованные пользователи могут видеть все доступные продукты. Теперь давайте позволим пользователям добавлять понравившиеся им товары в корзину. Чтобы начать, создайте службу Cart с помощью команды ниже:
nest generate service cart/service/cart –flat
Затем откройте файл cart.service.ts, созданный командой, и добавьте фрагмент кода, приведенный ниже:
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { CartEntity } from '../cart.entity';
import { ProductsService } from 'src/product/service/products.service';
import { Users } from 'src/auth/user.entity';
@Injectable()
export class CartService {
constructor(
@InjectRepository(CartEntity)
private cartRepository: Repository<CartEntity>,
@InjectRepository(Users)
private userRepository: Repository<Users>,
private productsService: ProductsService,
) { }
…
Вы импортировали модули, необходимые для создания сервиса Nest.js в приведенном выше фрагменте кода. Мы также импортировали их здесь, поскольку вы создали связь между сущностями корзины, пользователя и продукта. Затем вы создаете метод конструктора для привязки этих сущностей к классу CartService. Теперь создайте метод для добавления товара в корзину.
async addToCart(productId: number, quantity: number, user: string): Promise<any> {
const cartItems = await this.cartRepository.find({ relations: ["item",'user'] });
const product = await this.productsService.getOne(productId);
const authUser = await this.userRepository.findOne({ username: user })
//Confirm the product exists.
if (product) {
//confirm if user has item in cart
const cart = cartItems.filter(
(item) => item.item.id === productId && item.user.username === user,
);
if (cart.length < 1) {
const newItem = this.cartRepository.create({ total: product.price * quantity, quantity });
newItem.user = authUser;
newItem.item = product;
this.cartRepository.save(newItem)
return await this.cartRepository.save(newItem)
} else {
//Update the item quantity
const quantity = (cart[0].quantity += 1);
const total = cart[0].total * quantity;
return await this.cartRepository.update(cart[0].id, { quantity, total });
}
}
return null;
}
В приведенном выше фрагменте кода вы создали метод addToCart, который принимает в качестве аргументов productId, количество и пользователя. Затем проверяется, есть ли у пользователя товар, который уже находится в его корзине. Если да, то вы увеличиваете количество и обновляете общую цену этого товара. В противном случае вы добавляете товар в корзину пользователя.
Далее сделайте сущности cartEntity, productEntity User и productService доступными в cartService, зарегистрировав их в файле cart.module.ts с помощью приведенного ниже фрагмента кода:
…
import { CartEntity } from './cart.entity';
import { ProductsService } from 'src/product/service/products.service';
import { ProductEntity } from 'src/product/product.entity';
import { Users } from 'src/auth/user.entity';
@Module({
imports: [TypeOrmModule.forFeature([CartEntity, ProductEntity, Users])],
providers: [CartService, ProductsService],
…
})
Наконец, создайте метод getItemsInCart, который принимает в качестве аргумента пользователя, чтобы вернуть все корзины, принадлежащие определенному пользователю.
async getItemsInCard(user: string): Promise<CartEntity[]> {
const userCart = await this.cartRepository.find({ relations: ["item",'user'] });
return (await userCart).filter(item => item.user.username === user)
}
Создание службы заказов
Когда пользователи закончат покупки, они могут заказать товары, находящиеся в их корзине. Создайте службу заказа с помощью приведенной ниже команды:
nest generate service order/service/order –flat
Теперь откройте файл order.service.ts, созданный в результате выполнения вышеуказанной команды, и добавьте фрагмент кода, приведенный ниже:
import { OrderEntity } from '../order.entity';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { CartService } from 'src/cart/service/cart.service';
import { Users } from 'src/auth/user.entity';
@Injectable()
export class OrderService {
constructor(@InjectRepository(OrderEntity)
private orderRepository: Repository<OrderEntity>,
@InjectRepository(Users)
private userRepository: Repository<Users>,
private cartService: CartService) { }
Вы импортировали модули, необходимые для создания службы Nest.js в приведенном выше фрагменте кода. Мы также импортировали их здесь, поскольку вы создали связь между сущностями корзины, пользователя и продукта. Затем вы создали метод конструктора для привязки этих сущностей к классу OrderService. Теперь создайте метод для заказа товаров в корзине пользователя.
…
async order(user: string): Promise<any> {
//find user existing orders
const usersOrder = await this.orderRepository.find({ relations: ['user'] });
const userOrder = usersOrder.filter(order => order.user?.username === user && order.pending === false);
//find user's cart items
const cartItems = await this.cartService.getItemsInCard(user)
const subTotal = cartItems.map(item => item.total).reduce((acc, next) => acc + next);
//get the authenticated user
const authUser = await this.userRepository.findOne({ username: user })
//if users has an pending order - add item to the list of order
const cart = await cartItems.map(item => item.item);
if (userOrder.length === 0) {
const newOrder = await this.orderRepository.create({ subTotal });
newOrder.items = cart
newOrder.user = authUser;
return await this.orderRepository.save(newOrder);
} else {
const existingOrder = userOrder.map(item => item)
await this.orderRepository.update(existingOrder[0].id, { subTotal: existingOrder[0].subTotal + cart[0].price });
return { message: "order modified" }
}
}
…
Затем создайте другой метод для получения заказа пользователя из массива заказов из базы данных с помощью приведенного ниже фрагмента кода:
…
async getOrders(user: string): Promise<OrderEntity[]> {
const orders = await this.orderRepository.find({ relations: ['user'] });
return orders.filter(order => order.user?.username === user)
}
}
Наконец, откройте файл order.module.ts и сделайте сущности users, product и cart доступными в orderService с помощью приведенного ниже фрагмента кода:
import { TypeOrmModule } from '@nestjs/typeorm';
import { OrderEntity } from './order.entity';
import { ProductEntity } from 'src/product/product.entity';
import { CartService } from 'src/cart/service/cart.service';
import { CartEntity } from 'src/cart/cart.entity';
import { Users } from 'src/auth/user.entity';
import { ProductsService } from 'src/product/service/products.service';
@Module({
imports: [TypeOrmModule.forFeature([OrderEntity, ProductEntity, CartEntity, Users])],
controllers: [OrderController],
providers: [OrderService, CartService, ProductsService]
})
Создание контроллеров приложений
После успешного создания сервисов приложений давайте создадим маршруты API для этих сервисов.
Создайте контроллер авторизации
Создайте контроллер аутентификации с помощью команды ниже:
nest generate controller auth/controller/auth –flat
Теперь откройте файл auth.controller.ts, созданный в результате выполнения вышеуказанной команды, и настройте маршруты auth с помощью приведенного ниже фрагмента кода:
import { Controller, Request, Post, UseGuards, Body } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { AuthService } from '../service/auth.service';
import { Users } from '../user.entity';
@Controller('api/v1/auth/')
export class AuthController {
constructor(private usersService: AuthService) { }
@Post('signup')
async signup(@Body() user: Users): Promise<Users> {
return this.usersService.signup(user);
}
@UseGuards(AuthGuard('local'))
@Post('login')
async login(@Request() req) {
return this.usersService.login(req.user)
}
}
Создание контроллера продукта
После настройки маршрутов контроллера аутентификации создайте контроллер продукта с помощью приведенной ниже команды:
nest generate controller product/controller/product –flat
Откройте файл product.controller.ts, созданный в результате выполнения вышеуказанной команды, и настройте маршруты продукта с помощью приведенного ниже фрагмента кода:
import { Controller, Post, Get, Put, Delete, Param, Request, Body, UseGuards } from '@nestjs/common';
import {UpdateResult, DeleteResult} from 'typeorm';
import { ProductsService } from '../service/products.service';
import { ProductEntity } from '../product.entity';
import { JwtAuthGuard } from 'src/auth/jwt-auth.guard';
@Controller('api/v1/products')
export class ProductsController {
constructor(private productsService: ProductsService) { }
@UseGuards(JwtAuthGuard)
@Get()
async GetAll(): Promise<ProductEntity[]> {
return await this.productsService.getAll();
}
@UseGuards(JwtAuthGuard)
@Post()
async Create(@Request() req, @Body() product: ProductEntity): Promise<ProductEntity> {
return await this.productsService.create(product, req.user);
}
@UseGuards(JwtAuthGuard)
@Get(':id')
async GetOne(@Param() id: number): Promise<ProductEntity> {
return await this.productsService.getOne(id);
}
@UseGuards(JwtAuthGuard)
@Put(':id')
async Update(@Param() id: number, @Body() product: ProductEntity, @Request() req): Promise<UpdateResult> {
return await this.productsService.update(id, product, req.user);
}
@UseGuards(JwtAuthGuard)
@Delete(':id')
async Delete(@Param() id: number, @Request() req): Promise<DeleteResult> {
return await this.productsService.delete(id, req.user);
}
}
В приведенном выше фрагменте кода вы определили CRUD-маршруты для службы продукта. Мы использовали декоратор UseGuard, передав ему JwtAuthGaurd для защиты маршрутов от неавторизованных пользователей.
Создание контроллера корзины
Теперь создайте контроллер корзины с помощью приведенной ниже команды:
nest generate controller cart/controller/cart –flat
Затем откройте файл cart.controller.ts, созданный в результате выполнения вышеуказанной команды, и настройте маршруты корзины с помощью фрагмента кода ниже:
import { Controller, Post, Get,Request, Delete, Body, UseGuards } from '@nestjs/common';
import { CartService } from '../service/cart.service';
import { CartEntity } from '../cart.entity';
import { JwtAuthGuard } from 'src/auth/jwt-auth.guard';
@Controller('api/v1/cart')
export class CartController {
constructor(private cartService: CartService) { }
@UseGuards(JwtAuthGuard)
@Post()
async AddToCart(@Body() body, @Request() req): Promise<void> {
const { productId, quantity } = body
return await this.cartService.addToCart(productId, quantity, req.user.username);
}
@UseGuards(JwtAuthGuard)
@Get()
async getItemsInCart(@Request() req): Promise<CartEntity[]> {
return await this.cartService.getItemsInCard(req.user.username);
}
}
Создание контроллера заказов
Когда маршруты корзины настроены, создайте контроллер заказов с помощью команды ниже:
nest generate controller order/controller/order –flat
Затем откройте файл order.controlle.ts, созданный в результате выполнения вышеуказанной команды, и настройте маршруты корзины с помощью приведенного ниже фрагмента кода:
import { Controller, Post, Get, Request, UseGuards } from '@nestjs/common';
import { OrderService } from '../service/order.service'
import { OrderEntity } from '../order.entity';
import { JwtAuthGuard } from 'src/auth/jwt-auth.guard';
@Controller('api/v1/order')
export class OrderController {
constructor(private orderService: OrderService) { }
@UseGuards(JwtAuthGuard)
@Post()
async order(@Request() req): Promise<any> {
return this.orderService.order(req.user.username)
}
@UseGuards(JwtAuthGuard)
@Get()
async getOrders(@Request() req): Promise<OrderEntity[]> {
return await this.orderService.getOrders(req.user.username)
}
}
На этом этапе все маршруты API были настроены.
Тестовое приложение
Теперь давайте протестируем их с помощью Postman. Результаты тестирования приведены ниже.
Не стесняйтесь тестировать другие маршруты и играть с кодом здесь, на Github.
Подключение Arctype к базе данных SQLite
Arctype — это клиент SQL и инструмент управления базами данных, который очень интересно использовать. Он позволяет вам иметь визуальное представление таблиц вашей базы данных, и вы можете выполнять CRUD-операции каталога в вашей базе данных с помощью Arctype. Подключение Arctype к базе данных SQLite является простым процессом. Чтобы начать работу, выполните следующие шаги:
Сначала запустите Arctype. Вы увидите окно, как показано ниже, позволяющее добавить учетные данные.
Перейдите на вкладку SQLite. Появится экран, показанный ниже.
Нажмите на кнопку Choose SQLite File и перейдите в папку проекта. Выберите файл базы данных приложения и нажмите кнопку открыть. Нажмите кнопку сохранить, и вы увидите сущности вашей базы данных, как показано на скриншоте ниже.
Заключение
Создав демонстрационный проект, мы узнали, как сделать приложение для электронной коммерции, используя Nestjs и базу данных SQLite. Сначала мы начали со знакомства с NestJS. Затем мы создали приложение NestJS, подключили приложение к базе данных SQLite с помощью TypeORM и выполнили операции CRUD. Теперь, когда вы получили необходимые знания, не стесняйтесь добавлять в приложение дополнительную функциональность.