8

如何使用 TypeScript 和 GraphQL 开发应用

 3 years ago
source link: https://mp.weixin.qq.com/s/EdJFb8GrmhbgQL2kkjOjhQ
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

GraphQL是一个专为构建灵活的API而生的强大的查询语言。 它允许您为数据定义类型系统,因此在执行查询时,它仅返回所需的数据。

与TypeScript一起使用时,GraphQL可以为开发人员提供更好的体验,因为它们都是类型语言。TypeScript是JavaScript的类型化超集,可通过添加类型对其进行扩展。因此,一起使用这些技术肯定会帮助您构建可预测的强类型API。

在本教程中,我将首先解释为什么要结合这些技术,然后通过使用TypeGraphQL从头构建API来展示如何将TypeScript与GraphQL结合使用。

先决条件

本教程假定您有使用TypeScript的经验,尤其是对TypeScript类和装饰器。GraphQL的知识将派上用场,但不是强制性的。

在本指南中,我们将使用TypeGraphQL

,这是一个使用Node.js和TypeScript构建GraphQL API的现代框架。

为什么将TypeScript与GraphQL一起使用

TypeScript是由Microsoft开发和维护的一种流行编程语言。它是JavaScript的超集,它使用静态类型检查使代码可预测。

多年来,TypeScript已被证明是用于大型代码库的有价值的语言。TypeScript通过其类型来提高代码质量,从而增加代码的健壮性,可理解性和可预测性。

GraphQL解决了API过度获取或获取不足的问题。GraphQL 可以通过一次请求就获取你应用所需的所有数据。通过这种方式,GraphQL使您的查询变得灵活,并且您的API可读且易于学习。

TypeScript和GraphQL都依靠类型使代码易于理解。但是,只能使用buildSchema方法或扩展名为.gql的文件在GraphQL模式中定义GraphQL类型。GraphQL解析器不支持GraphQL类型,因为解析器只是常规的JavaScript函数,而不是GraphQL代码。TypeScript解决了这个问题,因为正如我们前面提到的那样,它是JavaScript的超集。因此,它可以在GraphQL解析器上设置类型。这就是为什么将TypeScript与GraphQL一起使用才有意义的原因。

GraphQL处理GraphQL模式的类型,而TypeScript设置GraphQL解析器上的类型。但是,由于要处理多种语言,因此使用Node.js,GraphQL和TypeScript构建强类型的API可能很难维护。

TypeGraphQL打算解决保持模式与解析器之间一致性的问题。TypeGraphQL允许您使用TypeScript类和装饰器来为API创建架构,类型和解析器。它使用TypeScript构建整个GraphQL API。

RzMfArf.png!mobile

到目前为止,我们已经了解了为什么将TypeScript与GraphQL搭配一起使用,以及为什么TypeGraphQL在构建和维护使用TypeScript版GraphQL API时很方便。

事不宜迟,让我们深入练习部分,并使用TypeGraphQL构建GraphQL API。

安装

在使用TypeScript和GraphQL之前,我们首先得创建一个Node.js的应用,打开你的终端界面,执行以下命令:

yarn init

或者使用npm包管理器

npm init

然后需要你为项目设定一些信息,不需要填的一路回车就好,最后会在项目目录生成package.json文件。

fantingshengdeMacBook-Pro:graphql-typescript fantingsheng$ yarn init
yarn init v1.12.3
question name (graphql-typescript):
question version (1.0.0):
question description: for study
question entry point (index.js):
question repository url: https://github.com/fantingsheng/graphql-typescript
question author: Timfan
question license (MIT):
question private:
success Saved package.json
:sparkles:  Done in 223.35s.

接下来安装一些需要的依赖

yarn add express apollo-server-express graphql reflect-metadata type-graphql class-validator

或者

npm install express apollo-server-express graphql reflect-metadata type-graphql class-validator

我们先下载好这些安装包,然后再解释它们分别是干什么的。另外还要安装它们的类型定义,以便支持TypeScript的使用。

yarn add -D ts-node typescript @types/express @types/node nodemon

或者

npm install -D ts-node typescript @types/express @types/node nodemon

注意:我们安装nodemon是为了在代码更新的时候热重载

下面是每个依赖库的作用解释:

  • express 是一个极简的Node版web框架

  • apollo-server-express 是一个允许我们在Apollo GraphQL服务中使用 express 的中间件

  • reflect-metadata 使得TypeScript装饰器可以在当一个类已经定义的时候为它添加一个类和成员。它是TypeGraphQL的一个依赖。

  • class-validator 允许 TypeGraphQL 基于验证的情况下使用装饰器和非装饰器

接下来,为项目搭建结构

src
| ├── resolvers
| |  └── todoResolver.ts
| └── schemas
| |  └── Todo.ts
| └── index.ts
├── tsconfig.json
├── package.json
└── yarn.lock

这里有四个文件需要说明下:

  • 应用的入口文件 index.ts

  • schemas 目录包含了该项目的GraphQL Schema

  • resolvers 目录包含了所有API的实现

  • tsconfig.json 告诉TypeScript如何去编译代码

与此同时,我们需要在package.json文件中添加服务的执行命令:

"scripts": {
  "start": "nodemon --exec ts-node src/index.ts"
}

该script命令通过使用nodemon去开启服务,即使代码临时修改,也会重启生效。

