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

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

作者: QLing09 | 来源:发表于2020-08-25 16:43 被阅读0次

    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> = 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<Array<Maybe<Post>>>,
    };
    
    export type AuthorPostsArgs = {
      findTitle?: Maybe<Scalars['String']>
    };
    
    export type Post = {
      __typename?: 'Post',
      id: Scalars['Int'],
      title: Scalars['String'],
      author: Author,
    };
    
    export type Query = {
      __typename?: 'Query',
      posts?: Maybe<Array<Maybe<Post>>>,
    };
    

    安装

    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<Types.AuthorList, 'count'>
        & { list?: Types.Maybe<Array<Types.Maybe<(
          { __typename?: 'Author' }
          & Pick<Types.Author, 'id' | 'firstName' | 'lastName'>
          & { posts?: Types.Maybe<Array<Types.Maybe<(
            { __typename?: 'Post' }
            & Pick<Types.Post, 'title' | 'author'>
          )>>> }
        )>>> }
      )> }
    );
    
    export type AuthorQueryVariables = Types.Exact<{
      id: Types.Scalars['Int'];
    }>;
    
    
    export type AuthorQuery = (
      { __typename?: 'query' }
      & { author?: Types.Maybe<(
        { __typename?: 'Author' }
        & Pick<Types.Author, 'id' | 'firstName' | 'lastName'>
        & { posts?: Types.Maybe<Array<Types.Maybe<(
          { __typename?: 'Post' }
          & Pick<Types.Post, 'title' | 'author'>
        )>>> }
      )> }
    );
    
    export type CreateAuthorMutationVariables = Types.Exact<{
      author?: Types.Maybe<Types.AuthorInPut>;
    }>;
    
    
    export type CreateAuthorMutation = (
      { __typename?: 'mutation' }
      & Pick<Types.Mutation, 'createAuthor'>
    );
    
    export type UpdateAuthorMutationVariables = Types.Exact<{
      id: Types.Scalars['Int'];
      author?: Types.Maybe<Types.AuthorInPut>;
    }>;
    
    
    export type UpdateAuthorMutation = (
      { __typename?: 'mutation' }
      & Pick<Types.Mutation, 'updateAuthor'>
    );
    
    
    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<ListAuthorQuery, ListAuthorQueryVariables>) {
            return Apollo.useQuery<ListAuthorQuery, ListAuthorQueryVariables>(ListAuthorDocument, baseOptions);
          }
    export function useListAuthorLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ListAuthorQuery, ListAuthorQueryVariables>) {
              return Apollo.useLazyQuery<ListAuthorQuery, ListAuthorQueryVariables>(ListAuthorDocument, baseOptions);
            }
    export type ListAuthorQueryHookResult = ReturnType<typeof useListAuthorQuery>;
    export type ListAuthorLazyQueryHookResult = ReturnType<typeof useListAuthorLazyQuery>;
    export type ListAuthorQueryResult = Apollo.QueryResult<ListAuthorQuery, ListAuthorQueryVariables>;
    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<AuthorQuery, AuthorQueryVariables>) {
            return Apollo.useQuery<AuthorQuery, AuthorQueryVariables>(AuthorDocument, baseOptions);
          }
    export function useAuthorLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AuthorQuery, AuthorQueryVariables>) {
              return Apollo.useLazyQuery<AuthorQuery, AuthorQueryVariables>(AuthorDocument, baseOptions);
            }
    export type AuthorQueryHookResult = ReturnType<typeof useAuthorQuery>;
    export type AuthorLazyQueryHookResult = ReturnType<typeof useAuthorLazyQuery>;
    export type AuthorQueryResult = Apollo.QueryResult<AuthorQuery, AuthorQueryVariables>;
    export const CreateAuthorDocument = gql`
        mutation CreateAuthor($author: authorInPut) {
      createAuthor(author: $author)
    }
        `;
    export type CreateAuthorMutationFn = Apollo.MutationFunction<CreateAuthorMutation, CreateAuthorMutationVariables>;
    
    /**
     * __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<CreateAuthorMutation, CreateAuthorMutationVariables>) {
            return Apollo.useMutation<CreateAuthorMutation, CreateAuthorMutationVariables>(CreateAuthorDocument, baseOptions);
          }
    export type CreateAuthorMutationHookResult = ReturnType<typeof useCreateAuthorMutation>;
    export type CreateAuthorMutationResult = Apollo.MutationResult<CreateAuthorMutation>;
    export type CreateAuthorMutationOptions = Apollo.BaseMutationOptions<CreateAuthorMutation, CreateAuthorMutationVariables>;
    export const UpdateAuthorDocument = gql`
        mutation UpdateAuthor($id: Int!, $author: authorInPut) {
      updateAuthor(id: $id, author: $author)
    }
        `;
    export type UpdateAuthorMutationFn = Apollo.MutationFunction<UpdateAuthorMutation, UpdateAuthorMutationVariables>;
    
    /**
     * __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<UpdateAuthorMutation, UpdateAuthorMutationVariables>) {
            return Apollo.useMutation<UpdateAuthorMutation, UpdateAuthorMutationVariables>(UpdateAuthorDocument, baseOptions);
          }
    export type UpdateAuthorMutationHookResult = ReturnType<typeof useUpdateAuthorMutation>;
    export type UpdateAuthorMutationResult = Apollo.MutationResult<UpdateAuthorMutation>;
    export type UpdateAuthorMutationOptions = Apollo.BaseMutationOptions<UpdateAuthorMutation, UpdateAuthorMutationVariables>;
    

    完整demo

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

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/egrnjktx.html