NestJS là gì?
NestJS là một khung NodeJS hiện đại sử dụng các khung NodeJS phổ biến như Express và Fastify. NestJS phần lớn được lấy cảm hứng từ Angular và do đó, nó sử dụng một hệ thống mô-đun kiểu Angular. NestJS được viết bằng TypeScript, mặc dù nó cũng hỗ trợ JavaScript gốc.
Điều kiện tiên quyết
Để làm theo hướng dẫn này, bạn phải đáp ứng các yêu cầu sau
- Năng lực trong PostMan hoặc bất kỳ công cụ kiểm tra API nào khác.
- Kiến thức cơ bản về ứng dụng NodeJS và Express.
- Kiến thức cơ bản về TypeScript.
- Năng lực trong MongoDB (Mongoose).
Phần sau sẽ được cài đặt trên hệ thống của bạn
- NodeJS v.14 trở lên.
- Mã Visual Studio (Được khuyến nghị) hoặc bất kỳ IDE nào khác.
- PostMan hoặc bất kỳ Công cụ kiểm tra API nào khác.
Các thuật ngữ phổ biến được sử dụng trong NestJS;
Dưới đây là một số thuật ngữ được sử dụng thường xuyên nhất trong NestJS mà bạn sẽ gặp nhiều trong bài viết này.
Giao diện
Giao diện là một định nghĩa kiểu. Do đó, nó được sử dụng như một trình kiểm tra / thực thi kiểu trong các hàm, lớp, v.v.
interface humanInterface{
name:string;
gender:string;
age:number;
}
const kevin: humanInterface={
name:'Kevin Sunders',
gender:'Male',
age: 25,
}
humanInterface
ở trên thực hiện kiểm tra kiểu nghiêm ngặt trên kevin
vật. Typecript sẽ gây ra lỗi nếu bạn thêm một trường khác hoặc thay đổi kiểu của bất kỳ thuộc tính nào trong số các thuộc tính của đối tượng.
Bộ điều khiển
Các bộ điều khiển có nhiệm vụ tiếp nhận các yêu cầu gửi đến và phản hồi cho máy khách. Bộ điều khiển cộng tác với dịch vụ liên quan của nó.
Dịch vụ
Dịch vụ là một nhà cung cấp lưu trữ và truy xuất dữ liệu và được sử dụng với bộ điều khiển tương ứng của nó.
Người trang trí
Decorator là một biểu thức trả về hàm chấp nhận một target
, name
và property descriptor
như là các đối số tùy chọn. Trình trang trí được viết là @decorator-name
. Chúng thường được đính kèm với khai báo lớp, phương thức và tham số.
@Get()
getAll(): Model[] {
return this.testService.getAll();
}
@Get
trình trang trí ở trên đánh dấu khối mã bên dưới nó là GET
yêu cầu. Tìm hiểu thêm về điều đó sau.
Mô-đun
Mô-đun là một phần của chương trình xử lý một tác vụ cụ thể. Một mô-đun trong NestJS được đánh dấu bằng cách chú thích một lớp được chú thích bằng @Module()
người trang trí. Nest sử dụng siêu dữ liệu do @Module()
cung cấp decorator để tổ chức cấu trúc ứng dụng.
Cài đặt CLI
Để bắt đầu, bạn sẽ phải cài đặt NestJS CLI **** với npm
. Bạn có thể bỏ qua bước này nếu bạn đã cài đặt NestJS CLI trên hệ thống của mình.
npm i -g @nestjs/cli
Khối mã ở trên sẽ cài đặt CLI lồng trên toàn cầu trên hệ thống của bạn.
Tạo một dự án mới
Để tạo một dự án mới, hãy chạy nest new
theo sau là tên dự án mong muốn của bạn. Đối với bài viết này, chúng tôi sẽ viết một API blog đơn giản với chức năng CRUD trong khi tuân thủ các tiêu chuẩn RESTful.
nest new Blog-Api
Lệnh này sẽ nhắc bạn chọn một trình quản lý gói, hãy chọn npm
.
Sau đó, điều này sẽ mở đầu cho toàn bộ cấu trúc dự án với một điểm cuối API thử nghiệm có cổng được đặt thành 3000
theo mặc định. Bạn có thể kiểm tra nó tại http://localhost:3000
sau khi chạy npm run start:dev
lệnh này sẽ khởi động máy chủ ở chế độ xem tương tự như những gì gật đầu thực hiện trong các ứng dụng express.
Sau khi kiểm tra điểm cuối, bạn sẽ cần xóa một số tệp mặc định vì bạn sẽ không cần chúng nữa. Để làm điều này;
- mở thư mục src và bên trong,
- xóa
app.controller.spec.ts
, - xóa
app.controller.ts
, - xóa
app.service.ts
, - Mở
app.module.ts
, - Xóa tham chiếu đến
AppController
trongcontrollers
mảng và các lần nhập, - Xóa tham chiếu đến
AppService
trongproviders
mảng và các lần nhập.
Bạn cũng có thể cần thay đổi README.md
để đáp ứng các thông số kỹ thuật của bạn.
app.module.ts
của bạn tệp sẽ trông như thế này,
//app.module.ts
import { Module } from '@nestjs/common';
@Module({
imports: [],
controllers: [],
providers: [],
})
export class AppModule {}
Biến môi trường
Thông lệ tốt, một số thông tin nhạy cảm trong mã của bạn không nên được công khai. Ví dụ:PORT
của bạn và MongoDB URI
của bạn .
Hãy sửa lỗi này trong mã của bạn.
Trên thiết bị đầu cuối của bạn chạy
npm i dotenv
Sau đó, tạo một .env
tệp trong thư mục của bạn và thêm nó vào .gitignore
của bạn tập tin. Lưu trữ PORT
của bạn , bạn cũng sẽ phải lưu trữ MongoDB URI
của mình sau này ở cùng một nơi. Bây giờ hãy thay thế PORT
bị lộ trong main.ts
của bạn tập tin. Để thực hiện việc này, hãy nhập dotenv
gói và gọi .config()
phương pháp trên đó.
import * as dotenv from 'dotenv';
dotenv.config();
Đây phải là main.ts
của bạn sau khi bạn làm theo các bước ở trên.
//main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as dotenv from 'dotenv';
dotenv.config();
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT);
}
bootstrap();
Tạo mô-đun
Để tạo mô-đun NestJS bằng NestJS CLI, hãy chạy đoạn mã bên dưới.
nest generate module blogs
Lệnh này tạo một blogs
thư mục chứa blogs.module.ts
tệp và đăng ký BlogsModule
trong app.module.ts
của bạn tệp.
Tạo giao diện
Hãy tạo giao diện bằng NestJS CLI để thực hiện việc kiểm tra loại đối tượng sẽ đại diện cho các bài đăng trên blog của bạn. Để đạt được điều này, trước tiên bạn phải cd
vào blogs
vì chúng được khuyến nghị lưu trữ gần các đối tượng miền mà chúng được liên kết.
cd src/blogs
Sau đó, chạy đoạn mã bên dưới để tạo giao diện.
nest generate interface blogs
điều này tạo ra một blogs.interface.ts
tập tin. Đây là nơi chúng tôi sẽ xác định giao diện của mình. chúng tôi sẽ đặt tên giao diện là BlogsInterface
.
export interface BlogsInterface {
title: string;
body: string;
category: string;
dateCreated: Date;
}
trước khi chạy thêm bất kỳ lệnh nào trên thiết bị đầu cuối của bạn, hãy nhớ cd
ra khỏi src
thư mục và trở lại thư mục gốc của bạn bằng cách chạy
cd ../..
Tạo dịch vụ &bộ điều khiển
Bạn sẽ cần tạo một lớp dịch vụ để lưu trữ và truy xuất dữ liệu cũng như xử lý tất cả logic và một lớp bộ điều khiển để xử lý tất cả các yêu cầu đến và phản hồi đi.
Dịch vụ
Để tạo một dịch vụ, hãy chạy lệnh dưới đây,
nest generate service blogs
Lệnh này tạo hai tệp blogs.service.spec.ts
và blogs.service.ts
và đăng ký dịch vụ trong providers
mảng trong blogs.module.ts
.
Bộ điều khiển
Để tạo bộ điều khiển, hãy chạy lệnh bên dưới,
nest generate controller blogs
Lệnh này tạo hai tệp blogs.controller.spec.ts
và blogs.controller.ts
và đăng ký bộ điều khiển trong controllers
mảng trong blogs.module.ts
.
Với những điều này, cấu trúc blog của bạn gần như hoàn chỉnh, bạn chỉ cần tạo BlogsService
có thể truy cập vào các phần khác của chương trình của bạn. Bạn có thể đạt được điều này bằng cách tạo exports
mảng trong blogs.module.ts
gửi và đăng ký BlogsService
trong mảng đó.
//blogs.module.ts
import { Module } from '@nestjs/common';
import { BlogsService } from './blogs.service';
import { BlogsController } from './blogs.controller';
@Module({
providers: [BlogsService],
controllers: [BlogsController],
exports: [BlogsService],
})
export class BlogsModule {}
MongoDB (Mongoose).
Cài đặt mongoose bằng cách chạy,
npm install --save @nestjs/mongoose mongoose
Sau khi cài đặt, hãy nhập {MongooseModule}
từ '@nestjs/mongoose’
vào app.module.ts
của bạn tập tin. Sau đó lấy MongoDB URI
của bạn và lưu trữ nó trong .env
của bạn tập tin. Lặp lại các bước để nhập dotenv
trong app.module.ts
tập tin. Sau đó, trong imports
gọi mảng .forRoot()
phương thức lấy MongoDB URI
của bạn làm đối số trên MongooseModule
. Tương tự với mongoose.connect()
trong các ứng dụng cấp tốc thông thường.
@Module({
imports: [BlogsModule, MongooseModule.forRoot(process.env.MONGODB_URI)],
Tạo một lược đồ.
Hãy tạo một giản đồ để xác định hình dạng của các blog trong bộ sưu tập của chúng tôi. Để làm điều này,
- Tạo một thư mục bên trong
blogs
của bạn thư mục, đặt tên cho nó làschemas
, - Bên trong các lược đồ
schemas
, tạo một tệp và gọi nó làblogs.schema.ts
.
Sau đó,
Trước tiên, bạn sẽ phải,
- Nhập
prop
decorator,Schema
trình trang trí vàSchemaFactory
từ@nestjs/mongoose
, - Tạo một lớp
Blog
và xuất nó, - Chuyển lớp thành một Lược đồ bằng cách đặt
@Schema()
người trang trí phía trên lớp, - Tạo một
BlogSchema
không đổi , chỉ định giá trị trả về của việc gọi.createForClass(Blog)
với tên lớp của bạn làm đối số trênSchemaFactory
mà bạn đã nhập trước đó.
//blogs.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
@Schema()
export class Blog {}
export const BlogSchema = SchemaFactory.createForClass(Blog);
Sau đó, bạn sẽ cần xác định các thuộc tính của Lược đồ.
Để xác định một thuộc tính trong lược đồ, bạn sẽ cần đánh dấu từng thuộc tính bằng @prop()
người trang trí. @prop
decorator chấp nhận một đối tượng tùy chọn hoặc một khai báo kiểu phức tạp. Khai báo kiểu phức tạp có thể là mảng và khai báo kiểu đối tượng lồng nhau.
//blogs.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
@Schema()
export class Blog {
@Prop({ required: true })
title: string;
@Prop({ required: true })
body: string;
@Prop({ required: true })
category: string;
@Prop({ required: true })
dateCreated: Date;
}
export const BlogSchema = SchemaFactory.createForClass(Blog);
Nhập tiếp theo { Document }
từ 'mongoose'
.
Sau đó, tạo một kiểu liên hợp với lớp Giản đồ và Document
đã nhập . Như vậy,
//blogs.schema.ts
import { Document } from 'mongoose';
export type BlogDocument = Blog & Document;
blogs.schema.ts
cuối cùng của bạn tệp sẽ trông như thế này,
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
export type BlogDocument = Blog & Document;
@Schema()
export class Blog {
@Prop({ required: true })
title: string;
@Prop({ required: true })
body: string;
@Prop({ required: true })
category: string;
@Prop({ required: true })
dateCreated: Date;
}
export const BlogSchema = SchemaFactory.createForClass(Blog);
Lược đồ đăng ký
Bạn sẽ cần nhập mọi thứ vào blogs.module.ts
của mình tập tin. Để đạt được điều này, bạn cần phải,
- Nhập
{MongooseModule}
từ'@nestjs/mongoose’
, - Nhập
{Blog, BlogSchema}
từ'./schemas/blogs.schema'
- Tạo một
imports
mảng bên trong@module
người trang trí - Gọi
.forFeature()
trênMongooseModule
. Điều này đưa vào một mảng chứa một đối tượng xác định mộtname
và mộtschema
thuộc tính sẽ được đặt thànhBlog.name
của bạn vàBlogSchema
của bạn tương ứng.
@Module({
imports: [
MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
],
Lược đồ tiêm
Bạn sẽ cần đưa vào Blog
mô hình thành blogs.service.ts
bằng cách sử dụng @InjectModel()
người trang trí. Để đạt được điều này, bạn sẽ phải
- nhập
{ Model }
từ'mongoose'
, - nhập
{ InjectModel }
từ'@nestjs/mongoose’
, - Nhập
{Blog, BlogDocument}
từ'./schemas/blogs.schema’
, - Tạo một
constructor
bên trongBlogsService
lớp học, - Khai báo một
private
biến và gọi nó làblogModel
và gán một loạiModel<BlogDocument>
với nó. Tất cả các phương thức mongoose sẽ được gọi trên biến này.
Nhớ lại rằng, BlogDocument
là kiểu kết hợp của Blog
lớp và Model
của Mongoose mà bạn đã tạo trước đó. Nó được sử dụng làm kiểu chung cho biến của bạn.
- Trang trí
blogModel
với@InjectModel()
và chuyểnBlog.name
như một đối số.
constructor(
@InjectModel(Blog.name)
private blogModel: Model<BlogDocument>,
) {}
Cách hoạt động của định tuyến
Đến đây chắc hẳn bạn đã nhận thấy rằng @Controller
người trang trí có chuỗi 'blogs'
truyền vào nó. Điều này có nghĩa là bộ điều khiển sẽ gửi tất cả các phản hồi và xử lý tất cả các yêu cầu được thực hiện trên http://localhost/3000/blogs
.
Tiếp theo, bạn sẽ triển khai logic của bộ điều khiển và dịch vụ.
Dịch vụ và Logic điều khiển.
Cuối cùng đã đến lúc triển khai chức năng CRUD của bạn.
Trước khi bắt đầu, bạn cần thiết lập bộ điều khiển của mình. Bắt đầu bằng cách nhập một số HTTP
bộ trang trí phương pháp vào bộ điều khiển của bạn.
//blogs.controller.ts
import {
Controller,
Body,
Delete,
Get,
Post,
Put,
Param,
} from '@nestjs/common';
Sau đó, bạn sẽ cần nhập và đăng ký dịch vụ để có thể truy cập và nhập giao diện để kiểm tra loại.
//blogs.controller.ts
import { BlogsInterface } from './blogs.interface';
import { BlogsService } from './blogs.service';
Để đăng ký dịch vụ của bạn, hãy tạo một constructor
bên trong BlogsController
lớp và khai báo một private readonly
dịch vụ service
và đặt loại của nó thành BlogsService
.
constructor(private readonly service: BlogsService) {}
Bây giờ bạn đã thiết lập xong, hãy bắt đầu.
Tạo
Logic dịch vụ
Nhập { BlogsInterface }
từ './blogs.interface'
và thêm một async
chức năng của BlogsService
lớp được gọi là createBlog
, sẽ lấy một tham số blogs
, với loại của nó là BlogInterface
và kiểu trả về của nó là Promise
với một <Blog>
chung chung gõ phím.
async createBlog(blog: BlogsInterface): Promise<Blog> {
return await new this.blogModel({
...blog,
dateCreated: new Date(),
}).save();
}
Logic của bộ điều khiển
Trong BlogsController
của bạn lớp thêm một async
chức năng của lớp. Gọi nó là createBlog
và đánh dấu nó bằng @Post
decorator định nghĩa nó là một POST
yêu cầu. createBlog
lấy một tham số blogs
, với loại của nó là BlogInterface
. Đánh dấu tham số bằng @Body
decorator trích xuất toàn bộ body
đối tượng từ req
đối tượng và điền thông số được trang trí bằng giá trị của body
.
@Post()
async createBlog(
@Body()
blog: BlogsInterface,
) {
return await this.service.createBlog(blog);
}
Đọc
Thêm hai async
phương pháp, một để trả về một bài đăng trên blog và phương thức thứ hai để trả về tất cả các bài đăng trên blog.
Logic dịch vụ
async getAllBlogs(): Promise<Blog[]> {
return await this.blogModel.find().exec();
}
async getBlog(id: string): Promise<Blog> {
return await this.blogModel.findById(id);
}
Logic của bộ điều khiển
@Get()
async getAllBlogs() {
return await this.service.getAllBlogs();
}
@Get(':id')
async getBlog(@Param('id') id: string) {
return await this.service.getBlog(id);
}
async
các chức năng được đánh dấu bằng @Get
decorator định nghĩa nó là một GET
yêu cầu.
async
thứ hai trình trang trí của hàm có đối số ':id'
. Đó là những gì bạn sẽ chuyển vào @Param
người trang trí. Tham số được đánh dấu bằng @Param('id')
trích xuất params
thuộc tính từ req
đối tượng và điền thông số được trang trí bằng giá trị của params
.
Cập nhật
Hãy triển khai logic cho PUT
yêu cầu.
Logic dịch vụ
async updateBlog(id: string, body: BlogsInterface): Promise<Blog> {
return await this.blogModel.findByIdAndUpdate(id, body);
}
Logic của bộ điều khiển
@Put(':id')
async updateBlog(
@Param('id')
id: string,
@Body()
blog: BlogsInterface,
) {
return await this.service.updateBlog(id, blog);
}
async
tham số thứ hai của hàm được đánh dấu bằng @Body()
decorator trích xuất toàn bộ body
đối tượng từ req
đối tượng và điền thông số được trang trí bằng giá trị của body
.
Xóa
Hãy triển khai logic cho delete
yêu cầu.
Logic dịch vụ
async deleteBlog(id: string): Promise<void> {
return await this.blogModel.findByIdAndDelete(id);
}
Promise
loại chung là void
bởi vì một Delete
yêu cầu trả về một lời hứa trống rỗng.
Logic của bộ điều khiển
@Delete(':id')
async deleteBlog(@Param('id') id: string) {
return await this.service.deleteBlog(id);
}
Kiểm tra API
Để kiểm tra API này, bạn nên sử dụng công cụ kiểm tra API. Đối với bài viết này, tôi sẽ sử dụng một công cụ kiểm tra API phổ biến có tên là Postman. Tôi sẽ sử dụng dữ liệu ngẫu nhiên về các chủ đề phổ biến để kiểm tra.
Tạo
Tạo POST
yêu cầu http://localhost/3000/blogs
với các đối tượng JSON sau, điều này sẽ thêm tất cả dữ liệu vào cơ sở dữ liệu của bạn.
{
"title": "jeen-yuhs",
"body": "The life of superstar rapper Kanye West is currently streaming on Netflix - and according to our jeen-yuhs review, it's a fascinating watch. -credit:Radio Times",
"category":"Music"
}
{
"title": "Why You Should Always Wash Your Hands",
"body": "Germs from unwashed hands can be transferred to other objects, like handrails, tabletops, or toys, and then transferred to another person's hands.-credit cdc.gov",
"category":"Health"
}
{
"title": "Why You Should Follow me on Twitter",
"body": "Well, Because I asked nicely",
"category":"Random"
}
Bạn sẽ nhận được 201
phản hồi và blog đã tạo với ngày tháng và _id
đã thêm.
Đọc
Thực hiện GET
yêu cầu http://localhost/3000/blogs
. Điều này sẽ trả về một
200
phản hồi với một mảng của tất cả dữ liệu bạn đã thêm trước đó. Sao chép _id
thuộc tính của một trong các đối tượng mảng.
Tạo một GET
khác yêu cầu http://localhost/3000/blogs/id
với id đã sao chép trước đó. Điều này sẽ trả về 200
phản hồi với dữ liệu của đối tượng có id được sử dụng để thực hiện yêu cầu.
Cập nhật
Tạo PUT
yêu cầu http://localhost/3000/blogs/id
với dữ liệu dưới đây. id
nên được thay thế bằng cái bạn đã sao chép trước đó. Điều này sẽ trả về 200
phản hồi và cập nhật đối tượng mang id
đằng sau hậu trường. nếu bạn chạy một GET
khác yêu cầu bạn sẽ nhận được đối tượng cập nhật.
{
"title": "why you Should Cut your Nails",
"body": "It's important to trim your nails regularly. Nail trimming together with manicures makes your nails look well-groomed, neat, and tidy.- credit:WebMD",
"category":"Health"
}
Xóa
Thực hiện DELETE
yêu cầu http://localhost/3000/blogs/id
. Điều này sẽ trả về 200
phản hồi và xóa đối tượng mang id
đằng sau hậu trường. nếu bạn chạy một GET
khác yêu cầu bạn sẽ không nhìn thấy đối tượng đã xóa.
Kết luận
Vì vậy, chúng tôi cuối cùng ở cuối bài viết này. Hãy tóm tắt lại những gì bạn đã đề cập.
- NestJS là gì,
- Các thuật ngữ trong NestJS,
- Tạo ứng dụng NestJS,
- Tích hợp MongoDB vào ứng dụng NestJS,
- Thao tác và ứng dụng NestJS,
Đó là khá nhiều, chúc mừng bạn đã làm được điều này.
Bạn có thể tìm thấy mã trên github.
Chúc bạn may mắn trên hành trình NestJS!