为tsconfig.json文件增加配置

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true
  }
}

以上这两个属性都要设置为true,以便我们可以在项目中使用TypeScript的装饰器。

我们现在可以为API创建一个GraphQL Schema了。

创建GraphQL Schema

TypeGraphQL使得你可以通过TypeScript的类和装饰器创建一个schema,它仅仅是语法糖而已,最终还是会生成GraphQL代码。这个稍后再说,先创建一个schema

  • schema/Todo.ts

import { Field, ObjectType, InputType } from "type-graphql"

@ObjectType() export class Todo {
  @Field() id: number
  @Field() title: string
  @Field() description: string
  @Field() status: boolean
}

@InputType() export class TodoInput implements Partial<Todo> {
  @Field() title: string
  @Field() description: string
}

乍一看这语法好像有点奇怪,其实没什么,仅仅是因为增加了TypeScript的装饰器和类的概念在里面

这里的 @ObjectType() 是由TypeGraphQL提供,为了创建新的对象和schema而存在。 Todo 类反应了Todo对象的结构, TodoInput 定义了我们往Todo里面增加的期望数据

结构。

如下是相同功能的GraphQL代码。

type Todo {
  id: ID!
  title: String!
  description: String!
  status: Boolean!
}

input TodoInput {
  title: String!
  description: String!
}

可以看到逻辑完全一样,唯一的不同是没有使用TypeScript。

创建GraphQL Resolver

不像GraphQL,TypeGraphQL将query和mutation语句写在了resolver的里面,当被调用的时候方法名作为唯一入口。

import { Query, Resolver, Mutation, Arg } from "type-graphql";
import { Todo, TodoInput } from "../schemas/Todo";


@Resolver(of => Todo)
export class TodoResolver {
    private todos: Todo[] = []

  @Query(returns => [Todo], { nullable: true })
  async getTodos(): Promise<Todo[]> {
    return await this.todos;
  }

  @Mutation(returns => Todo)
  async addTodo(@Arg('todoInput') {title, description }: TodoInput): Promise<Todo> {
    const todo = {
      id: Math.random(),
      title,
      description,
      status: false
    }

    await this.todos.push(todo)
    return todo;
  }
}

这里我们使用 resolver 装饰器创建一个新的返回Todo的GraphQL resolver。然后,创建一个GraphQL query去查询所有的Todo类型的数据。

之后,我们再定义一个mutation query往Todo类型的数组里增加一组新的数据。

让我们把代码转化成GraphQL形式

type Mutation {
  addTodo(todoInput: TodoInput!): Todo!
}

type Query {
  getTodos: [Todo!]
}

到这里,我们就可以通过创建好的schema和resolver来搭建服务了。

搭建服务

  • src/index.ts

import "reflect-metadata";
import { ApolloServer } from "apollo-server-express";
import * as Express from "express";
import { buildSchema } from "type-graphql";

import { TodoResolver } from "./resolvers/todoResolver";

async function main() {
  const schema = await buildSchema({
    resolvers: [TodoResolver],
    emitSchemaFile: true
  });

  const app = Express();

  const server = new ApolloServer({
    schema
  });

  server.applyMiddleware({ app });

  app.listen(4000, () =>
    console.log("Server is running on http://localhost:4000/graphql")
  );
}

main();

我们导入 TodoResolver ,通过在 buildSchema 方法里以resolver参数传入,这样来创建一个新的GraphQL Schema。

然后通过schema对象来创建一个ApolloServer

设置属性 emitSchemaFile: true 来允许TypeGraphQL在打包阶段生成一个schema.gql文件。

通过以下命令来启动应用

yarn start

或者

npm start

在浏览器中访问 http://localhost:4000/graphql

YZjaMjI.png!mobile

在项目根目录下生成了一个 schema.gql 文件

# -----------------------------------------------
# !!! THIS FILE WAS GENERATED BY TYPE-GRAPHQL !!!
# !!!   DO NOT MODIFY THIS FILE BY YOURSELF   !!!
# -----------------------------------------------

type Mutation {
  addTodo(todoInput: TodoInput!): Todo!
}

type Query {
  getTodos: [Todo!]
}

type Todo {
  description: String!
  id: Float!
  status: Boolean!
  title: String!
}

input TodoInput {
  description: String!
  title: String!
}

然后添加以下代码到GraphQL运行器中创建一个新的Todo

mutation {
  addTodo(todoInput: { title: "Todo 1", description: "This is my todo" }) {
    title
    description
    status
  }
}
Ej22YrJ.png!mobile

然后使用以下GraphQL query查询新的Todo

{
  getTodos {
    title
    description
    status
  }
}
YVfU3i.png!mobile

好了,我们的功能完成了。

我们已经实现了使用TypeScript构建GraphQL API。

完整代码

https://github.com/fantingsheng/graphql-typescript

References

[1] TypeGraphQL Docs:  https://typegraphql.com/docs/introduction.html

[2] TypeScript Decorators Docs:  https://www.typescriptlang.org/docs/handbook/decorators.html

[3] TypeScript Classes Docs:  https://www.typescriptlang.org/docs/handbook/classes.html

[4] TypeGraphQL Examples:  https://typegraphql.com/docs/examples.html

[5] GraphQL Docs:  https://graphql.org/learn/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK