使用 apollo-cli 从 GraphQL Schema 生成 TypeScript/Flow/Scala/Swift 代码

这里的对象是apollo-cli所支持的,不是根据我的喜好来选择的。这次我需要的是TypeScript。

假设你有这样的 schema.graphql。

type Query {
  user: User!
}

type User {
  id: ID!
  name: String!
}

所以,假设想要生成使用此代码,文件结构有许多前提条件。大致如下。

schema.graphql
queries/
  getUser.graphql

使用者從架構定義中提取並執行該查詢。

query getUser {
  user {
    id
    name
  }
}

查询getUser的部分在简单的graphql查询中是可省略的,但在类型生成时有必要命名。

这次的目标是,在这个 schema.graphql 的基础上为 getUser.graphql 的结果添加类型。

使用 apollo-cli 进行代码生成

当我搜索时,我发现了三个选项:apollo-codegen,apollo-cli和apollo,这让人有些困惑。但根据问题讨论,似乎未来会将所有功能集中到apollo上,因此我决定使用apollo。

npm i -g apollo

如果使用(npm i -g apollo-cli),就会额外安装一个名为apollo-cli的命令。有点混乱。

阿波罗代码生成:generate是一个用于生成代码的命令,但它无法直接接收*.graphql文件,而需要编译后的json文件。

$ apollo schema:download --endpoint schema.graphql

通过这个操作,将会生成一个 schema.json 文件。

尽管命令名称为schema:download听起来有点奇怪,但由于Apollo是一家提供PaaS服务的赞助商,所以推测它的设定是基于从服务器下载架构定义这一前提条件。可能在考虑了Graphqool等方面的情况下进行定义。

使用生成的 schema.json 生成代码。

$ apollo codegen:generate --target=typescript --schema=schema.json --queries="queries/*.graphql"

运行后,将生成 queries/__generated__/getUser.ts。

在这里将目标设为Scala或Swift,将生成这些代码。确实,因为目前只使用了GraphQL的定义部分,所以不受语言限制。

使用React + TypeScript生成的类型

假设使用 react-apollo/Query。

首先,需要通过 webpack 来加载 getUser.graphql 文件。可以使用命令 yarn add graphql-tag 安装相关依赖,并且在 webpack.config.js 的 module.rules 中添加一个 .graphql 的加载器。

  // module.rules
  rules: [
    // ...
    {
      test: /\.(graphql|gql)$/,
      exclude: /node_modules/,
      loader: "graphql-tag/loader"
    }
  ]

用这个方法,可以把查询的读取表达式转换成类似于带有 gql 标签的字符串的形式。

import gql from 'graphql-tag'
export default gql`...`

使用生成的类型,为React代码添加类型。

import { Query } from "react-apollo";
import getUser from "../queries/getUser.graphql";
import { getUser as GetUserType } from "../queries/__generated__/getUser";

const GetUserQuery: React.ComponentType<{
  query: any;
  children: (p: { loading: boolean; data: GetUserType }) => React.ReactNode;
}> = Query as any;

export default () => {
  return (
    <GetUserQuery query={getUser}>
      {props => {
        if (props.loading) {
          return "Loading...";
        }
        return `Hello, ${props.data.user.name} - ${props.data.user.id}`;
      }}
    </GetUserQuery>
  );
};

顺便提一下,我之所以对 Query 进行类型转换是因为我想通过 children 将其类型传递给 data,但是因为 Query 的定义本身可能有问题,它不符合 React.Component 的类型要求,所以在正常使用的时候会引发类型错误…所以我选择忽略了这个问题。

虽然还可以更泛化一些,但我暂时认为是这样的感觉。

服务器上运行的仓库在这里:https://github.com/mizchi-sandbox/graphql-next-ts。

广告
将在 10 秒后关闭
bannerAds