GraphQL 스키마에 대한 유형 스크립트 유형 자동 생성

소개하다.


이 문서에서 Typescript로 작성된GraphQL API의 자동 생성 유형을 GraphQL codegen으로 사용하는 방법을 보여 드리겠습니다.

선결 조건


GraphQL과 Typescript 지식이 필요합니다.NodeJS와 Typescript는 컴퓨터에 설치되어 있어야 합니다.

배경.


타자 원고


Typescript은 JavaScript의 정적 유형 검사자입니다.그것은 더 좋은 코드를 작성하고, 실행할 때가 아니라, 개발할 때 잠재적인 오류를 포착하는 데 도움이 되는 개발 도구로 사용된다.

GraphQL


GraphQL은 HTTP API를 작성하는 데 사용되는 쿼리 언어입니다.이는 네트워크 로드와 일반적인 REST API에 필요한 엔드포인트 수를 최적화하는 데 유용합니다.

아폴로GraphQL


Apollo GraphQL은 GraphQL API를 구축하는 데 사용되는 프레임워크/도구 모음입니다.그것은 서버와 클라이언트에게 해결 방안을 제공한다.

GraphQL 코드 생성기(GraphQL codegen)


graphql-codegen은GraphQL 유형과 해석기 정의에 따라 Typescript 유형을 자동으로 생성하는 도구입니다.

저희가 뭘 만들까요?


화가와 작품을 관리하는 데 사용되는 단순한 GraphQL API를 구축하겠습니다.Apollo server와 graphql codegen을 사용하여 Typescript 유형을 자동으로 생성하여 전체 코드 라이브러리에서 사용할 것입니다.
만약 당신이 언제든지 길을 잃거나 속도를 높이려고 한다면, 여기서 최종 코드를 찾을 수 있습니다: https://github.com/xcanchal/apollo-server-typescript

손대다


먼저 프로젝트에 새 폴더를 만들고 npm 프로젝트를 초기화합니다.
$ mkdir {project-name}
$ cd {project-name}
$ npm init --yes
다음 종속성 및 devdependency를 설치합니다.
$ npm install --save apollo-server graphql

