GraphQL API 与 TypeScript 入门
GraphQL 是一种现代的 API 查询语言,它允许客户端只请求他们真正需要的数据。与添加了严格类型检查的 TypeScript 结合使用时,开发过程变得更加可预测和安全。在本逐步教程中,我们将使用流行的工具和最佳实践,用 TypeScript 创建一个完整的 GraphQL API。
为什么选择 GraphQL 与 TypeScript?首先,您在编译阶段就能获得自动补全和类型检查。其次,GraphQL 允许将多个查询合并为一个,从而减少网络请求的数量。第三,TypeScript 非常适合描述复杂的图形数据结构。
项目设置与依赖安装
首先,我们将创建一个新项目并安装必要的包。我们将使用 Apollo Server(最流行的 GraphQL 服务器)和 TypeGraphQL 来方便地与 TypeScript 集成。
mkdir graphql-ts-tutorialcd graphql-ts-tutorialnpm init -ynpm install apollo-server graphql reflect-metadata class-validatornpm install typescript type-graphql @types/node --save-devnpx tsc --init安装后,配置 tsconfig.json。确保包含以下选项:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "lib": ["ES2020"], "experimentalDecorators": true, "emitDecoratorMetadata": true, "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true }}创建文件夹结构:
src/ ├── index.ts ├── resolvers/ │ └── user.resolver.ts ├── schemas/ │ └── user.schema.ts └── data/ └── users.ts创建模式与数据类型
在 TypeGraphQL 中,数据类型使用装饰器来描述。我们将创建一个用户模型和一个用于变更的输入数据类型。
// src/schemas/user.schema.tsimport { ObjectType, Field, ID, InputType } from "type-graphql";
@ObjectType()export class User { @Field(() => ID) id!: number;
@Field() name!: string;
@Field() email!: string;
@Field({ nullable: true }) age?: number;}
@InputType()export class CreateUserInput { @Field() name!: string;
@Field() email!: string;
@Field({ nullable: true }) age?: number;}请注意使用 @ObjectType() 来描述返回类型,使用 @InputType() 来描述输入参数。这使得 TypeGraphQL 能够自动生成 GraphQL 模式。
实现解析器
解析器是处理查询并返回数据的函数。我们将创建一个简单的内存数组来存储用户。
// src/data/users.tsimport { User } from "../schemas/user.schema";
export const users: User[] = [ { id: 1, name: "伊万·彼得罗夫", email: "ivan@example.com", age: 28 }, { id: 2, name: "玛丽亚·西多罗娃", email: "maria@example.com", age: 32 },];现在,为查询和变更编写解析器:
// src/resolvers/user.resolver.tsimport { Resolver, Query, Mutation, Arg, Int } from "type-graphql";import { User, CreateUserInput } from "../schemas/user.schema";import { users } from "../data/users";
@Resolver()export class UserResolver { @Query(() => [User]) async getAllUsers(): Promise<User[]> { return users; }
@Query(() => User, { nullable: true }) async getUserById( @Arg("id", () => Int) id: number ): Promise<User | undefined> { return users.find(user => user.id === id); }
@Mutation(() => User) async createUser( @Arg("input") input: CreateUserInput ): Promise<User> { const newUser: User =
```