Nest 实现 GraphQL 版 TodoList
我们经常用 restful 的接口来开发业务。
比如 GET 请求 /students 查询所有学生,/students/1 查询 id 为 1 的学生
发送 POST、PUT、DETETE 请求分别代表增删改。
其实也可以用 GraphQL 的方式来写接口:
查询: 
新增: 

增删改查都在一个接口里搞定,并且想要什么数据由前端自己取。
今天我们就用 Nest + GrahQL 做一个 TodoList 的增删改查。
数据存在 mysql 里,用 Prisma 作为 ORM 框架。

创建个项目,然后我们首先来实现 restful 接口的增删改查。
用 docker 把 mysql 跑起来:
从 docker 官网下载 docker desktop,这个是 docker 的桌面端:

跑起来后,搜索 mysql 镜像(这步需要科学上网),点击 run:

输入容器名、端口映射、以及挂载的数据卷,还要指定一个环境变量:

端口映射就是把宿主机的 3306 端口映射到容器里的 3306 端口,这样就可以在宿主机访问了。
数据卷挂载就是把宿主机的某个目录映射到容器里的 /var/lib/mysql 目录,这样数据是保存在本地的,不会丢失。
而 MYSQL_ROOT_PASSWORD 的密码则是 mysql 连接时候的密码。

跑起来后,我们用 GUI 客户端连上,这里我们用的是 mysql workbench,这是 mysql 官方提供的免费客户端:

连接上之后,点击创建 database:

指定名字、字符集为 utf8mb4,然后点击右下角的 apply。
创建成功之后在左侧就可以看到这个 database 了:

现在还没有表。
我们在 Nest 里用 Prisma 连接 mysql。
进入项目,安装 prisma
执行 prisma init 创建 schema 文件:

生成了 schema 文件(用来定义 model 的),和 .env 文件:

改下 .env 的配置:
并且修改下 schema 里的 datasource 部分:
然后创建 model:

id 自增,content 是长度为 50 的字符串,还有创建时间 createTime、更新时间 updateTime。
执行 prisma migrate dev,它会根据定义的 model 去创建表:

它会生成 sql 文件,里面是这次执行的 sql。
然后还会生成 client 代码,用来连接数据库操作这个表。
可以看到,这次执行的 sql 就是 create table 建表语句:

这时候数据库就就有这个表了:

接下来我们就可以在代码里做 CRUD 了。
生成一个 service:

改下生成的 PrismaService,继承 PrismaClient,这样它就有 crud 的 api 了:
在 constructor 里设置 PrismaClient 的 log 参数,也就是打印 sql 到控制台。
在 onModuleInit 的生命周期方法里调用 $connect 来连接数据库。
然后在 AppService 里注入 PrismaService,实现 CRUD:
@Inject 注入 PrismaService,用它来做 CRUD,where 是条件、data 是数据,select 是回显的字段:

然后创建用到的两个 dto 的 class
todolist-create.dto.ts
todolist-update.dto.ts
在 AppController 里引入下,添加几个路由:
添加增删改查 4 个路由,post 请求用 @Body() 注入请求体,@Query 拿路径中的参数:

把服务跑起来试一下:

首先是 list,现在没有数据:

然后添加一个:

服务端打印了 insert into 的 sql:

数据库也有了这条记录:

再加一个:

然后查一下:

接下来试下修改、删除:


再查一下:

没啥问题。
这样,todolist 的 restful 版接口就完成了。
接下来实现 graphql 版本:
安装用到的包:
然后在 AppModule 里引入下:
typePaths 就是 schema 文件的路径:

添加一个 todolist.graphql
语法比较容易看懂,就是定义数据的结构。
在 Query 下定义查询的接口,在 Mutation 下定义增删改的接口。
然后实现 resolver,也就是这些接口的实现:

用 @Resolver 声明 resolver,用 @Query 声明查询接口,@Mutation 声明增删改接口,@Args 取传入的参数。
具体增删改查的实现和之前一样。
浏览器访问 http://localhost:3000/graphql 就是 playground,可以在这里查询:

左边输入查询语法,右边是执行后返回的结果。
当然,对新手来说这个 playground 不够友好,没有提示。
我们换一个:


试一下新增:

查询:

修改:

单个查询:

删除:

查询:

基于 GraphQL 的增删改查都成功了!
然后在 react 项目里调用下。

进入项目,安装 @apollo/client
改下 main.tsx
创建 ApolloClient 并设置到 ApolloProvider。
然后在 App.tsx 里用 useQuery 发请求:
把服务跑起来:

这里涉及到的跨域,现在后端服务里开启下跨域支持:

可以看到,返回了查询结果:

然后加一下新增:

用 useMutation 的 hook,指定 refetchQueries 也就是修改完之后重新获取数据。
调用的时候传入 content 数据。
测试下:

数据库里也可能看到新增的数据:

这样,我们就能在 react 项目里用 graphql 做 CRUD 了。
案例代码上传了 github。
后端代码: https://github.com/QuarkGluonPlasma/nestjs-course-code/tree/main/graphql-todolist
前端代码:https://github.com/QuarkGluonPlasma/nestjs-course-code/tree/main/graphql-todolist-client
总结
我们实现了 Restful 和 GraphQL 版的 CRUD。
前端用 React + @apollo/client。
后端用 Nest + GraphQL + Prisma + MySQL。
GraphQL 主要是定义 schema 和 resolver 两部分,schema 是 Query、Mutation 的结构,resolver 是它的实现。
可以在 playground 里调用接口,也可以在 react 里用 @appolo/client 调用。
相比 restful 的版本,graphql 只需要一个接口,然后用查询语言来查,需要什么数据取什么数据,更加灵活。
业务开发中,你会选择用 GraphQL 开发接口么?
#前端# #后端#