依据graphql schema自动生成客户端类型定义和调用接口

graphql 前端用起来还是真香的。今天我们就来讨论怎么根据后端给的schema自动生成自动生成客户端类型定义和调用接口。

GraphQL代码生成器旨在解决一个问题:在很多情况下,我们发现自己写的是GraphQL已经描述过的东西,只是格式不同;例如:解析器签名,MongoDB模型,Angular服务等。通过对schema分析并对其解析,GraphQL代码生成器可以基于预定义插件或基于用户自定义插件输出多种格式代码。无论你使用哪种语言,GraphQL代码生成器都能满足你的要求。

graphql-code-generator文档

简单案例:

type Author {
  id: Int!
  firstName: String!
  lastName: String!
  posts(findTitle: String): [Post]
}

type Post {
  id: Int!
  title: String!
  author: Author!
}

type Query {
  posts: [Post]
}

schema {
  query: Query
}
export type Maybe = T | null;
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
  ID: string,
  String: string,
  Boolean: boolean,
  Int: number,
  Float: number,
};

export type Author = {
  __typename?: 'Author',
  id: Scalars['Int'],
  firstName: Scalars['String'],
  lastName: Scalars['String'],
  posts?: Maybe>>,
};

export type AuthorPostsArgs = {
  findTitle?: Maybe
};

export type Post = {
  __typename?: 'Post',
  id: Scalars['Int'],
  title: Scalars['String'],
  author: Author,
};

export type Query = {
  __typename?: 'Query',
  posts?: Maybe>>,
};

安装

yarn add graphql

yarn add -D @graphql-codegen/cli

通过运行下面命令,将从路由端获取GraphQL schema,typescript类型定义将在指定的目标位置生成。

yarn generate

我们最好通过定义的codegen.yml文件进行生成。

codegen.yml

通过配置项进行GraphQL代码生成,需要创建codegen.yml或者codegen.json文件,然后运行生成代码。

CLI将自动检查定义的配置文件并相应地生成代码。此外,还可以使用--config选项定义配置文件的路径,如下:

yarn graphql-codegen --config ./path/to/config.yml

这个有个简单的配置:

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

schema 字段

schema字段是指向GraphQLSchema-可以通过多种方式指定它并加载GraphQLSchema.可以指定一个schema的字符串,也可以指定string[]指向多个schemas,将被合并。

指定位置可以在根目录,也可以在输出文件的层级,例如:

schema: http://localhost:3000/graphql
generates:
  ./src/types.ts:
    plugins:
      - typescript
generates:
  ./src/types1.ts:
    schema: http://server1.com/graphql
    plugins:
      - typescript
  ./src/types2.ts:
    schema: http://server2.com/graphql
    plugins:
      - typescript

在根目录和输出文件层,同时都指定schema,将合并成一个:

schema: http://localhost:3000/graphql
generates:
  ./src/types.ts:
    schema: ./schema.graphql
    plugins:
      - typescript
      - typescript-operations

schema可用格式:URL、JSON、本地.graphql文件、Code Files、JavaScript export、String、GitHub

documents 字段

documents字段指向你的GraphQL文档:query, mutation, subscription and fragment.
可选项,当你用插件为客服端生成代码时才需要。
可以指定一个string,或者string[]指定多个文档地址。

config 字段

config字段用户将配置传递给插件。可以在.yml文件的多个层级中指定它。

require 字段

require字段允许加载任何外部文件,无需事先进行编译。

require:
  - extension1
  - extension2

上面介绍完基础概念和用法,生成对应的类型文件没问题了。重点来了,如果想生成接口文件怎么做呢?

这里我们拿react项目来举例。
需要用到的插件:typescript, typescript-operations, typescript-react-apollo ,near-operation-file-preset

near-operation-file-preset:这个插件为预设的每个操作文件生成对应的文件。
typescript-react-apollo:扩展了基本的TypeScript插件,@graphql-codegen/typescript, @graphql-codegen/typescript-operations,也具有相似的配置。

如果后端是graphql项目,可以从后端到处一份完成schema文档,可以根据该文档生成对应的typescript types文档和和接口文档。

overwrite: true
schema: ./demo.gql
generates:
  ./src/__generated__/types.ts:
    plugins:
      - typescript
  src/:
    documents: './src/pages/**/gqls.ts'
    schema: ./demo.gql
    preset: near-operation-file
    presetConfig:
      baseTypesPath: __generated__/types.ts
      extension: .generated.tsx
      folder: __generated__
    plugins:
      - typescript-operations
      - typescript-react-apollo

生成的接口文档:

import * as Types from '../../../__generated__/types';

import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
export type ListAuthorQueryVariables = Types.Exact<{
  perPage: Types.Scalars['Int'];
  page: Types.Scalars['Int'];
}>;


export type ListAuthorQuery = (
  { __typename?: 'query' }
  & { listAuthor?: Types.Maybe<(
    { __typename?: 'AuthorList' }
    & Pick
    & { list?: Types.Maybe
      & { posts?: Types.Maybe
      )>>> }
    )>>> }
  )> }
);

export type AuthorQueryVariables = Types.Exact<{
  id: Types.Scalars['Int'];
}>;


export type AuthorQuery = (
  { __typename?: 'query' }
  & { author?: Types.Maybe<(
    { __typename?: 'Author' }
    & Pick
    & { posts?: Types.Maybe
    )>>> }
  )> }
);

