依據(jù)graphql schema自動生成客戶端類型定義和調(diào)用接口

graphql 前端用起來還是真香的。今天我們就來討論怎么根據(jù)后端給的schema自動生成自動生成客戶端類型定義和調(diào)用接口。

GraphQL代碼生成器旨在解決一個問題:在很多情況下,我們發(fā)現(xiàn)自己寫的是GraphQL已經(jīng)描述過的東西,只是格式不同;例如:解析器簽名,MongoDB模型,Angular服務(wù)等。通過對schema分析并對其解析,GraphQL代碼生成器可以基于預(yù)定義插件或基于用戶自定義插件輸出多種格式代碼。無論你使用哪種語言,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代碼生成,需要創(chuàng)建codegen.yml或者codegen.json文件,然后運行生成代碼。

CLI將自動檢查定義的配置文件并相應(yīng)地生成代碼。此外,還可以使用--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字段用戶將配置傳遞給插件??梢栽?code>.yml文件的多個層級中指定它。

require 字段

require字段允許加載任何外部文件,無需事先進行編譯。

require:
  - extension1
  - extension2

上面介紹完基礎(chǔ)概念和用法,生成對應(yīng)的類型文件沒問題了。重點來了,如果想生成接口文件怎么做呢?

這里我們拿react項目來舉例。
需要用到的插件:typescript, typescript-operations, typescript-react-apollo ,near-operation-file-preset

near-operation-file-preset:這個插件為預(yù)設(shè)的每個操作文件生成對應(yīng)的文件。
typescript-react-apollo:擴展了基本的TypeScript插件,@graphql-codegen/typescript, @graphql-codegen/typescript-operations,也具有相似的配置。

如果后端是graphql項目,可以從后端到處一份完成schema文檔,可以根據(jù)該文檔生成對應(yīng)的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自動生成類型文檔和接口文檔,希望大家多多指教!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容