在NestJS中使用GraphQL
- 1554字
- 8分钟
- 2024-07-12
GraphQL 是一种用于 API 查询语言和服务器端运行时的规范,它能够满足客户端对数据的准确需求。本文将介绍 GraphQL 的基本概念,并讲解如何在 NestJS 中集成和使用 GraphQL,包括 Schema 的定义、复杂查询和变更的实现。
GraphQL 的基本概念
GraphQL 是由 Facebook 开发的一种用于 API 的查询语言,它提供了一个灵活和高效的替代方案来替代 REST API。GraphQL 允许客户端请求它们需要的确切数据,不多也不少,并且从多个资源中获取数据只需要一个请求。
主要概念包括:
- Schema:定义 API 中可以查询的所有数据类型和它们之间的关系。
- Query:读取数据的请求。
- Mutation:修改数据的请求。
- Resolver:处理查询和变更请求的函数。
NestJS 中的 GraphQL 模块
NestJS 提供了强大的 GraphQL 模块,支持使用代码优先(code-first)和模式优先(schema-first)两种方法来定义 GraphQL Schema。
在 NestJS 中使用 GraphQL
项目目录结构
在使用 GraphQL 时,我们需要创建一些特定的文件和目录来组织代码:
1src/2├── app.module.ts3├── main.ts4├── user/5│ ├── user.model.ts6│ ├── user.input.ts7│ ├── user.resolver.ts8│ ├── user.service.ts
安装和配置
- 安装必要的包:
1npm install @nestjs/graphql @nestjs/apollo graphql apollo-server-express @nestjs/typeorm typeorm mysql2
- 配置 GraphQL 模块和数据库连接:
在 src/app.module.ts
中配置 GraphQL 模块和 TypeORM 模块:
1import { Module } from "@nestjs/common";2import { GraphQLModule } from "@nestjs/graphql";3import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";4import { TypeOrmModule } from "@nestjs/typeorm";5import { join } from "path";6import { UserModule } from "./user/user.module";7import { User } from "./user/user.model";8
9@Module({10 imports: [11 GraphQLModule.forRoot<ApolloDriverConfig>({12 driver: ApolloDriver,13 autoSchemaFile: join(process.cwd(), "src/schema.gql"), // 自动生成 schema.gql 文件14 }),15 TypeOrmModule.forRoot({16 type: "mysql",17 host: "localhost",18 port: 3306,19 username: "root",20 password: "password",21 database: "test",22 entities: [User],23 synchronize: true,24 }),25 UserModule,26 ],27})28export class AppModule {}
代码优先与模式优先
代码优先(Code-First)
代码优先是通过装饰器定义 Schema,在编译时自动生成 GraphQL Schema 文件。这种方法使得开发者可以通过代码直接定义和管理 Schema。
示例:
1import { ObjectType, Field, Int } from "@nestjs/graphql";2import { Entity, Column, PrimaryGeneratedColumn } from "typeorm";3
4@Entity()5@ObjectType()6export class User {7 @PrimaryGeneratedColumn()8 @Field(() => Int)9 id: number;10
11 @Column()12 @Field()13 name: string;14
15 @Column()16 @Field()17 email: string;18}
模式优先(Schema-First)
模式优先是手动编写 Schema 文件,然后通过解析 Schema 文件生成类型和解析器。这种方法使得开发者可以直接编辑和管理 GraphQL Schema 文件。
示例:
首先编写 Schema 文件:
1type User {2 id: Int!3 name: String!4 email: String!5}6
7type Query {8 getUsers: [User]9}10
11type Mutation {12 createUser(name: String!, email: String!): User13}
然后配置 NestJS 使用这个 Schema 文件:
1import { Module } from "@nestjs/common";2import { GraphQLModule } from "@nestjs/graphql";3import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";4import { join } from "path";5import { UserModule } from "./user/user.module";6
7@Module({8 imports: [9 GraphQLModule.forRoot<ApolloDriverConfig>({10 driver: ApolloDriver,11 typePaths: ["./**/*.graphql"],12 }),13 UserModule,14 ],15})16export class AppModule {}
定义 Schema
在代码优先模式下,我们已经通过装饰器定义了 Schema。
创建和使用 Resolver
在 src/user/user.resolver.ts
中创建 Resolver 来处理查询和变更:
1import { Resolver, Query, Mutation, Args } from "@nestjs/graphql";2import { User } from "./user.model";3import { CreateUserInput } from "./user.input";4import { UserService } from "./user.service";5
6@Resolver(() => User)7export class UserResolver {8 constructor(private readonly userService: UserService) {}9
10 @Query(() => [User])11 async getUsers(): Promise<User[]> {12 return this.userService.getUsers();13 }14
15 @Mutation(() => User)16 async createUser(@Args("input") input: CreateUserInput): Promise<User> {17 return this.userService.createUser(input);18 }19}
实现复杂查询
在 src/user/user.resolver.ts
中实现复杂查询:
1import { Resolver, Query, Args, Int } from "@nestjs/graphql";2import { User } from "./user.model";3import { UserService } from "./user.service";4
5@Resolver(() => User)6export class UserResolver {7 constructor(private readonly userService: UserService) {}8
9 @Query(() => [User])10 async getUsers(11 @Args("page", { type: () => Int, nullable: true }) page: number = 1,12 @Args("limit", { type: () => Int, nullable: true }) limit: number = 10,13 ): Promise<User[]> {14 return this.userService.getUsersWithPagination(page, limit);15 }16
17 @Query(() => [User])18 async searchUsers(19 @Args("keyword", { type: () => String }) keyword: string,20 ): Promise<User[]> {21 return this.userService.searchUsers(keyword);22 }23}24
25// src/user/user.service.ts26import { Injectable } from "@nestjs/common";27import { InjectRepository } from "@nestjs/typeorm";28import { Repository } from "typeorm";29import { User } from "./user.model";30import { CreateUserInput } from "./user.input";31
32@Injectable()33export class UserService {34 constructor(35 @InjectRepository(User)36 private usersRepository: Repository<User>,37 ) {}38
39 async getUsers(): Promise<User[]> {40 return this.usersRepository.find();41 }42
43 async createUser(input: CreateUserInput): Promise<User> {44 const user = this.usersRepository.create(input);45 return this.usersRepository.save(user);46 }47
48 async getUsersWithPagination(page: number, limit: number): Promise<User[]> {49 const [result] = await this.usersRepository.findAndCount({50 skip: (page - 1) * limit,51 take: limit,52 });53 return result;54 }55
56 async searchUsers(keyword: string): Promise<User[]> {57 return this.usersRepository58 .createQueryBuilder("user")59 .where("user.name LIKE :keyword", { keyword: `%${keyword}%` })60 .orWhere("user.email LIKE :keyword", { keyword: `%${keyword}%` })61 .getMany();62 }63}
与前端结合
配置前端环境
在前端项目中,通常使用 Apollo Client 来与 GraphQL API 进行交互。首先,我们需要安装 Apollo Client 相关的依赖:
1npm install @apollo/client graphql
发起 GraphQL 请求
在前端项目中配置 Apollo Client:
1import { ApolloClient, InMemoryCache } from "@apollo/client";2
3const client = new ApolloClient({4 uri: "http://localhost:3000/graphql",5 cache: new InMemoryCache(),6});7
8export default client;
处理查询和变更
使用 Apollo Client 发起查询和变更请求:
1import React from "react";2import { useQuery, gql } from "@apollo/client";3
4const GET_USERS = gql`5 query GetUsers {6 getUsers {7 id8 name9 email10 }11 }12`;13
14function Users() {15 const { loading, error, data } = useQuery(GET_USERS);16
17 if (loading) return <p>Loading...</p>;18 if (error) return <p>Error :(</p>;19
20 return data.getUsers.map(({ id, name, email }) => (21 <div key={id}>22 <p>23 {name}: {email}24 </p>25 </div>26 ));27}28
29export default Users;
处理变更请求:
1import React, { useState } from "react";2import { useMutation, gql } from "@apollo/client";3
4const CREATE_USER = gql`5 mutation CreateUser($name: String!, $email: String!) {6 createUser(input: { name: $name, email: $email }) {7 id8 name9 email10 }11 }12`;13
14function AddUser() {15 const [name, setName] = useState("");16 const [email, setEmail] = useState("");17 const [createUser, { data, loading, error }] = useMutation(CREATE_USER);18
19 const handleSubmit = (e) => {20 e.preventDefault();21 createUser({ variables: { name, email } });22 setName("");23 setEmail("");24 };25
26 return (27 <div>28 <form onSubmit={handleSubmit}>29 <input30 value={name}31 onChange={(e) => setName(e.target.value)}32 placeholder="Name"33 />34 <input35 value={email}36 onChange={(e) => setEmail(e.target.value)}37 placeholder="Email"38 />39 <button type="submit">Add User</button>40 </form>41 {loading && <p>Loading...</p>}42 {error && <p>Error :(</p>}43 {data && <p>User {data.createUser.name} created!</p>}44 </div>45 );46}47
48export default AddUser;
在前端应用中使用这些组件:
1import React from "react";2import { ApolloProvider } from "@apollo/client";3import client from "./apollo-client";4import Users from "./components/Users";5import AddUser from "./components/AddUser";6
7function App() {8 return (9 <ApolloProvider client={client}>10 <div>11 <h2>My first Apollo app 🚀</h2>12 <AddUser />13 <Users />14 </div>15 </ApolloProvider>16 );17}18
19export default App;
总结
本文介绍了 GraphQL 的基本概念,以及如何在 NestJS 项目中集成和使用 GraphQL。通过配置 GraphQL 模块,定义 Schema,创建和实现查询与变更,以及实现复杂查询,开发者可以充分利用 GraphQL 的强大功能来构建高效灵活的 API。最后,我们还展示了如何在前端项目中使用 Apollo Client 与 GraphQL API 进行交互,发起查询和变更请求,并处理返回的数据。通过这些示例,我们可以在 NestJS 中创建自己的 GraphQL API,并与前端项目无缝集成,满足不同的业务需求。


