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
自动生成类型文档和接口文档,希望大家多多指教!