export type CreateAuthorMutationVariables = Types.Exact<{
  author?: Types.Maybe;
}>;


export type CreateAuthorMutation = (
  { __typename?: 'mutation' }
  & Pick
);

export type UpdateAuthorMutationVariables = Types.Exact<{
  id: Types.Scalars['Int'];
  author?: Types.Maybe;
}>;


export type UpdateAuthorMutation = (
  { __typename?: 'mutation' }
  & Pick
);


export const ListAuthorDocument = gql`
    query ListAuthor($perPage: Int!, $page: Int!) {
  listAuthor(perPage: $perPage, page: $page) {
    count
    list {
      id
      firstName
      lastName
      posts {
        title
        author
      }
    }
  }
}
    `;

/**
 * __useListAuthorQuery__
 *
 * To run a query within a React component, call `useListAuthorQuery` and pass it any options that fit your needs.
 * When your component renders, `useListAuthorQuery` returns an object from Apollo Client that contains loading, error, and data properties
 * you can use to render your UI.
 *
 * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
 *
 * @example
 * const { data, loading, error } = useListAuthorQuery({
 *   variables: {
 *      perPage: // value for 'perPage'
 *      page: // value for 'page'
 *   },
 * });
 */
export function useListAuthorQuery(baseOptions?: Apollo.QueryHookOptions) {
        return Apollo.useQuery(ListAuthorDocument, baseOptions);
      }
export function useListAuthorLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) {
          return Apollo.useLazyQuery(ListAuthorDocument, baseOptions);
        }
export type ListAuthorQueryHookResult = ReturnType;
export type ListAuthorLazyQueryHookResult = ReturnType;
export type ListAuthorQueryResult = Apollo.QueryResult;
export const AuthorDocument = gql`
    query Author($id: Int!) {
  author(id: $id) {
    id
    firstName
    lastName
    posts {
      title
      author
    }
  }
}
    `;

/**
 * __useAuthorQuery__
 *
 * To run a query within a React component, call `useAuthorQuery` and pass it any options that fit your needs.
 * When your component renders, `useAuthorQuery` returns an object from Apollo Client that contains loading, error, and data properties
 * you can use to render your UI.
 *
 * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
 *
 * @example
 * const { data, loading, error } = useAuthorQuery({
 *   variables: {
 *      id: // value for 'id'
 *   },
 * });
 */
export function useAuthorQuery(baseOptions?: Apollo.QueryHookOptions) {
        return Apollo.useQuery(AuthorDocument, baseOptions);
      }
export function useAuthorLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) {
          return Apollo.useLazyQuery(AuthorDocument, baseOptions);
        }
export type AuthorQueryHookResult = ReturnType;
export type AuthorLazyQueryHookResult = ReturnType;
export type AuthorQueryResult = Apollo.QueryResult;
export const CreateAuthorDocument = gql`
    mutation CreateAuthor($author: authorInPut) {
  createAuthor(author: $author)
}
    `;
export type CreateAuthorMutationFn = Apollo.MutationFunction;

/**
 * __useCreateAuthorMutation__
 *
 * To run a mutation, you first call `useCreateAuthorMutation` within a React component and pass it any options that fit your needs.
 * When your component renders, `useCreateAuthorMutation` returns a tuple that includes:
 * - A mutate function that you can call at any time to execute the mutation
 * - An object with fields that represent the current status of the mutation's execution
 *
 * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
 *
 * @example
 * const [createAuthorMutation, { data, loading, error }] = useCreateAuthorMutation({
 *   variables: {
 *      author: // value for 'author'
 *   },
 * });
 */
export function useCreateAuthorMutation(baseOptions?: Apollo.MutationHookOptions) {
        return Apollo.useMutation(CreateAuthorDocument, baseOptions);
      }
export type CreateAuthorMutationHookResult = ReturnType;
export type CreateAuthorMutationResult = Apollo.MutationResult;
export type CreateAuthorMutationOptions = Apollo.BaseMutationOptions;
export const UpdateAuthorDocument = gql`
    mutation UpdateAuthor($id: Int!, $author: authorInPut) {
  updateAuthor(id: $id, author: $author)
}
    `;
export type UpdateAuthorMutationFn = Apollo.MutationFunction;

/**
 * __useUpdateAuthorMutation__
 *
 * To run a mutation, you first call `useUpdateAuthorMutation` within a React component and pass it any options that fit your needs.
 * When your component renders, `useUpdateAuthorMutation` returns a tuple that includes:
 * - A mutate function that you can call at any time to execute the mutation
 * - An object with fields that represent the current status of the mutation's execution
 *
 * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
 *
 * @example
 * const [updateAuthorMutation, { data, loading, error }] = useUpdateAuthorMutation({
 *   variables: {
 *      id: // value for 'id'
 *      author: // value for 'author'
 *   },
 * });
 */
export function useUpdateAuthorMutation(baseOptions?: Apollo.MutationHookOptions) {
        return Apollo.useMutation(UpdateAuthorDocument, baseOptions);
      }
export type UpdateAuthorMutationHookResult = ReturnType;
export type UpdateAuthorMutationResult = Apollo.MutationResult;
export type UpdateAuthorMutationOptions = Apollo.BaseMutationOptions;

完整demo

初探graphql-code-generator自动生成类型文档和接口文档,希望大家多多指教!

你可能感兴趣的:(依据graphql schema自动生成客户端类型定义和调用接口)