最近才深切地意识到 graphql-code-generator 的便利之处

首先

今天也是如往常一样,在开发一个前端使用React,后端使用Rails,同时配合API的单页应用。

我觉得在TypeScript的React中声明react-apollo的类型很繁琐。

由于后端使用了GraphQL,它似乎在很多地方都进行了类型声明,感觉有点微妙。。

让我们讨论使用graphql-code-generator来解决一些令人不适的问题。

本次的組成

前端

GitHub –> GitHub

    • React(SPAで)

 

    • TypeScript

 

    • create-react-app

 

    React Apollo

后端

GitHub -> GitHub (GitHub)

    • Ruby

 

    • Rails(APIで)

 

    GraphQL

为了将上述的两个存储库与此存储库协同工作(作为开发环境),我们决定采用联动机制。

暂时跟随Apollo的官方指南试一试

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

将其在前端获取并显示出来。

+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>
           Edit <code>src/App.tsx</code> 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”: []}}这个值。

interface Todo {
  name: string;
}

interface TodosData {
  todos: Todo[];
}

以下是如何使用TodosData的方法。

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

没有发生任何错误,执行成功。

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

我要试试如果安装了GraphQL Code Generator会发生什么。

使用GraphQL代码生成器

按照公式手册的步骤,进行安装和设置。

 

$ yarn add -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations
"scripts": {
  "generate": "graphql-codegen"
}

由于后端已经准备好了端点http://localhost:5000/graphql,所以我们将在schema中使用它。

schema: http://localhost:5000/graphql
documents: ./graphql/queries/*.graphql
generates:
  ./src/types.d.ts:
    plugins:
      - typescript
      - typescript-operations

如果使用`documents`选项,似乎需要安装`@graphql-codegen/typescript-operations`。

将todos的查询内容写入到在documents指定的位置上。

query {
  todos {
    name
  }
}

在启动后端的情况下,尝试执行预设的生成命令。

$ yarn generate

已创建src/types.d.ts文件。

...省略...

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


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

由于未命名,我们给查询命名并重新执行。

-query {
+query todos {
   todos {
     name
   }
 }

在src/types.d.ts文件中定义了一个名为TodosQuery的类型。

我尝试将其用作useQuery的类型。

+ 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.tsx和graphql/queries/todos.graphql两个地方编写用于获取TODO数据的查询调用,感觉有点不好吧。

如果有一个专用的 useQuery 来获取 todos,就不需要传递类型和查询了…

引入@graphql-codegen/typescript-react-apollo。

如果有一个专门用于获取todos的useQuery函数,就不需要传递类型和查询了。。。

因此,我们将解除这种令人不悦的感觉。

首先要安装

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

添加 typescript-react-apollo。

 schema: http://localhost:5000/graphql
 documents: ./graphql/queries/*.graphql
 generates:
   ./src/types.d.ts:
     plugins:
       - typescript
       - typescript-operations
+      - typescript-react-apollo

执行生成命令

$ yarn generate

我們將嘗試使用生成的useTodosQuery函數,它位於src/types.d.ts中。

- 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的标识。

需要确定特定的任务。

如果在另一个屏幕或其他地方时,除了姓名之外,还需要身份证号,我就会想要创建以下类似的查询。

query todos {
  todos {
    id
    name
  }
}

然而,所有由graphql-code-generator生成的函数都设置成存放在src/types.d.ts中。

由于已经存在一个函数来获取仅指定name的todos的查询,所以请创建以下类似的文件:

运行yarn generate会出现“不是所有操作都有唯一的名称”的错误。

query todos {
  todos {
    id
    name
  }
}

请确认右侧查询中列出的名称必须是唯一的。

-query todos {
+query todosIncludeId {
   todos {
     id
     name
   }
 }

我试着将查询的名称更改为独特的名称。

然后,除了在src/types.d.ts中生成useTodosQuery之外,还生成了一个名为useTodosIncludeIdQuery的函数。

你可以在不破坏GraphQL的有用特性的情况下使用它。

文献引用

    • Apollo Docs

 

    • Graphql Code Generator – getting-started

 

    • graphql-codegen で型定義を生成する (React, Apollo, TypeScript) – Qiita

 

    • GraphQL Code Generator の使い方。〜GraphQLのSchemaからTSの型定義を自動生成する〜 – Qiita

 

    Graphql Code Generator – typescript-react-apollo
bannerAds