【全栈开发】使用NestJS、Angular和Prisma 打造全栈Typescript开发

在开发Angular应用程序时,我非常喜欢Typescript。使用NestJS,您可以以与Angular非常相似的方式编写后端。

我偶然发现了这个库,发现它非常有趣,所以我想设置一个简单的测试项目。一般来说,我主要使用SQL数据库,因此我也将尝试Prisma将我们的数据存储在PostgreSQL中,并在前端和后端之间提供一个通用模型。

要开始使用NestJS,您必须安装npm包并运行CLI命令来创建新的应用程序。为了在NestJS项目中托管我们的Angular应用程序,我们还需要添加NestJS静态包。

复制代码
** Install NestJS and create the Project.
npm install --save @nestjs/cli
nest new backend
npm install --save @nestjs/serve-static**Create our Angular application
cd backend
ng new ui

您已经可以看到CLI的实现与Angular非常相似。为了使NestJS能够托管我们的Angular应用程序,我们可以在后端的app.module.ts文件中添加对静态网站的引用。

复制代码
@Module({
  imports: [ServeStaticModule.forRoot({
    rootPath: join(__dirname, '../../ui', 'dist/ui'),
  }),],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

我们可以参考Angular dist文件夹的位置。

复制代码
**Build the angular code
cd ui
ng build**Start the nest server
cd ..
nest start --watch

现在我们已经运行了基本功能,我们可以设置模型了。我们将为专业驾驶的公里数创建一个简单的日志记录应用程序。我将在Prisma中完成这项工作,在那里我们可以创建一个模型,并自动生成客户端和数据库。

复制代码
npm install prisma --save-dev
npx prisma init

这将创建一个"schema.prisma"文件,并添加一个.env文件,我们可以在其中配置到数据库的连接字符串。我将在这里使用PostgreSQL,但prisma也支持MySQL、SQL Server甚至MongoDB。在模式文件中,我在这里为DriveLog创建一个简单的模型。

复制代码
model DriveLog {
  id          Int      @id @default(autoincrement())
  createdAt   DateTime @default(now())
  timestamp   DateTime  
  destination String?  
  odoStart  Int
  odoEnd    Int
  distance  Int?
}

我们将记录行程的时间和目的地,以及里程计的开始和结束值。

假设您已经正确配置了连接字符串,现在可以将模型推送到数据库中。这也将自动生成客户端代码。

复制代码
**Push the model to the DB and generate a PrismaClient.
npx prisma db push

因为我们想利用NestJS的注入功能,这些功能的工作方式与Angular非常相似。我们将创建一个PrismaService来包装生成的客户端代码。

复制代码
**Generate an empty service for NestJS
nest generate service prisma


import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient
  implements OnModuleInit {

  async onModuleInit() {
    await this.$connect();
  }

  async enableShutdownHooks(app: INestApplication) {
    this.$on('beforeExit', async () => {
      await app.close();
    });    
  }
}

我们在这里引用生成的PrismaClient,并确保我们可以从应用程序访问它,而不必每次都创建新的客户端。

现在,我们可以设置后端逻辑来创建CRUD操作,并将其添加到app.service文件中。我们将设置一个获取全部、保存和删除操作。

复制代码
import { Injectable } from '@nestjs/common';
import { DriveLog } from '@prisma/client';
import { PrismaService } from './prisma/prisma.service';

@Injectable()
export class AppService {

  constructor(private prisma: PrismaService) { }

  async getAll(): Promise<DriveLog[]> {
    return await this.prisma.driveLog.findMany();
  }

  async save(log: DriveLog) {
    let distance = log.odoEnd - log.odoStart;
    if(log.id){
      await this.prisma.driveLog.update({ where: {id: log.id}, data: { timestamp: new Date(log.timestamp), destination: log.destination, odoStart: log.odoStart, odoEnd: log.odoEnd, distance: distance }} );
    }else{
      await this.prisma.driveLog.create({ data: { timestamp: new Date(log.timestamp), destination: log.destination, odoStart: log.odoStart, odoEnd: log.odoEnd, distance: distance } });
    }
  }

  async delete(logId: number) {
    await this.prisma.driveLog.delete({ where: { id: logId } })
  }
}

我们将根据给定里程表值的开始-结束值计算保存操作中行驶的距离。

接下来,我们需要设置控制器,以便向Angular应用程序公开一些端点。

复制代码
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common';
import { DriveLog } from '@prisma/client';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private appService: AppService) {}

  @Get("api/logs")
  async getAll(): Promise<DriveLog[]> {
    return await this.appService.getAll();
  }

  @Post("api/logs")
  async create(@Body()log: DriveLog): Promise<void> {
    await this.appService.save(log);
  }

  @Delete("api/logs/:log")
  async delete(@Param('log') log: string ): Promise<void> {
    await this.appService.delete(parseInt(log));
  }
}

现在我们已经准备好设置Angular应用程序了。首先确保我们导入HttpClientModule和FormsModule,这样我们就可以创建一个简单的表单并调用我们刚刚在nest中创建的端点。

复制代码
<ul>
  <li *ngFor="let log of logs">
    {{log.timestamp |date}} - {{log.destination}} - {{log.distance}}km 
    <button (click)="deleteLog(log.id)">X</button>
    <button (click)="edit(log)">Edit</button>
  </li>
</ul>
<form>
  <input type="date" [(ngModel)]="newLog.timestamp" name="timestamp" placeholder="timestamp" >
  <input type="text" [(ngModel)]="newLog.destination" name="destination" placeholder="destination">
  <input type="number" [(ngModel)]="newLog.odoStart" name="odoStart" placeholder="start (km)" >
  <input type="number" [(ngModel)]="newLog.odoEnd" name="odoEnd" placeholder="end (km)" >
  <button (click)="save()">{{ newLog.id ? 'Save' : 'Add' }}</button>
</form>

在app.component.html中,我们创建了一个简单的表单,可以在其中查看、添加、更新和删除我们的旅行日志。

我们现在可以为app.component设置控制器来调用NestJS端点。

复制代码
import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';
import { DriveLog } from '@prisma/client';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {

  logs: DriveLog[] = []
  newLog: DriveLog = <DriveLog>{}

  constructor(private http: HttpClient) {
    this.getAll();
  }

  getAll() {
    this.http.get<DriveLog[]>("api/logs").subscribe(l => this.logs = l)
  }

  edit(log: DriveLog){
    this.newLog = log;
    this.newLog.timestamp = new Date(log.timestamp);
  }
 
  save() {
    this.http.post("api/logs", this.newLog).subscribe(() => this.getAll());
    this.newLog = <DriveLog>{};
  }

  deleteLog(id: number){
    this.http.delete(`api/logs/${id}`).subscribe(() => this.getAll());
  }
}

请注意,我们可以在这里简单地引用从prisma生成的DriveLog类型。

现在我们只需要构建我们的Angular代码,当再次运行NestJS应用程序时,我们将使表单正常工作。

这(对我来说)的好处在于,我可以从前端到后端编写应用程序,包括数据库逻辑,而无需更改编程语言,也无需维护前端和后端之间的工作方式。

文章链接

【全栈开发】使用NestJS【全栈开发】使用

欢迎收藏【架构师酒馆】和【开发者开聊

相关推荐
桂月二二35 分钟前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062062 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb2 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角2 小时前
CSS 颜色
前端·css
浪浪山小白兔3 小时前
HTML5 新表单属性详解
前端·html·html5
lee5763 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579653 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
limit for me4 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者4 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架
qq_392794484 小时前
前端缓存策略:强缓存与协商缓存深度剖析
前端·缓存