AWS AppSyncのGraphQLスキーマからTypeScriptの型を生成

2020-09-05
山下 徳光
#
AWS
#
AppSync
#
GraphQL

こんにちは、山下です。

Amplify CLIにはデフォルトで型生成の機能がついているんですが、開発しているプロジェクトではAmplify CLIを利用していなかったので、AppSyncのスキーマからTypeScriptの型を生成する方法を検討しました。

検証コードはGitHubにUPしておきましたので、ご自由にお試しください。

nori3tsu/generate-appsync-schema-example

型生成手順

以下の手順で型生成します。

  1. AppSyncからGraphQLスキーマをダウンロード
  2. GraphQLスキーマから型生成

1. AppSyncからGraphQLスキーマをダウンロード

AWS CLIを利用してGraphQLスキーマをダウンロードします。

$ APPSYNC_APP_ID=
$ aws appsync get-introspection-schema --api-id ${APPSYNC_APP_ID} --format SDL schema.graphql

今回はAmplify CLIで生成されるサンプルスキーマを利用しました。

type Mutation {
    # In this example, only users in the ManagerGroup can create tasks
    createTask(
        owner: String!,
        title: String!,
        taskStatus: String!,
        description: String!
    ): Task
        @aws_auth(cognito_groups: ["ManagerGroup"])
    # Both Employees and Managers can update a task's status
    updateTaskStatus(id: ID!, taskStatus: String!): Task
        @aws_auth(cognito_groups: ["EmployeeGroup","ManagerGroup"])
    updateTaskBody(id: ID!, title: String!, description: String!): Task
        @aws_auth(cognito_groups: ["ManagerGroup"])
}

type Query {
    # Users belonging to both EmployeesGroup and ManagerGroup can read a particular task
    getTask(id: ID!): Task
        @aws_auth(cognito_groups: ["EmployeeGroup","ManagerGroup"])
    # Only Managers can list all the Tasks
    allTasks(nextToken: String): TaskConnection
        @aws_auth(cognito_groups: ["ManagerGroup"])
}

type Task {
    id: ID!
    owner: String!
    title: String!
    description: String!
    taskStatus: String
}

type TaskConnection {
    items: [Task]
    nextToken: String
}

schema {
    query: Query
    mutation: Mutation
}

# ここは独自に追加
enum TaskType {
  Task,
  Story
}

2. GraphQLスキーマから型生成

依存ライブラリインストール

graphql-code-generatorを使います。

graphql-codegenをインストール。

$ yarn add graphql
$ yarn add -D @graphql-codegen/cli

TypeScriptで型生成するために必要な依存ライブラリをインストール。

$ yarn add -D @graphql-codegen/typescript
$ yarn add -D @graphql-codegen/typescript-operations

codegen.yml作成

codegen.yml を作ります。

# 常に上書き
overwrite: true
# スキーマファイルを指定
# 今回のケースではAppSyncから出力
schema: "schema.graphql"
generates:
  # 型生成する型のパス
  src/generated/graphql.ts:
    plugins:
      - "typescript"
      # Mutation,Queryの型を生成
      - "typescript-operations"
    config:
      # __typenameフィールドの出力を抑制
      # 例: `__typename?: 'Task';`
      skipTypename: true
      # Mutation,Queryのオプショナルを外す
      avoidOptionals: true

今回は、skipTypenameavoidOptionals のオプションを設定しました。 様々なオプションが用意されているので、プラグインの公式ページを確認してみてください。

型生成

型生成を実行します。

$ yarn graphql-codegen --config codegen.yml
yarn run v1.22.0
$ ./generate-appsync-schema-example/node_modules/.bin/graphql-codegen --config codegen.yml
  ✔ Parse configuration
  ✔ Generate outputs
✨  Done in 1.14s.

TypeScriptの型が生成されました。

export type Maybe = T | null;
export type Exact = { [K in keyof T]: T[K] };
/** 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 = {
  createTask: Task;
  updateTaskStatus: Task;
  updateTaskBody: Task;
};


export type MutationCreateTaskArgs = {
  owner: Scalars['String'];
  title: Scalars['String'];
  taskStatus: Scalars['String'];
  description: Scalars['String'];
};


export type MutationUpdateTaskStatusArgs = {
  id: Scalars['ID'];
  taskStatus: Scalars['String'];
};


export type MutationUpdateTaskBodyArgs = {
  id: Scalars['ID'];
  title: Scalars['String'];
  description: Scalars['String'];
};

export type Query = {
  getTask: Task;
  allTasks: TaskConnection;
};


export type QueryGetTaskArgs = {
  id: Scalars['ID'];
};


export type QueryAllTasksArgs = {
  nextToken: Maybe;
};

export type Task = {
  id: Scalars['ID'];
  owner: Scalars['String'];
  title: Scalars['String'];
  description: Scalars['String'];
  taskStatus: Maybe;
};

export type TaskConnection = {
  items: Maybe>>;
  nextToken: Maybe;
};

export enum TaskType {
  Task = 'Task',
  Story = 'Story'
}

Prettier連携

生成されたファイルがPrettierで怒られて気になる人へ。 hooksのafterOneFileWriteに型生成後に実行するコマンドを設定できます。

18a19,22
>     hooks:
>       # 型生成後に実行するコマンド
>       afterOneFileWrite:
>         - prettier --write src/generated/graphql.ts

型生成スクリプトを作成

AppSync生成から型生成までをスクリプト化しておきます。

スクリプトの新規作成。

#!/bin/bash

# ワークディレクトリをプロジェクトルートに変更
cd $(dirname $0)/..

# AppSyncからGraphQLスキーマをダウンロード
APPSYNC_APP_ID="<ここにAppSync IDを設定>"
aws appsync get-introspection-schema --api-id ${APPSYNC_APP_ID} --format SDL schema.graphql

# 型生成
graphql-codegen --config codegen.yml

実行権限を付与。

$ chmod +x ./bin/codegen

package.jsonに型生成コマンドを追加。

13a14,16
>   },
>   "scripts": {
>     "graphql:codegen": "./bin/codegen"

以降は、$ yarn graphql:codegen コマンドで型生成を実行します。

おわりに

AWS CLIとgraphql-codegenを利用してAppSyncのGraphQLスキーマからTypeScriptの型を生成する方法をご紹介しました。 これでフロントエンド開発がより捗りますね!

株式会社Grandreamでは、フルリモートであなたのスキルを活かし、活躍できるエンジニアを募集しております。 詳しくは採用ページをご確認いただき、お気軽にお問い合わせください。

株式会社グランドリームでは、AWSを駆使した開発からUI/UXデザインまで、Webアプリケーションに関するすべての要望に応えます。
まずは一度お気軽にご相談ください。

お問い合わせはこちら