什么是Nest.js?一款轻量级JavaScript框架

什么是Nest.js?一款轻量级JavaScript框架

管理一个大规模的应用程序可能会很繁琐,尤其是在没有经过良好规划的结构和严格的代码组织策略下构建时。这可能会导致在维护过程中出现灾难,并应尽一切努力避免。这种灾难是由于随着项目用户基数的增长,对代码库的修改和新功能的引入所引起的。

另一方面,Nest.js旨在提供解决代码结构和代码组织策略问题的解决方案。它结合了现代化和模块化的软件工程原则。

Nest.js使用TypeScript进行类型检查,并为构建和部署可测试、可扩展、松散耦合且易于维护的应用程序提供了一个开箱即用的软件架构。

在本文中,我们将探讨Nest.js及其可以构建的内容。我们还将解释该框架的优缺点,以便让您清楚为什么公司更喜欢它而不是其他Node.js框架。最后,我们将演示如何使用Nest.js创建一个待办事项API。

什么是Nest.js?

Nest.js是一种快速增长的Node.js框架,用于使用Node.js构建高效、可扩展和企业级的后端应用程序。它以使用现代JavaScript和TypeScript产生高度可测试、可维护和可扩展的应用程序而闻名。

Nest.js官方标志

Nest.js官方标志(图片来源:Behance

GitHub上拥有超过46.6k个星星和5.4k个Fork,并且每周下载量高达70万次,这个框架是使用Node.js构建后端项目的热门选择。

如果您需要构建可扩展、可维护、企业级的应用程序,Nest.js是您下一个项目的完美解决方案。

在下一节中,我们将探讨它的用途以及在生产中使用该框架的不同公司。

Nest.js的用途是什么?

Nest.js是一个用于构建高度可测试和可维护后端应用程序的服务器端Node.js框架。您可以使用Node.js创建各种类型的应用程序;唯一的限制在于应用程序的功能。

由于该框架利用了TypeScript,Nest.js在寻求发挥TypeScript类型检查能力的团队中特别受欢迎。而且,它易于学习和掌握,具有强大的CLI(命令行界面),可提高生产力和开发的便利性。这个强大的CLI使得快速启动任何服务器端项目并将其完成变得轻而易举。

此外,Nest.js提供了详细的文档,并且其开发者和贡献者社区非常活跃,愿意随时解决问题。

这些原因使得很多公司都倾向于切换到Nest.js框架。下面是一些在生产中使用该框架的知名品牌。

Roche

Roche是一家跨国医药公司,分为制药和诊断两个部门。这家美国生物科技公司在其主要网站上使用Nest.js框架,可靠地为患者提供服务并进一步扩大其业务。

Roche官方主页

Roche官方主页

Adidas

阿迪达斯是欧洲最大的运动服装制造商,全球排名第二。阿迪达斯以设计和制造鞋类、服装和配饰而闻名。由于其全球覆盖范围和知名度,他们决定使用高度可扩展的Nest.js框架来构建品牌的大规模高效应用程序。

阿迪达斯官方主页

阿迪达斯官方主页

Decathlon

迪卡侬是在57个国家拥有超过1,500家门店的体育用品零售商。迪卡侬选择了Nest.js作为其网络应用程序的后端,以帮助他们扩展和维护现有的代码库。

迪卡侬官方主页

迪卡侬官方主页

您可以在GitHub上找到使用Nest.js构建的其他公司、项目和工具的列表。

接下来,我们将讨论为什么您和您的公司应选择Nest.js作为下一个项目,并介绍为什么其他人已经使用该框架以及它的优势。

为什么选择Nest.js

选择一个框架取决于您正在开发的应用程序类型,因为不同的应用程序需要不同的工具集。

在这里,我们将列举选择Nest.js作为您的Node.js框架来升级或构建下一个项目的不同原因。

  • Nest.js易于学习和掌握,特别适用于来自Angular世界的开发人员。这使得开发过程快速高效,团队成员可以轻松适应任何新的开发原则和结构。
  • 该框架以出色的企业级应用程序架构而闻名,使构建高度可扩展和可维护的企业级应用程序变得轻而易举。
  • 您可以轻松使用Nest.js构建各种类型的后端服务,包括RESTful API、GraphQL应用程序、MVC应用程序、Websockets、CLI和Cron作业。一些标准架构已经内置在Nest.js框架中。
  • 由于Nest.js使用了现代技术,如TypeScript、可靠的架构模式、优秀的文档和易于单元测试,您可以构建可扩展和可维护的企业级应用程序。
  • Nest.js是为构建大规模的单体和微服务应用程序而创建的,其中架构已经处理好,您只需要构建自己的业务逻辑。
  • Nest.js支持并提供基于社区的大量nest-supported模块,以构建您选择的任何特定功能,从TypeORM、Mongoose和GraphQL等概念到日志记录、验证、缓存、WebSockets等等。

接下来,我们将探讨Nest.js的优缺点。通过讨论好的和坏的方面,这将有助于巩固您采用该框架的决定。

Nest.js的优缺点

在这里,我们将列举Nest.js的优缺点,以更好地了解为什么它在Node.js生态系统中如此受欢迎。

优点

使用Nest.js的一些好处包括:

  • 强大但用户友好:该框架对开发人员来说非常友好,即使是最复杂和强大的功能也很容易使用。Nest.js团队设计了这个框架,让开发人员可以快速入门,并专注于编写业务逻辑,而框架会处理其他重要的开发方面,比如安全性
  • Angular风格的语法(后端):Angular是一个非常受欢迎的前端框架,专注于架构和结构。Nest.js作为后端的Angular,它使用Angular风格和语法来帮助您构建企业项目结构。
  • TypeScript支持:Nest.js从一开始就支持TypeScript,它解决了性能问题,并通过提供编译错误和警告来快速编写可维护的应用程序。TypeScript与VSCode很好地集成在一起,提供易于使用的开发环境。
  • 详尽的文档:Nest.js拥有一些最好的框架文档,非常易于理解。查阅文档可以节省调试时间,快速找到解决问题的方法。
  • 良好的架构和快速开发:Nest.js为您的应用程序提供了坚实的结构和架构,无论是创建第一个MVP还是实际应用程序,都可以为您节省时间,从而增强您的开发过程。

缺点

有句著名的名言:“每个优势都有其不足之处”——Nest.js也不例外。因此,让我们探讨一下Nest.js的缺点。

  • 对新手来说有难度:对于不具备Angular背景的初学者开发人员来说,Nest.js可能有些棘手,需要一些时间和实践才能学习和掌握。此外,由于并非所有JavaScript开发人员都使用TypeScript,这个框架对这些开发人员来说也可能有难度。但就像其他技术一样,它需要时间和实践。
  • 调试困难:尽管TypeScript有其优点,但也会带来许多调试上的困扰,特别是对于TypeScript领域中的新手开发人员来说。

这就是Nest.js的优点和缺点,以及它们如何影响您选择它作为首选框架的决策制定过程。

接下来,我们将通过使用Nest.js构建一个RESTful API来巩固我们迄今为止学到的知识。继续阅读,了解如何开发一个待办事项API,允许用户创建和管理他们的待办事项列表。

构建你的第一个Nest.js RESTful API

是时候将我们学到的关于Nest.js的知识付诸实践,通过构建我们的第一个RESTful API来展示它的功能和简单性。

我们将从设置框架和安装所有必要工具开始,让它能够运行起来。

1. 设置Nest.js

首先,我们使用以下命令安装Nest CLI以创建新项目:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm i -g @nestjs/cli
npm i -g @nestjs/cli
npm i -g @nestjs/cli

之后,使用以下命令创建一个新项目:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
nest new nest-todo-api
cd nest-todo-api
npm run start:dev
nest new nest-todo-api cd nest-todo-api npm run start:dev
nest new nest-todo-api
cd nest-todo-api
npm run start:dev

现在,我们已经安装了Nest CLI并成功创建了新项目,让我们构建我们的API。

在你选择的任何代码编辑器中打开这个项目。如果你访问 localhost:3000,你应该会看到一个欢迎信息,显示一切都成功运行。

接下来,我们将设置一个MongoDB数据库来连接和管理项目中的待办事项数据。

在深入之前,让我们使用以下命令生成我们创建API所需的所有文件:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
nest generate module todos
nest generate controller todos
nest generate service todos
nest generate module todos nest generate controller todos nest generate service todos
nest generate module todos
nest generate controller todos
nest generate service todos

2. 设置MongoDB

接下来,我们将安装并配置MongoDB以与之前创建的项目一起工作。

在本地计算机上安装MongoDB后,运行以下命令来在我们新创建的项目中安装Mongoose库:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm install --save @nestjs/mongoose mongoose
npm install --save @nestjs/mongoose mongoose
npm install --save @nestjs/mongoose mongoose

这就是你需要做的。

接下来,我们将生成文件并将Mongoose引入项目和MongoDB进行通信。

在生成其他必要文件之前,让我们将Mongoose引入我们的应用程序模块文件中。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '@nestjs/mongoose';
import { TodosModule } from './todos/todos.module';
@Module({
imports: [MongooseModule.forRoot('mongodb://localhost/todos), TodosModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { MongooseModule } from '@nestjs/mongoose'; import { TodosModule } from './todos/todos.module'; @Module({ imports: [MongooseModule.forRoot('mongodb://localhost/todos), TodosModule], controllers: [AppController], providers: [AppService], }) export class AppModule {}
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '@nestjs/mongoose';
import { TodosModule } from './todos/todos.module';
@Module({
imports: [MongooseModule.forRoot('mongodb://localhost/todos), TodosModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

3. 构建模式

接下来,我们将为我们的数据库构建数据库模式。这个模式将指定数据在我们的数据库中的表示方式。

让我们在我们的todos.schema.ts文件中定义它:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import * as mongoose from 'mongoose';
export const ItemSchema = new mongoose.Schema({
title: String,
is_completed: Boolean,
description: String,
});
import * as mongoose from 'mongoose'; export const ItemSchema = new mongoose.Schema({ title: String, is_completed: Boolean, description: String, });
import * as mongoose from 'mongoose';
export const ItemSchema = new mongoose.Schema({
title: String,
is_completed: Boolean,
description: String,
});

4. 定义接口

接下来,我们将创建一个用于类型检查的接口。

让我们在我们的interfaces/todo.interface.ts文件中定义它:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { Document } from 'mongoose';
export interface Item extends Document {
id?: string;
title: string;
description?: string;
is_completed: boolean;
}
import { Document } from 'mongoose'; export interface Item extends Document { id?: string; title: string; description?: string; is_completed: boolean; }
import { Document } from 'mongoose';
export interface Item extends Document {
id?: string;
title: string;
description?: string;
is_completed: boolean;
}

5. 创建DTO

最后,我们将构建一个DTO (数据传输对象),定义数据将如何在网络中的对象之间发送或传递。

它是一个基本类,具有和我们模式相同的属性:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// ./dto/create-todo.ts
export class CreateItemDto {
readonly title: string;
readonly description: string;
readonly is_completed: boolean;
}
// ./dto/create-todo.ts export class CreateItemDto { readonly title: string; readonly description: string; readonly is_completed: boolean; }
// ./dto/create-todo.ts
export class CreateItemDto {
readonly title: string;
readonly description: string;
readonly is_completed: boolean;
}

6. 设置模型/服务

服务文件负责与MongoDB数据库进行交互和通信。它用于在先前创建的 todos 模式中创建、检索、更新和删除记录。

打开你的服务文件并添加以下代码:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { Injectable } from '@nestjs/common';
import { Todo } from './interfaces/todo.interface';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { CreateTodoDto } from './dto/create-todo.dto';
@Injectable()
export class ItemsService {
constructor(@InjectModel('Todo') private readonly todoModel: Model) {}
async findAll(): Promise<Todo[]> {
return await this.todoModel.find();
}
async findOne(id: string): Promise {
return await this.todoModel.findOne({ _id: id });
}
async create(item: CreateItemDto): Promise {
const newTodo = new this.todoModel(item);
return await newTodo.save();
}
async delete(id: string): Promise {
return await this.todoModel.findByIdAndRemove(id);
}
async update(id: string, todo: CreateTodoDto): Promise {
return await this.todoModel.findByIdAndUpdate(id, todo, { new: true });
}
}
import { Injectable } from '@nestjs/common'; import { Todo } from './interfaces/todo.interface'; import { Model } from 'mongoose'; import { InjectModel } from '@nestjs/mongoose'; import { CreateTodoDto } from './dto/create-todo.dto'; @Injectable() export class ItemsService { constructor(@InjectModel('Todo') private readonly todoModel: Model) {} async findAll(): Promise<Todo[]> { return await this.todoModel.find(); } async findOne(id: string): Promise { return await this.todoModel.findOne({ _id: id }); } async create(item: CreateItemDto): Promise { const newTodo = new this.todoModel(item); return await newTodo.save(); } async delete(id: string): Promise { return await this.todoModel.findByIdAndRemove(id); } async update(id: string, todo: CreateTodoDto): Promise { return await this.todoModel.findByIdAndUpdate(id, todo, { new: true }); } }
import { Injectable } from '@nestjs/common';
import { Todo } from './interfaces/todo.interface';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { CreateTodoDto } from './dto/create-todo.dto';
@Injectable()
export class ItemsService {
constructor(@InjectModel('Todo') private readonly todoModel: Model) {}
async findAll(): Promise<Todo[]> {
return await this.todoModel.find();
}
async findOne(id: string): Promise {
return await this.todoModel.findOne({ _id: id });
}
async create(item: CreateItemDto): Promise {
const newTodo = new this.todoModel(item);
return await newTodo.save();
}
async delete(id: string): Promise {
return await this.todoModel.findByIdAndRemove(id);
}
async update(id: string, todo: CreateTodoDto): Promise {
return await this.todoModel.findByIdAndUpdate(id, todo, { new: true });
}
}

上面的代码段使用Mongoose模型在我们的API上表达了CRUD (创建、读取、更新、删除)应用程序,以便他们访问我们底层的MongoDB数据库。

接下来,我们将创建我们的控制器文件,用于处理所有逻辑和与我们上面创建的服务进行通信。

7. 设置控制器

控制器负责处理传入的请求并向客户端发送响应。

让我们定义我们的 Todo 控制器并粘贴以下代码段:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
} from '@nestjs/common';
import { CreateTodoDto } from './dto/create-todo.dto';
import { TodosService } from './todos.service';
import { Todo } from './interfaces/todo.interface';
@Controller('items')
export class ItemsController {
constructor(private readonly todosService: TodosService) {}
@Get()
findAll(): Promise<Todo[]> {
return this.todosService.findAll();
}
@Get(':id')
findOne(@Param('id') id): Promise {
return this.todosService.findOne(id);
}
@Post()
create(@Body() createTodoDto: CreateTodoDto): Promise {
return this.todosService.create(createTodoDto);
}
@Delete(':id')
delete(@Param('id') id): Promise {
return this.todosService.delete(id);
}
@Put(':id')
update(@Body() updateTodoDto: CreateTodoDto, @Param('id') id): Promise {
return this.todosService.update(id, updateTodoDto);
}
}
import { Controller, Get, Post, Put, Delete, Body, Param, } from '@nestjs/common'; import { CreateTodoDto } from './dto/create-todo.dto'; import { TodosService } from './todos.service'; import { Todo } from './interfaces/todo.interface'; @Controller('items') export class ItemsController { constructor(private readonly todosService: TodosService) {} @Get() findAll(): Promise<Todo[]> { return this.todosService.findAll(); } @Get(':id') findOne(@Param('id') id): Promise { return this.todosService.findOne(id); } @Post() create(@Body() createTodoDto: CreateTodoDto): Promise { return this.todosService.create(createTodoDto); } @Delete(':id') delete(@Param('id') id): Promise { return this.todosService.delete(id); } @Put(':id') update(@Body() updateTodoDto: CreateTodoDto, @Param('id') id): Promise { return this.todosService.update(id, updateTodoDto); } }
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
} from '@nestjs/common';
import { CreateTodoDto } from './dto/create-todo.dto';
import { TodosService } from './todos.service';
import { Todo } from './interfaces/todo.interface';
@Controller('items')
export class ItemsController {
constructor(private readonly todosService: TodosService) {}
@Get()
findAll(): Promise<Todo[]> {
return this.todosService.findAll();
}
@Get(':id')
findOne(@Param('id') id): Promise {
return this.todosService.findOne(id);
}
@Post()
create(@Body() createTodoDto: CreateTodoDto): Promise {
return this.todosService.create(createTodoDto);
}
@Delete(':id')
delete(@Param('id') id): Promise {
return this.todosService.delete(id);
}
@Put(':id')
update(@Body() updateTodoDto: CreateTodoDto, @Param('id') id): Promise {
return this.todosService.update(id, updateTodoDto);
}
}

该框架使用注解来处理很多后台功能,例如通过为RESTful API的Put、Delete、Post和Get分别提供不同的注解(@Put()@Delete()@Post()@Get())来处理框架的路由系统。

8. 使用Postman测试API

最后,我们将使用Postman测试我们新创建的API。在部署到生产服务器之前,我们需要启动开发服务器以确保一切正常运行。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm run start:dev
npm run start:dev
npm run start:dev

你可以下载和运行Postman来测试你的RESTful API。

Nest.js待办事项列表结果

Nest.js待办事项列表结果

小结

Nest.js是一个强大的Node.js框架,也是目前最流行的TypeScript框架。

它为工程团队提供了标准的开发架构和行业最佳实践。开发人员可以将重复的工程流程抽象出来,专注于开发业务逻辑。

正是这些优势促使Adidas、Roche等知名品牌选择在其企业生产应用程序中使用该框架。

在本文中,我们为Nest.js打下了坚实的基础,解释了为什么你和你的公司应该考虑转向它。此外,我们构建了一个简单的待办事项RESTful API来实际展示该框架的强大之处。

现在,你可以决定Nest.js是否适合你。

评论留言