引言
\n\nGraphQL是一种用于API的查询语言,它允许客户端仅获取所需的数据。与TypeScript结合使用时,它成为创建类型安全、可扩展且文档完善的API的强大工具。在本逐步教程中,我们将使用Apollo Server和TypeGraphQL实际构建一个完整的基于TypeScript的GraphQL API。
您将了解到:
\n- \n
- 如何配置一个包含TypeScript和Apollo Server的项目 \n
- 如何使用TypeGraphQL装饰器定义GraphQL模式 \n
- 如何编写具有完整类型定义的解析器 \n
- 如何连接数据库并执行查询 \n
本材料对初学者以及已熟悉REST API但希望掌握构建API的现代方法的开发者都很有帮助。
\n\n1. 项目配置与依赖安装
\n\n我们从初始化项目开始。请确保您已安装Node.js(版本16+)和npm/yarn。
\n\nmkdir graphql-ts-tutorial\ncd graphql-ts-tutorial\nnpm init -y\n\n安装必要的包:
\n\nnpm install apollo-server graphql reflect-metadata type-graphql class-validator\nnpm install -D typescript @types/node ts-node\n\n创建tsconfig.json文件:
{\n "compilerOptions": {\n "target": "ES2020",\n "module": "commonjs",\n "lib": ["ES2020"],\n "experimentalDecorators": true,\n "emitDecoratorMetadata": true,\n "strict": true,\n "esModuleInterop": true,\n "outDir": "./dist",\n "rootDir": "./src"\n },\n "include": ["src/**/*"]\n}\n\n请注意experimentalDecorators和emitDecoratorMetadata标志——它们是TypeGraphQL工作所必需的。
2. 使用TypeGraphQL定义模式和类型
\n\n创建src文件夹和文件src/types/User.ts。在这里我们将描述用户模型。
import { ObjectType, Field, ID, InputType } from "type-graphql";\n\n@ObjectType()\nexport class User {\n @Field(() => ID)\n id!: number;\n\n @Field()\n name!: string;\n\n @Field()\n email!: string;\n\n @Field()\n createdAt!: Date;\n}\n\n说明:
\n- \n
@ObjectType()— 将类标记为GraphQL类型。 \n @Field()— 指示哪些字段将在API中可用。 \n @Field(() => ID)— 用于标量类型ID。 \n
现在为变更(创建用户)创建一个InputType:
@InputType()\nexport class CreateUserInput {\n @Field()\n name!: string;\n\n @Field()\n email!: string;\n}\n\n此类型将用于解析器中进行输入数据验证。
\n\n3. 编写解析器
\n\n创建文件src/resolvers/UserResolver.ts。在这里我们将实现查询和变更的逻辑。
import { Resolver, Query, Mutation, Arg } from "type-graphql";\nimport { User, CreateUserInput } from "../types/User";\n\n// 模拟数据库\nlet users: User[] = [\n { id: 1, name: "伊万·伊万诺夫", email: "ivan@example.com", createdAt: new Date() },\n { id: 2, name: "玛丽亚·彼得罗娃", email: "maria@example.com", createdAt: new Date() }\n];\n\nlet nextId = 3;\n\n@Resolver()\nexport class UserResolver {\n @Query(() => [User])\n async users(): Promise<User[]> {\n return users;\n }\n\n @Query(() => User, { nullable: true })\n async user(@Arg("id") id: number): Promise<User | undefined> {\n return users.find(u => u.id === id);\n }\n\n @Mutation(() => User)\n async createUser(@Arg("data") data: CreateUserInput): Promise<User> {\n const newUser: User = {\n id: nextId++,\n name: data.name,\n email: data.email,\n createdAt: new Date()\n };\n users.push(ne