简介
在这篇博客文章中,我将分享我的经验,建立了使用Nestjs,Mongodb和Postman的全面且定义明确的电子商务API。
我构建的API包括几个端点,这些端点共同构成了一个完整的电子商务API。这些终点适用于管理员,最终用户,产品和类别。
每个端点都是明确的,并提供了与API交互的清晰简洁的接口。端点也有充分的文献记录,使开发人员可以轻松了解如何使用它们。
我希望这篇博客文章对有兴趣与Nestjs建立电子商务API的开发人员有帮助。
这是该项目的一些关键要点:
- Nestjs 是一个强大的框架,可用于构建全面且定义明确的API。
- MongoDB 是一个可靠且可扩展的数据库,非常适合电子商务应用程序。
- Postman 是测试和调试API的强大工具。
我鼓励您尝试使用Nestjs,MongoDB和Postman构建自己的电子商务API。这是了解这些技术并建立宝贵技能的好方法。
关于项目
电子商务系统通常有两种类型的用户:用户和管理员。用户可以注册并登录到系统,但他们只能读取产品。管理员可以在产品上注册,登录和执行CRUD操作。
使用NPM的BCRypt模块完成了用户和管理员的密码哈希。该模块提供了一种安全的方法来哈希密码。
借助.Populate()方法来定义产品类别。此方法使您在获取产品时可以从数据库中获取产品类别。这使得在产品页面上显示产品类别变得容易。
详细的解释: -
- 用户和管理员:用户是电子商务系统的最终用户。他们可以注册并登录到系统,并且可以查看产品。管理员是系统管理员。他们比用户拥有更多的特权,并且可以在产品上执行CRUD操作。
- 密码哈希:密码哈希是一种安全措施,有助于保护用户密码。当用户注册用于电子商务系统时,使用安全算法将其密码悬浮。这意味着密码未存储在纯文本中,并且不能轻易解码。
- jsonwebtoken模块:JSONWEBTOKEN模块是生成和验证JSON Web令牌(JWTS)的流行模块。 JWT是对用户进行身份验证的安全方法。当用户登录到电子商务系统时,会发出JWT。然后可以使用此JWT在后续请求中对用户进行身份验证。
- .populate()方法:.populate()方法是一种用于从数据库中获取相关文档的方法。在电子商务系统的背景下,当产品获取产品时,可使用.populate()方法来获取产品类别。这使得在产品页面上显示产品类别变得容易。
- bcrypt模块:BCRYPT模块使用BCRYPT算法来哈希密码。 BCRYPT算法是一种缓慢的算法,这使攻击者很难违反密码。 BCRYPT模块还使用盐,这是一个随机字符串,在密码被哈希之前添加到密码。这使哈希更加独特和难以破解。
如何创建Nest Project
首先,我们需要在根目录中安装Nestjs。要在我们的根目录中安装Nestjs CLI,我们需要按照以下命令: -
$npm i -g @nestjs/cli
此外,要为我们的Nest Project文件创建样板,我们需要编写以下代码: -
$nest new project-name
您创建的文件看起来像这样: -
您的项目文件一开始会像这样,但是您可以根据需要创建或删除文件夹。
创建第一个API
NEST API由三个主要组件组成:提供商,控制器和服务。
提供商是普通的JavaScript类,可为应用程序提供功能。它们在模块文件中声明。
控制器处理HTTP请求。他们负责将请求路由到适当的提供商和服务。
服务包含应用程序的业务逻辑。控制器使用它们来执行数据访问和操纵等任务。
换句话说,提供商是API的基础,控制器是将其固定在一起的胶水,而服务是使其正常工作的肌肉。
正常数据流就像....
控制器 - >服务;
服务 - >存储库/架构;
存储库/架构 - >数据库;
所以这是您在SRC文件夹中的所有文件的样子...
模式
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import { Document } from "mongoose";
@Schema()
export class Admin extends Document{
@Prop({required: true})
firstName: string
@Prop({required: true})
lastName: string
@Prop({unique: true, required: true })
userName: string
@Prop({required: true})
password: string
@Prop({ unique: true, required: true })
mobileNo : number
@Prop({ unique: true, required: true })
email: string
@Prop({required: true})
gender: string
@Prop()
isAdmin: boolean
}
export const AdminSchema = SchemaFactory.createForClass(Admin)
上面的代码定义了管理API的杂种架构。模式是MongoDB数据库中文档的蓝图。它定义了文档的结构,包括允许的字段以及可以存储在每个字段中的数据类型。
上面代码中的杂种架构使用装饰器来验证文档中存储的数据。例如,isstring()装饰器确保名称字段的值是字符串,并且iSonotempty()装饰器确保电子邮件字段的值不是空的。
此模式可确保在管理API中存储的数据是有效且一致的。这使得管理数据并确保API正常工作变得更加容易。
控制器
import { Body, Controller, Post } from '@nestjs/common';
import { adminService } from './admin.service';
import { Admin } from './admin.schema';
import { adminDto } from './dto/admin.dto';
import { adminLoginDto } from './dto/adminLogin.dto';
@Controller('admin')
export class adminController {
constructor(
private adminService: adminService,
) {}
@Post('/register')
async newAdmin(@Body() adminDto: adminDto): Promise<Admin | object> {
return this.adminService.newAdmin(adminDto);
}
@Post('/login')
async loginAdmin(@Body() adminLoginDto: adminLoginDto): Promise<object>{
return this.adminService.loginAdmin(adminLoginDto);
}
}
上面的代码显示了管理API控制器文件,该文件是处理管理用户的HTTP请求和响应的类。控制器仅使用HTTP POST方法进行注册和登录请求。它还使用上述服务,这些服务是提供业务逻辑的类。
要创建一个控制器文件,必须在控制器类上方使用@controller()装饰器。这是一个标记为控制器的弹簧注释。
术语DTO代表数据传输对象。 DTO是简单的对象,用于在应用程序的不同组件之间传输数据。在这种情况下,它们用于验证在传入请求中流动的数据。
这是一个简单的管理员登录DTO ....
的示例
import { IsString } from 'class-validator';
export class adminLoginDto {
@IsString()
userName: string;
@IsString()
password: string;
}
服务
/* eslint-disable prettier/prettier */
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { Admin } from './admin.schema';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import * as bcrypt from 'bcrypt';
import { adminDto } from './dto/admin.dto';
import { JwtService } from '@nestjs/jwt';
import { adminLoginDto } from './dto/adminLogin.dto';
@Injectable()
export class adminService {
constructor(
@InjectModel(Admin.name)
private adminModel: Model<Admin>,
private jwtService: JwtService,
) {}
async newAdmin(adminDto: adminDto): Promise<Admin | object> {
const {
firstName,
lastName,
userName,
password,
email,
mobileNo,
gender,
isAdmin,
} = adminDto;
const salt = await bcrypt.genSalt();
const hashedPassword = await bcrypt.hash(password, salt);
const existingUser = await this.adminModel.findOne({
userName,
email,
});
if (!existingUser) {
const adminUser = await this.adminModel.create({
firstName,
lastName,
userName,
password: hashedPassword,
email,
mobileNo,
gender,
isAdmin: true,
});
return adminUser.save();
} else {
return {
statusCode: 400,
message: `User already exist.`,
};
}
}
async loginAdmin(adminLoginDto: adminLoginDto): Promise<object> {
const { userName, password } = adminLoginDto;
const admin = await this.adminModel.findOne({ userName });
const isAdmin = admin.isAdmin;
if (admin && (await bcrypt.compare(password, admin.password))) {
const payload = { userName, isAdmin };
const accessToken = await this.jwtService.sign(payload);
return {
statusCode: 200,
message: 'Login Successfull',
Admin: admin,
token: accessToken,
};
} else {
throw new UnauthorizedException('User is not authorized');
}
}
}
NEST项目中的服务模块负责应用程序的业务逻辑。控制器模块使用它执行任务,例如将数据保存到数据库,验证密码和生成令牌。
在此模块中,我们使用bcrypt软件包保存了Admin的数据,并使用Hashed密码保存。这样可以确保密码被安全存储并不能轻易解码。
.findone()方法用于根据用户名和电子邮件字段在数据库中查找数据。这两个字段应该是唯一的,因此使用.findone()方法可确保我们仅返回一个记录。
阵列破坏性用于从我们从数据库中检索到的记录中提取所需字段。这些字段将被保存到我们的数据库中。我们还保留一个标志以区分最终用户和管理用户。
登录函数使用相同的.findone()方法从数据库中查找数据。然后对密码进行验证,如果凭据正确,用户将收到令牌。
我们使用的Authguard只会访问管理员来创建,删除和更新产品。最终用户没有与管理员相同的权威。
结论
在这篇博客文章中,我们讨论了为电子商务平台创建管理员API的过程。我们介绍了通常包含在管理API中的不同端点,以及创建API时需要考虑的不同约束。
我们还讨论了对最终用户,产品和类别API等其他API的需求,以便为用户提供完整的电子商务体验。我们简要介绍了创建这些其他API时需要考虑的不同约束。
我们希望这篇博客文章有所帮助。如果您有任何疑问,请随时在下面发表评论。
谢谢您的阅读!
在这里您可以查看我的完整项目,我试图使其尽可能最小化,以更好地理解。