我敏锐地意识到graphql-code-generator的便利性。


介绍

今天和今天,我都在开发用于前端React和后端Rails的SPA API应用程序

在TypeScript的React端,我认为react-apollo的类型声明很烦人。

由于GraphQL用于后端,因此感觉就像您在各个地方声明类型一样,这很微妙。 ..

因此,我将讨论使用graphql-code-generator解决各种不愉快的部分。

这个配置

前端

GitHub

  • 反应(在SPA中)
  • typescript
  • 创建反应应用
  • 反应阿波罗

后端

GitHub

  • ruby
  • Rails(带有API)
  • GraphQL

*以上两个存储库是从此存储库链接的。 (作为开发环境)

目前,请尝试按照阿波罗官方提供的

我已经在后端创建了一个名为todos的API,以获取Todo模型中的所有数据。

在前端获取并显示它。

src / App.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
+import { gql, useQuery } from "@apollo/client";
 import React from "react";
 import logo from "./logo.svg";
 import "./App.css";

+const TODOS_QUERY = gql`
+  query {
+    todos {
+      name
+   }
+  }
+`;

 const App = () => {
+   const { loading, data } = useQuery(TODOS_QUERY);
+
   return (
     <div className="App">
       <header className="App-header">
         <img src={logo} className="App-logo" alt="logo" />
         <p><center>[wp_ad_camp_2]</center></p><p>
           Edit <wyn>src/App.tsx</wyn> and save to reload.
         </p>
-        <a
-          className="App-link"
-          href="https://reactjs.org"
-          target="_blank"
-          rel="noopener noreferrer"
-        >
-          Learn React
-        </a>
+        {loading ? (
+          <p>Loading ...</p>
+        ) : (
+          <ul>
+            {data && data.todos.map(({ name }, i) => <li key={i}>{name}</li>)}
+          </ul>
+        )}
       </header>
     </div>
   );
 };

 export default App;

我没有声明

类型,所以出现错误。

スクリーンショット 2020-08-13 21.10.37.png

我将声明

类型。

准备的类型是Todo模型类型和响应值类型。

响应返回值{"data":{"todos": []}

1
2
3
4
5
6
7
interface Todo {
  name: string;
}

interface TodosData {
  todos: Todo[];
}

如下使用

TodosData

1
2
-  const { loading, data } = useQuery(TODOS_QUERY);
+  const { loading, data } = useQuery<TodosData>(TODOS_QUERY);

我能够执行而没有错误。

スクリーンショット 2020-08-13 21.15.03.png

中,让我们看看如果包含GraphQL Code Generator会发生什么。

使用GraphQL代码生成器

根据官方步骤

安装和设置

https://graphql-code-generator.com/docs/getting-started/codegen-config

1
$ yarn add -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations

package.json

1
2
3
"scripts": {
  "generate": "graphql-codegen"
}

在后端侧准备的末端波恩是http://localhost:5000/graphql,因此将其用于schema

程式码

1
2
3
4
5
6
7
schema: http://localhost:5000/graphql
documents: ./graphql/queries/*.graphql
generates:
  ./src/types.d.ts:
    plugins:
      - typescript
      - typescript-operations

*使用documents选项时似乎需要@graphql-codegen/typescript-operations

documents中指定的位置编写对todos的查询。

graphql /查询/ todos.graphql

1
2
3
4
5
query {
  todos {
    name
  }
}

后端运行时,尝试执行准备好的generate命令。

1
$ yarn generate

src/types.d.ts文件已生成。

src / types.d.ts

1
2
3
4
5
6
7
8
9
10
11
12
...省略...

export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>;


export type Unnamed_1_Query = (
  { __typename?: 'Query' }
  & { todos: Array<(
    { __typename?: 'Todo' }
    & Pick<Todo, 'name'>
  )> }
);

因为它是

Unnamed,所以给查询起一个名字,然后再次执行它。

graphql /查询/ todos.graphql

1
2
3
4
5
6
-query {
+query todos {
   todos {
     name
   }
 }

src/types.d.ts文件中定义了名为TodosQueryType

让我们将其用于useQuery类型。

src / App.tsx

1
2
3
4
+ import { TodosQuery } from "./types.d";

- const { loading, data } = useQuery<TodosData>(TODOS_QUERY);
+ const { loading, data } = useQuery<TodosQuery>(TODOS_QUERY);

我能够以相同的方式确认操作。

スクリーンショット 2020-08-16 22.05.54.png

不再需要在

src/App.tsx中定义Todo模型的类型和响应值的类型。

但是编写查询以在两个位置src/App.tsxgraphql/queries/todos.graphql处获取TODO数据是不愉快的。

如果我有专用的useQuery来获取

todos,则不必传递任何类型或查询。 .. ..

介绍@ graphql-codegen / typescript-react-apollo

如果我有专用的useQuery来获取

todos,则不必传递任何类型或查询。 .. ..

通过说

,我们将消除这种不愉快的感觉。

首先安装

1
$ yarn add -D @graphql-codegen/typescript-react-apollo

添加

typescript-react-apollo

程式码

1
2
3
4
5
6
7
8
 schema: http://localhost:5000/graphql
 documents: ./graphql/queries/*.graphql
 generates:
   ./src/types.d.ts:
     plugins:
       - typescript
       - typescript-operations
+      - typescript-react-apollo

执行生成命令

1
$ yarn generate

src/types.d.ts中生成了一个名为useTodosQuery的函数,因此让我们使用它。

src / App.tsx

1
2
3
4
5
- import { TodosQuery } from "./types.d";
+ import { useTodosQuery } from "./types.d";

- const { loading, data } = useQuery<TodosQuery>(TODOS_QUERY);
+ const { loading, data } = useTodosQuery();

它正常工作。

スクリーンショット 2020-08-16 22.29.40.png

GraphQL的便利之一是,即使使用相同的API,也只能获取所需的字段。

早先,当获取todos数据时,仅指定和获取了name,并且实现了诸如列表显示之类的功能。

要实现单独编辑和删除等功能,除非name是唯一的,否则它类似于id

您需要标识

Todo

如果在另一个屏幕上除name之外还需要id,则需要单独创建以下查询。

1
2
3
4
5
6
query todos {
  todos {
    id
    name
  }
}

但是,graphql-code-generator生成的所有功能都设置在src/types.d.ts中。

因为已经有一个查询函数仅指定name来获取todos,所以请创建以下文件和

当我运行

yarn generate时,出现错误Not all operations have an unique name

graphql /查询/ todosIncludeId.graphql

1
2
3
4
5
6
query todos {
  todos {
    id
    name
  }
}

query右侧的名称必须唯一。

graphql /查询/ todosIncludeId.graphql

1
2
3
4
5
6
7
-query todos {
+query todosIncludeId {
   todos {
     id
     name
   }
 }

我将

query的名称更改为唯一名称。

然后,除useTodosQuery之外,在src/types.d.ts中生成了useTodosIncludeIdQuery函数。

您可以使用GraphQL而不破坏其有用的特性。 :thumbsup:

参考

  • 阿波罗文件
  • Graphql代码生成器-入门
  • 使用graphql-codegen(React,Apollo,TypeScript)--Qiita生成类型定义
  • 如何使用GraphQL代码生成器。 ?从GraphQL Schema自动生成TS类型定义?
  • Graphql代码生成器--typescript-react-apollo