用Nest.js和MongoDB创建API。
#javascript #api #nestjs #mongodb

简介

在这篇博客文章中,我将分享我的经验,建立了使用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 

您创建的文件看起来像这样: -

Image description

您的项目文件一开始会像这样,但是您可以根据需要创建或删除文件夹。

创建第一个API

NEST API由三个主要组件组成:提供商,控制器和服务。

提供商是普通的JavaScript类,可为应用程序提供功能。它们在模块文件中声明。

控制器处理HTTP请求。他们负责将请求路由到适当的提供商和服务。

服务包含应用程序的业务逻辑。控制器使用它们来执行数据访问和操纵等任务。

换句话说,提供商是API的基础,控制器是将其固定在一起的胶水,而服务是使其正常工作的肌肉。

正常数据流就像....
控制器 - >服务;
服务 - >存储库/架构;
存储库/架构 - >数据库;

所以这是您在SRC文件夹中的所有文件的样子...

Image description

模式

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时需要考虑的不同约束。

我们希望这篇博客文章有所帮助。如果您有任何疑问,请随时在下面发表评论。

谢谢您的阅读!

在这里您可以查看我的完整项目,我试图使其尽可能最小化,以更好地理解。