$ npm install --save-dev typescript @tsconfig/recommended graphql-codegen @graphql-codegen/cli @graphql-codegen/typescript nodemon ts-node
tsconfig.json, Typescript 구성 파일을 만듭니다.우리는 추천하는 예시를 사용하지만, 우리는 모든 원시 outDir 파일의 옆에 놓지 않고, 생성하고자 하는 파일을'dist/'폴더에 추가할 것입니다.
{
  "compilerOptions": {
    "outDir": "dist",
    "target": "ES2015",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Recommended"
}
기본 초기 설정을 완료하려면 .ts 스크립트에서 다음 dev 명령을 추가합니다.이 명령은 개발 모드에서 서버를 실행하는 데 사용됩니다(JS 파일을 생성하고 변경할 때마다 재부팅).
"scripts": {
  "dev": "nodemon --exec ts-node ./server.ts --watch"
}
이제 GraphQL 서버를 위한 코드를 작성합시다.편집기 오류를 잠시 무시하고 새 package.json 파일을 만듭니다.
import { ApolloServer } from 'apollo-server';

import typeDefs from './type-defs';
import resolvers from './resolvers';

(async () => {
  const server = new ApolloServer({ typeDefs, resolvers });
  const { url } = await server.listen();
  console.log(`🚀 Server ready at ${url}`);
})();
우리는 몇 개의 수조를 데이터베이스로 사용할 것이다.server.ts이라는 새 파일을 만들고 다음 내용을 붙여넣습니다.당분간 우리는 database.ts을 실체 유형으로 사용할 것이다(나를 평가하지 마라. 우리는 잠시 후에 이 문제를 해결할 것이다!)
export const painters: any[] = [];
export const paintings: any[] = [];
위대하다이제 API의 모드를 정의할 수 있습니다.any이라는 새 파일을 만들고 type-defs.tsPainter의 엔티티 유형을 추가합니다.
import { gql } from 'apollo-server';

export default gql`
  type Painter {
    name: String!
    country: String!
    techniques: [String]!
  }

  type Painting {
    author: String!
    title: String!
    technique: String!
    date: String!
  }
`
우리는 새로운 화가와 그림을 데이터베이스에 삽입하는 방법이 필요하다.Painting 파일에서 첫 번째 변종을 정의하면 화가를 만들 수 있습니다.
# [...]

input PainterInput {
  name: String!
  country: String!
  techniques: [String]!
}

type Mutation {
  createPainter(input: PainterInput!): Painter!
}
그 다음에 우리는 창작 회화에 유사한 변체를 추가할 것이다.
# [...]

input PaintingInput {
  author: String!
  title: String!
  technique: String!
  date: String!
}

type Mutation {
  # [...]
  createPainting(input: PaintingInput!): Painting!
}
다음 단계는 GraphQL이 이전에 정의한 형식과 연결된 데이터를 조회하거나 수정하는 방법을 알려주는 해상도를 만드는 것입니다.type-defs.ts이라는 파일을 만들면 다음과 같은 내용이 포함됩니다(마찬가지로 typescript 형식을 만들기 전에 resolvers.ts을 사용합니다).
import { painters, paintings } from './database';

const resolvers = {
  Mutation: {
    createPainter(_: any, { input: painter }: any): any {
      painters.push(painter);
      return painter;
    },
    createPainting(_: any, { input: painting }: any): any {
      paintings.push(painting);
      return painting;
    }
  }
};

export default resolvers;
지금까지 우리는 화가와 유화를 삽입할 수 있다.다음 단계는 일부 조회를 실현하고 데이터베이스에서 데이터를 검색하는 것이다.다음 쿼리를 any 파일에 추가합니다.
# [...]

type Query {
  painters: [Painter]! # get all painters
  paintings: [Painting]! # get all paintings
  painter(name: String): Painter # get a painter by name
  painting(title: String): Painting # get a painting by title
}
해당 파서를 type-defs.ts 파일에 추가합니다.
// [...]

const resolvers = {
  // [...]
  Query: {
    painters: (): any => painters,
    paintings: (): any => paintings,
    painter(_: any, { name }: any): any {
      console.log(name);
      return painters.find((painter) => painter.name === name);
    },
    painting(_: any, { title }: any): any {
      return paintings.find((painting) => painting.title === title);
    },
  },
// [...]
};
resolvers.ts 파일은 다음과 같습니다.
import { gql } from 'apollo-server';

export default gql`
  type Painter {
    name: String!
    country: String!
    techniques: [String]!
  }

  type Painting {
    author: String!
    title: String!
    technique: String!
    date: String!
  }

  input PainterInput {
    name: String!
    country: String!
    techniques: [String]!
  }

  input PaintingInput {
    author: String!
    title: String!
    technique: String!
    date: String!
  }

  type Query {
    painters: [Painter]!
    paintings: [Painting]!
    painter(name: String): Painter
    painting(title: String): Painting
  }

  type Mutation {
    createPainter(input: PainterInput!): Painter!
    createPainting(input: PaintingInput!): Painting!
  }
`
type-defs.ts 파일은 다음과 같습니다.
import { painters, paintings } from './database';

const resolvers = {
  Query: {
    painters: (): any => painters,
    paintings: (): any => paintings,
    painter(_: any, { name }: any): any {
      console.log(name);
      return painters.find((painter) => painter.name === name);
    },
    painting(_: any, { title }: any): any {
      return paintings.find((painting) => painting.title === title);
    },
    },
  },
  Mutation: {
    createPainter(_: any, { input: painter }: any): any {
      painters.push(painter);
      return painter;
    },
    createPainting(_: any, { input: painting }: any): any {
      paintings.push(painting);
      return painting;
    }
  }
};

export default resolvers;
현재 우리는 API의 유형과 해석기를 정의했다. 개발 모드에서 서버를 실행하고, Apollo Studio의 외관을 살펴보자. 이것은 서버를 테스트하는 플랫폼이다.resolvers.ts을 실행하여 새 브라우저를 열고 탐색합니다.
$ npm run dev

// -> 🚀 Server ready at http://localhost:4000/
"서버 조회"단추를 누르면 Apollo Studio에 들어갑니다. 모드 정의를 탐색하고 우리가 이미 실행한 돌연변이와 조회를 실행할 수 있습니다.

마지막으로 본고에서 가장 중요한 일은GraphQL 모델과 일치하는 typescript 파일을 만드는 데 사용할 유형입니다.
코드 라이브러리로 돌아가서 npm run dev을 설정합니다.graphql-codegen이라는 새 파일을 만들고 다음 기본 구성을 붙여넣습니다(사용 가능한 옵션의 전체 목록 here 참조).
schema: "./type-defs.ts" # GraphQL types (input file)
generates:
  ./gql-types.d.ts: # Typescript types (output generated file)
    plugins: # List of needed plugins (installed as devDeps)
      - typescript
