创建一个代码谱投稿应用程序#5(使用graphql-code-generator进行类型定义)
←上一篇文章
这次要做的事情
上次我們是從前端發送 GraphQL 查詢以顯示分數列表,但分數的類型是我們手動創建的。之前的程式碼如下:
...
type Score = {
id: Number
title: String
}
...
我們將使用graphql-code-generator來一鍵生成此命令的型別定義。
安装图书馆
首先需要安装库。
$ yarn add -D @graphql-codegen/cli
安装其他必要的插件
$ yarn add --dev @graphql-codegen/typescript @graphql-codegen/typescript-graphql-request @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo
安装
当您执行以下命令时,它将以交互方式帮您创建配置文件。(您也可以自行创建配置文件)
$ npx graphql-codegen init
因为会被问到各种问题,所以我会一一回答。
以下是我所回答的内容。
? Where is your schema?: (path or url) http://localhost:3000/graphql
? Where are your operations and fragments?: ./graphql/documents/**/*.graphql
? Pick plugins: TypeScript (required by other typescript plugins), TypeScript Operations (operations and fragments), TypeScript React Apollo (typed
components and HOCs)
? Where to write the output: ./graphql/generated.tsx
? Do you want to generate an introspection file? No
? How to name the config file? codegen.yml
? What script in package.json should run the codegen? codegen
简单来说,需要解释一些重要的事情。
你的模式在哪里?
我正在编写服务器端的GraphQL端点。从该端点读取模式并对其进行类型定义等操作。
你的操作和片段在哪里?
我将创建一个用于编写在前端使用的查询(query)和变更(mutation)的文件(我将在接下来的工作中创建它)。这次我打算创建一个名为graphql的文件夹,并分别将查询放在/graphql/query/〇〇.graphql,将变更放在/graphql/mutation/〇〇.graphql中,所以我会这样做。
输出写在哪里?
当您输入命令时,这里将显示类型定义。
怎样给配置文件命名?
在 package.json 中应该运行哪个脚本来执行代码生成?
根据配置添加命令到 package.json。
这里是已经完成的设置文件。
overwrite: true
schema: "http://localhost:3000/graphql"
documents: "./graphql/documents/**/*.graphql"
generates:
./graphql/generated.tsx:
plugins:
- "typescript"
- "typescript-operations"
- "typescript-react-apollo"
package.json中添加了命令。
...
"private": true,
"scripts": {
"dev": "next dev -p 3001",
"build": "next build",
"start": "next start",
+ "lint": "next lint",
+ "codegen": "graphql-codegen --config codegen.yml"
},
"dependencies": {
...
执行命令
以上是设定完成!在执行命令之前,我们将在前端编写要使用的查询。我们将编写一个查询来获取上次使用的Score列表。
query Scores {
scores {
id
title
}
}
用这个来执行命令。
yarn下面是刚刚在package.json中添加的命令。
$ yarn codegen
一切都没有问题,以下是创建的类型定义!
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
export type Maybe<T> = T | null;
export type InputMaybe<T> = Maybe<T>;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
const defaultOptions = {} as const;
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: string;
String: string;
Boolean: boolean;
Int: number;
Float: number;
ISO8601DateTime: any;
};
export type Mutation = {
__typename?: 'Mutation';
/** An example field added by the generator */
testField: Scalars['String'];
};
export type Query = {
__typename?: 'Query';
score: Score;
scores: Array<Score>;
};
export type QueryScoreArgs = {
id?: InputMaybe<Scalars['Int']>;
};
export type Score = {
__typename?: 'Score';
createdAt: Scalars['ISO8601DateTime'];
id: Scalars['ID'];
title?: Maybe<Scalars['String']>;
updatedAt: Scalars['ISO8601DateTime'];
};
export type ScoresQueryVariables = Exact<{ [key: string]: never; }>;
export type ScoresQuery = { __typename?: 'Query', scores: Array<{ __typename?: 'Score', id: string, title?: string | null }> };
export const ScoresDocument = gql`
query Scores {
scores {
id
title
}
}
`;
/**
* __useScoresQuery__
*
* To run a query within a React component, call `useScoresQuery` and pass it any options that fit your needs.
* When your component renders, `useScoresQuery` 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 } = useScoresQuery({
* variables: {
* },
* });
*/
export function useScoresQuery(baseOptions?: Apollo.QueryHookOptions<ScoresQuery, ScoresQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<ScoresQuery, ScoresQueryVariables>(ScoresDocument, options);
}
export function useScoresLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ScoresQuery, ScoresQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<ScoresQuery, ScoresQueryVariables>(ScoresDocument, options);
}
export type ScoresQueryHookResult = ReturnType<typeof useScoresQuery>;
export type ScoresLazyQueryHookResult = ReturnType<typeof useScoresLazyQuery>;
export type ScoresQueryResult = Apollo.QueryResult<ScoresQuery, ScoresQueryVariables>;
使用所创建的类型定义进行重写
使用实际生成的类型定义,我将上次创建的index.tsx进行了改写,以下是改写后的代码。
import { Box } from '@chakra-ui/react'
import type { ReactElement } from 'react'
import { Layout } from '../components/common/Layout'
import type { NextPageWithLayout } from './_app'
import { useQuery } from "@apollo/client";
import { Score, ScoresDocument } from '../graphql/generated';
const Page: NextPageWithLayout = () => {
const { data, loading, error } = useQuery(ScoresDocument)
if (loading) return <Box>ロード中...</Box>;
if (error) return <Box>{error.message}</Box>;
return (
<Box>
<ul>
{data.scores.map((score: Score) => (
<li>{score.title}</li>
))}
</ul>
</Box>
)
}
Page.getLayout = function getLayout(page: ReactElement) {
return (
<Layout>
{page}
</Layout>
)
}
export default Page
查询也可以被重写为ScoresDocument的形式,并且之前自己创建的Score类型定义也是使用服务器端的schema生成的,因此类型安全性得到了提高!
這次就到這裡吧!
只需要一种选择的原文重述:
我参考了一下那个网站或文章。
GraphQL 代码生成器
初次接触 GraphQL。使用代码生成器来生成类型的笔记。