10 分钟搭建一个 GraphQL 后端项目

这次我们通过快速搭建一个 GraphQL 项目来学习如何使用它。

项目使用的技术栈:

项目依赖

项目初始化

  • 终端前往存放项目的文件夹,创建项目:
$ mkdir tinylearn && cd tinylearn
  • 项目初始化:
$ npm init -y
  • 用编辑器打开项目(笔者使用的是 VSCode):
  • 安装依赖包,终端输入:
$ npm install apollo-server@2.13.1 \
    class-validator@0.12.2 \
    graphql@14.6.0 \
    reflect-metadata@0.1.13  \
    type-graphql@0.17.6
$ npm install --save-dev @types/graphql@14.0.7 \
    @types/node@12.12.39 \
    ts-node@8.10.1 \
    typescript@3.9.2
  • 在项目根目录加入文件 tinylearn/tsconfig.json:
{
  "compilerOptions": {
    "target": "es2018",
    "module": "commonjs",
    "lib": [
      "es2018",
      "esnext.asynciterable"
    ],
    "strictFunctionTypes": true,
    "strictNullChecks": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

tsconfig.jsonTypescript 的配置文件,它指定编译项目所需的根文件和编译器选项。

Hello world

准备工作已经做完了,接下来我们写点代码。

  • 创建 tinylearn/src/index.ts 文件,并写入相关代码:

index.ts:

console.log('Hello world!');
  • 修改 package.json:
{
  "name": "tinylearn",

  ...

  "scripts": {
+    "start": "ts-node src"  
-    "test": "echo \"Error: no test specified\" && exit 1"
  },

  ...

}

  • 运行以下命令,启动项目:
$ npm start

结果如下:

恭喜 Hello world 跑起来了!

引入 GraphQL

接下来我们要写一些逻辑了。

  • 修改 src/index.ts 为:
import "reflect-metadata"
import { buildSchema, ObjectType, Field, ID, Resolver, Query } from "type-graphql";
import { ApolloServer } from "apollo-server";

@ObjectType()
class Post {

  @Field(type => ID)
  id: string;

  @Field()
  created: Date;

  @Field()
  content: string;
}

@Resolver(Post)
class PostResolver {

  @Query(returns => [Post])
  async posts(): Promise<Post[]> {
    return [
      {
        id: "0",
        created: new Date(),
        content: '提供基于GraphQL API的数据查询及访问,「Hasura」获990万美元A轮...'
      },
      {
        id: "1",
        created: new Date(),
        content: '为什么GraphQL是API的未来'
      },
      {
        id: "2",
        created: new Date(),
        content: 'Netflix:我们为什么要将 GraphQL 引入前端架构?'
      },
    ]
  }
}

async function main() {

  try {

    const schema = await buildSchema({
      resolvers: [PostResolver],
      dateScalarMode: 'timestamp'
    });


    const server = new ApolloServer({
      schema,
      playground: true
    });

    const { url } = await server.listen(4444);

    console.log(`GraphQL Playground available at ${url}`);

  } catch (error) {
    console.error(error);
  }
}


main();
  • 再次运行项目:
$ npm start

结果:


玩一玩

浏览器访问网址 http://localhost:4444/:

我们先点击右侧 SCHEMA 按钮:

然后在左侧输入:

它会有自动补全,所以输入应该会很轻松。

点击中间圆形的播放按钮:

其实这个页面就像是 Postman,左边可以看作是前端发请求的配置,中间是服务器返回的 json,右边可以看作是后端的 API 文档。

我们改变参数再发请求试试:

整个过程就像是后端定义了一个 json graph(也就是 schema),前端根据需求拉取这个 graph 的部分数据。

我们再来回顾一下代码 tinylearn/src/index.ts

@ObjectType()
class Post {

  @Field(type => ID)
  id: string;

  @Field()
  created: Date;

  @Field()
  content: string;
}

@Resolver(Post)
class PostResolver {

  @Query(returns => [Post])
  async posts(): Promise<Post[]> {
    return [
      {
        id: "0",
        created: new Date(),
        content: '提供基于GraphQL API的数据查询及访问,「Hasura」获990万美元A轮...'
      },
      {
        id: "1",
        created: new Date(),
        content: '为什么GraphQL是API的未来'
      },
      {
        id: "2",
        created: new Date(),
        content: 'Netflix:我们为什么要将 GraphQL 引入前端架构?'
      },
    ]
  }
}

后端定义 Schema:

前端根据需求,参考 Schema 后发起请求:

前端获取返回值:

另外,这个 json graph (schema) 是一个严格的类型系统:

  • posts: [Posts!]! - Post 数组
  • id: ID! - 字符串 ID
  • created: Timestamp! - 时间戳
  • content: String! - 字符串

我们检查一下返回值的类型:

确实如此,返回值的类型和 Schema 里面一样:

postsPost 数组。

id 是字符串 ID。
created 是时间戳。
content 是字符串。

大家对 GraphQL 是否有了新的认识?欢迎给我留言。

未完待续

大家可能还是有很多疑问,不用心急,我们慢慢来。

下一篇 《Flutter 如何接入 GraphQL》 会介绍如何使用 Flutter(移动端大热) 接入本章写好的接口。让前端真正的跑起来,这样我们就会对 GraphQL 有更完整的认知。

Flutter Demo:

源码

代码地址
tinylearn/src/index.ts:

import "reflect-metadata"
import { buildSchema, ObjectType, Field, ID, Resolver, Query } from "type-graphql";
import { ApolloServer } from "apollo-server";

@ObjectType()
class Post {

  @Field(type => ID)
  id: string;

  @Field()
  created: Date;

  @Field()
  content: string;
}

@Resolver(Post)
class PostResolver {

  @Query(returns => [Post])
  async posts(): Promise<Post[]> {
    return [
      {
        id: "0",
        created: new Date(),
        content: '提供基于GraphQL API的数据查询及访问,「Hasura」获990万美元A轮...'
      },
      {
        id: "1",
        created: new Date(),
        content: '为什么GraphQL是API的未来'
      },
      {
        id: "2",
        created: new Date(),
        content: 'Netflix:我们为什么要将 GraphQL 引入前端架构?'
      },
    ]
  }
}

async function main() {

  try {

    const schema = await buildSchema({
      resolvers: [PostResolver],
      dateScalarMode: 'timestamp'
    });


    const server = new ApolloServer({
      schema,
      playground: true
    });

    const { url } = await server.listen(4444);

    console.log(`GraphQL Playground available at ${url}`);

  } catch (error) {
    console.error(error);
  }
}


main();

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。