마지막으로, 편리함을 위해 codegen.yaml에 새 스크립트를 추가합니다.
"scripts": {
  "generate-gql-types": "graphql-codegen"
}
그것(package.json)을 실행하여 npm run generate-gql-types(codegen.yaml)이라는 새 파일을 어떻게 만드는지 보십시오.이 파일에는 Typescript 유형이 모두 포함되어 있습니다.
export type Maybe<T> = T | null;
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]> };
/** 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 Mutation = {
  __typename?: 'Mutation';
  createPainter: Painter;
  createPainting: Painting;
};


export type MutationCreatePainterArgs = {
  input: PainterInput;
};


export type MutationCreatePaintingArgs = {
  input: PaintingInput;
};

export type Painter = {
  __typename?: 'Painter';
  country: Scalars['String'];
  name: Scalars['String'];
  techniques: Array<Maybe<Scalars['String']>>;
};

export type PainterInput = {
  country: Scalars['String'];
  name: Scalars['String'];
  techniques: Array<Maybe<Scalars['String']>>;
};

export type Painting = {
  __typename?: 'Painting';
  author: Scalars['String'];
  date: Scalars['String'];
  technique: Scalars['String'];
  title: Scalars['String'];
};

export type PaintingInput = {
  author: Scalars['String'];
  date: Scalars['String'];
  technique: Scalars['String'];
  title: Scalars['String'];
};

export type Query = {
  __typename?: 'Query';
  painter?: Maybe<Painter>;
  painters: Array<Maybe<Painter>>;
  painting?: Maybe<Painting>;
  paintings: Array<Maybe<Painting>>;
};


export type QueryPainterArgs = {
  name?: Maybe<Scalars['String']>;
};


export type QueryPaintingArgs = {
  title?: Maybe<Scalars['String']>;
};
멋있죠?코드에서 실제로 사용하면 모양새를 볼 때 좋아하고 유형 검사에서 이득을 볼 수 있습니다.
먼저 gql-types.d.ts 파일을 업데이트하겠습니다.
import { Painter, Painting } from './gql-types';

export const painters: Painter[] = [];
export const paintings: Painting[] =[];
그런 다음 database.ts 파일에서 동일한 작업을 수행합니다.
import { painters, paintings } from './database';
import {
  Painter,
  Painting,
  MutationCreatePainterArgs,
  MutationCreatePaintingArgs,
  QueryPainterArgs,
  QueryPaintingArgs,
} from './gql-types';

const resolvers = {
  Query: {
    painters: (): Painter[] => painters,
    paintings: (): Painting[] => paintings,
    painter(_: any, { name }: QueryPainterArgs): Painter | undefined {
      console.log(name);
      return painters.find((painter) => painter.name === name);
    },
    painting(_: any, { title }: QueryPaintingArgs): Painting | undefined {
      return paintings.find((painting) => painting.title === title);
    },
  },
  Mutation: {
    createPainter(_: any, { input: painter }: MutationCreatePainterArgs): Painter {
      painters.push(painter);
      return painter;
    },
    createPainting(_: any, { input: painting }: MutationCreatePaintingArgs): Painting {
      paintings.push(painting);
      return painting;
    }
  }
};

export default resolvers;

결론


경탄할 만한!당신은 이미 이 강좌를 완성했습니다.이런 방법을 사용하면 같은 실체(하나는GraphQL, 하나는Typescript)를 두 번 정의할 필요가 없다. 우리는 GraphQL API를 디자인, 실현하고 유지할 때 진정으로 중요한 내용인 모델 유형, 조회와 돌연변이를 주목할 수 있다.resolvers.ts을 사용하면 우리는 Typescript 유형을 자동으로 생성할 수 있다. 우리의 코드는GraphQL 모델과 일치하기 때문에 너무 많은 노력을 기울일 필요가 없다. 응용 프로그램의 발전에 따라 필요한 모든 설정 조정을 제외하고는.
이것은Typescript와GraphQL을 사용하는 많은 방법 중의 하나이기 때문에 만약에 다른 방법을 사용한다면 의심할 여지없이 우리와 공유해 주십시오. 그러면 우리는 새로운 것을 배울 수 있습니다!
Twitter에서 팔로우 해주시면 더 많이 아실 거예요.

좋은 웹페이지 즐겨찾기